From c8b2a3e21d19a4bddb1bf5395756747c53ccec7b Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 11 Feb 2024 00:54:39 +0100 Subject: [PATCH 1/8] Add commands for audio normalization; pass 1 realised in a new action --- runner/actions/actions.go | 13 +++++++------ runner/cmd.yaml | 10 ++++++++++ runner/config/cmd.go | 8 ++++++-- runner/handlers.go | 1 + 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/runner/actions/actions.go b/runner/actions/actions.go index d1bd32556..fe61077b3 100644 --- a/runner/actions/actions.go +++ b/runner/actions/actions.go @@ -39,12 +39,13 @@ func (a *ActionProvider) GetMassDir(courseID, streamID uint64, version string) s type ActionType string const ( - PrepareAction ActionType = "prepare" - StreamAction = "stream" - TranscodeAction = "transcode" - UploadAction = "upload" - ThumbnailAction = "thumbnail" - SelfStreamAction = "selfstream" + PrepareAction ActionType = "prepare" + StreamAction = "stream" + TranscodeAction = "transcode" + UploadAction = "upload" + ThumbnailAction = "thumbnail" + SelfStreamAction = "selfstream" + AudioNormalizeAction = "audio_normalize" ) type Action struct { diff --git a/runner/cmd.yaml b/runner/cmd.yaml index 0d0494894..9a5592b63 100644 --- a/runner/cmd.yaml +++ b/runner/cmd.yaml @@ -1,4 +1,14 @@ stream: '-y -hide_banner -nostats %v -t %.0f -i %v -c:v copy -c:a copy -f mpegts %v -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename %v/%%05d.ts %v' +SeparateAudioFast: "-i %v -vn -c:a copy %v" +SeparateAudio: "-i %v -vn %v" + +# Two-pass audio normalization with FFmpeg loudnorm +# Loudnorm configuration "I=-23:TP=-2:LRA=7" -- Chosen according to EBU R128 +## First pass: Audio analyse, get parameters needed in second pass +AudioNormalize1: "-i %v -nostats -y -af loudnorm=I=-23:TP=-2:LRA=7:print_format=json -f null -" +## Second pass: Apply normalization to the audio +AudioNormalize2: "-i %v -af loudnorm=I=-23:TP=-2:LRA=7:measured_i=%v:measured_tp=%v:measured_lra=%v:measured_thresh=%v:offset=%v:linear=true:print_format=summary -c:v copy -c:a aac %v" + Transcoding: '-i %v -c:v libx264 -c:a copy -crf 0 -probesize 100M -analyzeduration 250M %v' diff --git a/runner/config/cmd.go b/runner/config/cmd.go index ae84ceb63..d957dbb4d 100644 --- a/runner/config/cmd.go +++ b/runner/config/cmd.go @@ -9,8 +9,12 @@ import ( type CmdList struct { //this is for adding extra parameters - Stream string `Default:"-y -hide_banner -nostats %x -t &.0f -i %s -c:v copy -c:a copy -f mpegts %x -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename %x %x"` - Transcoding string `Default:"-i %v -c:v libx264 %v"` + Stream string `Default:"-y -hide_banner -nostats %x -t &.0f -i %s -c:v copy -c:a copy -f mpegts %x -c:v libx264 -preset veryfast -tune zerolatency -maxrate 2500k -bufsize 3000k -g 60 -r 30 -x264-params keyint=60:scenecut=0 -c:a aac -ar 44100 -b:a 128k -f hls -hls_time 2 -hls_list_size 3600 -hls_playlist_type event -hls_flags append_list -hls_segment_filename %x %x"` + SeparateAudioFast string `Default:"-i %v -vn -c:a copy %v"` + SeparateAudio string `Default:"-i %v -vn %v"` + AudioNormalize1 string `Default:"-i %v -nostats -y -af loudnorm=I=-23:TP=-2:LRA=7:print_format=json -f null -"` + AudioNormalize2 string `Default:"-i %v -af loudnorm=I=-23:TP=-2:LRA=7:measured_i=%v:measured_tp=%v:measured_lra=%v:measured_thresh=%v:offset=%v:linear=true:print_format=summary -c:v copy -c:a aac %v"` + Transcoding string `Default:"-i %v -c:v libx264 %v"` } func NewCmd(log *slog.Logger) *CmdList { diff --git a/runner/handlers.go b/runner/handlers.go index c7b5bbd4d..844af0153 100644 --- a/runner/handlers.go +++ b/runner/handlers.go @@ -25,6 +25,7 @@ func (r *Runner) RequestStream(ctx context.Context, req *protobuf.StreamRequest) r.actions.PrepareAction(), r.actions.StreamAction(), r.actions.TranscodeAction(), + r.actions.AudioNormalizeAction(), //r.actions.GenerateVideoThumbnail(), r.actions.UploadAction(), } From 9ecefa64ccd189fd2506882ac7cb8fdbf40f65fb Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 11 Feb 2024 00:57:01 +0100 Subject: [PATCH 2/8] Pass 1 realised in a new action --- runner/actions/audio_normalize.go | 107 ++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 runner/actions/audio_normalize.go diff --git a/runner/actions/audio_normalize.go b/runner/actions/audio_normalize.go new file mode 100644 index 000000000..4e96c1c82 --- /dev/null +++ b/runner/actions/audio_normalize.go @@ -0,0 +1,107 @@ +package actions + +import ( + "bufio" + "bytes" + "context" + "encoding/json" + "fmt" + "log/slog" + "os" + "os/exec" + "regexp" + "strings" +) + +type InfoForAudioNormalization struct { + InputI string `json:"input_i"` + InputTp string `json:"input_tp"` + InputLra string `json:"input_lra"` + InputThresh string `json:"input_thresh"` + OutputI string `json:"output_i"` + OutputTp string `json:"output_tp"` + OutputLra string `json:"output_lra"` + OutputThresh string `json:"output_thresh"` + NormalizationType string `json:"normalization_type"` + TargetOffset string `json:"target_offset"` +} + +func (a *ActionProvider) AudioNormalizeAction() *Action { + return &Action{ + Type: AudioNormalizeAction, + ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { + + streamID, ok := ctx.Value("stream").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain stream", ErrRequiredContextValNotFound) + } + courseID, ok := ctx.Value("course").(uint64) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain courseID", ErrRequiredContextValNotFound) + } + version, ok := ctx.Value("version").(string) + if !ok { + return ctx, fmt.Errorf("%w: context doesn't contain version", ErrRequiredContextValNotFound) + } + + fileName := fmt.Sprintf("%s/%s/%s/%s.mp4", a.MassDir, courseID, streamID, version) + + // Pass 1 + // Errors during pass 1 should not propagate to outside. + // Thus, in the following code whenever an error occurs, ctx and nil are returned. + // But errors will prevent pass 2 from executing, ultimately resulting in the video not undergoing audio normalization. + cmd := fmt.Sprintf(a.Cmd.AudioNormalize1, fileName) + c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) + c.Stderr = os.Stderr + stdoutPipe, err := c.StdoutPipe() + if err != nil { + return ctx, nil + } + err = c.Start() + if err != nil { + return ctx, nil + } + + var output bytes.Buffer + scanner := bufio.NewScanner(stdoutPipe) + go func() { // Reads the output from FFmpeg + for scanner.Scan() { + line := scanner.Text() + output.WriteString(line + "\n") + } + }() + + err = c.Wait() + if err != nil { + return ctx, nil + } + + info := &InfoForAudioNormalization{} + err = extractAndParseJSON(output.String(), info) + if err != nil { + return ctx, nil + } + + // pass 2 + // TODO + return ctx, nil + }, + } +} + +func extractAndParseJSON(output string, info *InfoForAudioNormalization) error { + re := regexp.MustCompile(`(?s)\{.*\}`) // Finds JSON data from the output + matches := re.FindStringSubmatch(output) + + if len(matches) == 0 { + return fmt.Errorf("no JSON data found") + } + + jsonData := matches[0] + err := json.Unmarshal([]byte(jsonData), info) + if err != nil { + return err + } + + return nil +} From 76975b15889aba5d801872640dfabe2d45309c7b Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 25 Feb 2024 22:50:26 +0100 Subject: [PATCH 3/8] Make sure transcoding with audio normalization does the same to video. --- runner/cmd.yaml | 3 +-- runner/config/cmd.go | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/runner/cmd.yaml b/runner/cmd.yaml index 9a5592b63..74a325837 100644 --- a/runner/cmd.yaml +++ b/runner/cmd.yaml @@ -8,7 +8,6 @@ SeparateAudio: "-i %v -vn %v" ## First pass: Audio analyse, get parameters needed in second pass AudioNormalize1: "-i %v -nostats -y -af loudnorm=I=-23:TP=-2:LRA=7:print_format=json -f null -" ## Second pass: Apply normalization to the audio -AudioNormalize2: "-i %v -af loudnorm=I=-23:TP=-2:LRA=7:measured_i=%v:measured_tp=%v:measured_lra=%v:measured_thresh=%v:offset=%v:linear=true:print_format=summary -c:v copy -c:a aac %v" +AudioNormalize2: "-i %v -af loudnorm=I=-23:TP=-2:LRA=7:measured_i=%v:measured_tp=%v:measured_lra=%v:measured_thresh=%v:offset=%v:linear=true:print_format=summary -c:a aac -c:v libx264 -crf 0 -probesize 100M -analyzeduration 250M %v" Transcoding: '-i %v -c:v libx264 -c:a copy -crf 0 -probesize 100M -analyzeduration 250M %v' - diff --git a/runner/config/cmd.go b/runner/config/cmd.go index d957dbb4d..04660c4f3 100644 --- a/runner/config/cmd.go +++ b/runner/config/cmd.go @@ -13,7 +13,7 @@ type CmdList struct { SeparateAudioFast string `Default:"-i %v -vn -c:a copy %v"` SeparateAudio string `Default:"-i %v -vn %v"` AudioNormalize1 string `Default:"-i %v -nostats -y -af loudnorm=I=-23:TP=-2:LRA=7:print_format=json -f null -"` - AudioNormalize2 string `Default:"-i %v -af loudnorm=I=-23:TP=-2:LRA=7:measured_i=%v:measured_tp=%v:measured_lra=%v:measured_thresh=%v:offset=%v:linear=true:print_format=summary -c:v copy -c:a aac %v"` + AudioNormalize2 string `Default:"-i %v -af loudnorm=I=-23:TP=-2:LRA=7:measured_i=%v:measured_tp=%v:measured_lra=%v:measured_thresh=%v:offset=%v:linear=true:print_format=summary -c:a aac -c:v libx264 -crf 0 -probesize 100M -analyzeduration 250M %v"` Transcoding string `Default:"-i %v -c:v libx264 %v"` } From c69431a5bb469b69427fbd19f676b5dd67737bc2 Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 25 Feb 2024 22:52:02 +0100 Subject: [PATCH 4/8] Integrate audio normalization into transcode. Apply it only when exactly 1 video exists for the stream. --- runner/actions/audio_normalize.go | 107 ------------------------------ runner/actions/transcode.go | 90 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 107 deletions(-) delete mode 100644 runner/actions/audio_normalize.go diff --git a/runner/actions/audio_normalize.go b/runner/actions/audio_normalize.go deleted file mode 100644 index 4e96c1c82..000000000 --- a/runner/actions/audio_normalize.go +++ /dev/null @@ -1,107 +0,0 @@ -package actions - -import ( - "bufio" - "bytes" - "context" - "encoding/json" - "fmt" - "log/slog" - "os" - "os/exec" - "regexp" - "strings" -) - -type InfoForAudioNormalization struct { - InputI string `json:"input_i"` - InputTp string `json:"input_tp"` - InputLra string `json:"input_lra"` - InputThresh string `json:"input_thresh"` - OutputI string `json:"output_i"` - OutputTp string `json:"output_tp"` - OutputLra string `json:"output_lra"` - OutputThresh string `json:"output_thresh"` - NormalizationType string `json:"normalization_type"` - TargetOffset string `json:"target_offset"` -} - -func (a *ActionProvider) AudioNormalizeAction() *Action { - return &Action{ - Type: AudioNormalizeAction, - ActionFn: func(ctx context.Context, log *slog.Logger) (context.Context, error) { - - streamID, ok := ctx.Value("stream").(uint64) - if !ok { - return ctx, fmt.Errorf("%w: context doesn't contain stream", ErrRequiredContextValNotFound) - } - courseID, ok := ctx.Value("course").(uint64) - if !ok { - return ctx, fmt.Errorf("%w: context doesn't contain courseID", ErrRequiredContextValNotFound) - } - version, ok := ctx.Value("version").(string) - if !ok { - return ctx, fmt.Errorf("%w: context doesn't contain version", ErrRequiredContextValNotFound) - } - - fileName := fmt.Sprintf("%s/%s/%s/%s.mp4", a.MassDir, courseID, streamID, version) - - // Pass 1 - // Errors during pass 1 should not propagate to outside. - // Thus, in the following code whenever an error occurs, ctx and nil are returned. - // But errors will prevent pass 2 from executing, ultimately resulting in the video not undergoing audio normalization. - cmd := fmt.Sprintf(a.Cmd.AudioNormalize1, fileName) - c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) - c.Stderr = os.Stderr - stdoutPipe, err := c.StdoutPipe() - if err != nil { - return ctx, nil - } - err = c.Start() - if err != nil { - return ctx, nil - } - - var output bytes.Buffer - scanner := bufio.NewScanner(stdoutPipe) - go func() { // Reads the output from FFmpeg - for scanner.Scan() { - line := scanner.Text() - output.WriteString(line + "\n") - } - }() - - err = c.Wait() - if err != nil { - return ctx, nil - } - - info := &InfoForAudioNormalization{} - err = extractAndParseJSON(output.String(), info) - if err != nil { - return ctx, nil - } - - // pass 2 - // TODO - return ctx, nil - }, - } -} - -func extractAndParseJSON(output string, info *InfoForAudioNormalization) error { - re := regexp.MustCompile(`(?s)\{.*\}`) // Finds JSON data from the output - matches := re.FindStringSubmatch(output) - - if len(matches) == 0 { - return fmt.Errorf("no JSON data found") - } - - jsonData := matches[0] - err := json.Unmarshal([]byte(jsonData), info) - if err != nil { - return err - } - - return nil -} diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go index 87cfcd74b..988fe1309 100644 --- a/runner/actions/transcode.go +++ b/runner/actions/transcode.go @@ -1,12 +1,16 @@ package actions import ( + "bufio" + "bytes" "context" + "encoding/json" "errors" "fmt" "log/slog" "os" "os/exec" + "regexp" "strings" "time" ) @@ -67,7 +71,26 @@ func (a *ActionProvider) TranscodeAction() *Action { i++ } + // Pass 1 of audio normalization. + // Audio normalization is only applied, when only one video of the stream exists. Reasons for this: + // 1. Multiple videos existing for one stream is typically caused by a shutdown of a runner. This does not happen frequently. + // 2. It's much more inefficient to apply the audio normalization operation for more than one file: + // 2.1 Instead of 2 passes, 3 passes are needed: concat - get parameter - execute; + // 2.2 Video files need to be stored 3 times instead of twice (including the raw .ts files), at least temporarily + // (Extracting and only operating/storing the audio is unacceptable due to the problem mentioned in one comment of this answer: https://stackoverflow.com/a/27413824) + var info *InfoForAudioNormalization = nil + if len(fileName) == 1 { + info, err = getInfoForAudioNormalization(ctx, a.Cmd.AudioNormalize1, fileName[0]) + } + cmd := fmt.Sprintf(a.Cmd.Transcoding, filenames, outputName) + // Pass 2 of audio normalization + // Applied only when pass 1 is successfully executed + // It does the same to the video, and additionally normalizes the audio with the given parameters from pass 1 + if info != nil { + cmd = fmt.Sprintf(a.Cmd.AudioNormalize2, filenames, + info.InputI, info.InputTp, info.InputLra, info.InputThresh, info.TargetOffset, outputName) + } c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) c.Stderr = os.Stderr err = c.Start() @@ -79,3 +102,70 @@ func (a *ActionProvider) TranscodeAction() *Action { }, } } + +type InfoForAudioNormalization struct { + InputI string `json:"input_i"` + InputTp string `json:"input_tp"` + InputLra string `json:"input_lra"` + InputThresh string `json:"input_thresh"` + OutputI string `json:"output_i"` + OutputTp string `json:"output_tp"` + OutputLra string `json:"output_lra"` + OutputThresh string `json:"output_thresh"` + NormalizationType string `json:"normalization_type"` + TargetOffset string `json:"target_offset"` +} + +func getInfoForAudioNormalization(ctx context.Context, cmdFmt string, filename string) (*InfoForAudioNormalization, error) { + // Errors during pass 1 won't propagate to outside. + // But errors will prevent pass 2 from executing, ultimately resulting in the video not undergoing audio normalization. + cmd := fmt.Sprintf(cmdFmt, filename) + c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) + c.Stderr = os.Stderr + stdoutPipe, err := c.StdoutPipe() + if err != nil { + return nil, nil + } + err = c.Start() + if err != nil { + return nil, nil + } + + var output bytes.Buffer + scanner := bufio.NewScanner(stdoutPipe) + go func() { // Reads the output from FFmpeg + for scanner.Scan() { + line := scanner.Text() + output.WriteString(line + "\n") + } + }() + + err = c.Wait() + if err != nil { + return nil, nil + } + + info := &InfoForAudioNormalization{} + err = extractAndParseJSON(output.String(), info) + if err != nil { + return nil, nil + } + return info, nil +} + +func extractAndParseJSON(output string, info *InfoForAudioNormalization) error { + re := regexp.MustCompile(`(?s)\{.*}`) // Finds JSON data from the output + matches := re.FindStringSubmatch(output) + + if len(matches) == 0 { + return fmt.Errorf("no JSON data found") + } + + jsonData := matches[0] + err := json.Unmarshal([]byte(jsonData), info) + if err != nil { + return err + } + + return nil +} From 11f3a3d416f066ba82658576ea9b996689177244 Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 25 Feb 2024 22:58:40 +0100 Subject: [PATCH 5/8] Pass 1: properly return error message --- runner/actions/transcode.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go index 988fe1309..2b160817b 100644 --- a/runner/actions/transcode.go +++ b/runner/actions/transcode.go @@ -124,11 +124,11 @@ func getInfoForAudioNormalization(ctx context.Context, cmdFmt string, filename s c.Stderr = os.Stderr stdoutPipe, err := c.StdoutPipe() if err != nil { - return nil, nil + return nil, err } err = c.Start() if err != nil { - return nil, nil + return nil, err } var output bytes.Buffer @@ -142,15 +142,15 @@ func getInfoForAudioNormalization(ctx context.Context, cmdFmt string, filename s err = c.Wait() if err != nil { - return nil, nil + return nil, err } info := &InfoForAudioNormalization{} err = extractAndParseJSON(output.String(), info) if err != nil { - return nil, nil + return nil, err } - return info, nil + return info, err } func extractAndParseJSON(output string, info *InfoForAudioNormalization) error { From f172a0bec06074f2fba3dc0e409a59c9c7b0b8d4 Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 25 Feb 2024 23:08:18 +0100 Subject: [PATCH 6/8] Pass 1: 1. synchronise reading from stdin before extracting info; 2. make sure to close everything in case of error --- runner/actions/transcode.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go index 2b160817b..58057e883 100644 --- a/runner/actions/transcode.go +++ b/runner/actions/transcode.go @@ -12,6 +12,7 @@ import ( "os/exec" "regexp" "strings" + "sync" "time" ) @@ -126,6 +127,8 @@ func getInfoForAudioNormalization(ctx context.Context, cmdFmt string, filename s if err != nil { return nil, err } + defer stdoutPipe.Close() + err = c.Start() if err != nil { return nil, err @@ -133,7 +136,12 @@ func getInfoForAudioNormalization(ctx context.Context, cmdFmt string, filename s var output bytes.Buffer scanner := bufio.NewScanner(stdoutPipe) + + var wg sync.WaitGroup + wg.Add(1) + go func() { // Reads the output from FFmpeg + defer wg.Done() for scanner.Scan() { line := scanner.Text() output.WriteString(line + "\n") @@ -145,6 +153,8 @@ func getInfoForAudioNormalization(ctx context.Context, cmdFmt string, filename s return nil, err } + wg.Wait() + info := &InfoForAudioNormalization{} err = extractAndParseJSON(output.String(), info) if err != nil { From 57444fd9a37cdb6943a46732b194c2e650a17bda Mon Sep 17 00:00:00 2001 From: meandaD Date: Sun, 25 Feb 2024 23:10:07 +0100 Subject: [PATCH 7/8] Audio normalization: log when applied --- runner/actions/transcode.go | 1 + 1 file changed, 1 insertion(+) diff --git a/runner/actions/transcode.go b/runner/actions/transcode.go index 58057e883..5e45d885f 100644 --- a/runner/actions/transcode.go +++ b/runner/actions/transcode.go @@ -91,6 +91,7 @@ func (a *ActionProvider) TranscodeAction() *Action { if info != nil { cmd = fmt.Sprintf(a.Cmd.AudioNormalize2, filenames, info.InputI, info.InputTp, info.InputLra, info.InputThresh, info.TargetOffset, outputName) + log.Info("Transcoding with audio normalization", "files", files) } c := exec.CommandContext(ctx, "ffmpeg", strings.Split(cmd, " ")...) c.Stderr = os.Stderr From c992954e445cb60dd5cfe0f54d81eb18e25dc429 Mon Sep 17 00:00:00 2001 From: meandaD Date: Mon, 26 Feb 2024 15:16:05 +0100 Subject: [PATCH 8/8] Remove the unused action AudioNormalization --- runner/actions/actions.go | 13 ++++++------- runner/handlers.go | 1 - 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/runner/actions/actions.go b/runner/actions/actions.go index fe61077b3..d1bd32556 100644 --- a/runner/actions/actions.go +++ b/runner/actions/actions.go @@ -39,13 +39,12 @@ func (a *ActionProvider) GetMassDir(courseID, streamID uint64, version string) s type ActionType string const ( - PrepareAction ActionType = "prepare" - StreamAction = "stream" - TranscodeAction = "transcode" - UploadAction = "upload" - ThumbnailAction = "thumbnail" - SelfStreamAction = "selfstream" - AudioNormalizeAction = "audio_normalize" + PrepareAction ActionType = "prepare" + StreamAction = "stream" + TranscodeAction = "transcode" + UploadAction = "upload" + ThumbnailAction = "thumbnail" + SelfStreamAction = "selfstream" ) type Action struct { diff --git a/runner/handlers.go b/runner/handlers.go index 844af0153..c7b5bbd4d 100644 --- a/runner/handlers.go +++ b/runner/handlers.go @@ -25,7 +25,6 @@ func (r *Runner) RequestStream(ctx context.Context, req *protobuf.StreamRequest) r.actions.PrepareAction(), r.actions.StreamAction(), r.actions.TranscodeAction(), - r.actions.AudioNormalizeAction(), //r.actions.GenerateVideoThumbnail(), r.actions.UploadAction(), }