diff --git a/internal/adapters/audio/ffmpeg_test.go b/internal/adapters/audio/ffmpeg_test.go index 57205a5..e4bebb9 100644 --- a/internal/adapters/audio/ffmpeg_test.go +++ b/internal/adapters/audio/ffmpeg_test.go @@ -109,3 +109,20 @@ printf data > "$last"`) require.NoError(t, err) assert.NotContains(t, " "+strings.ReplaceAll(string(raw), "\n", " ")+" ", " -t ") } + +func TestFFmpegToWAV_CapsTheStreamCountBeforeTheInput(t *testing.T) { + // ffmpeg also allocated ~570 MB opening the 900-stream file (#49). + rec := filepath.Join(t.TempDir(), "argv") + bin := stub(t, `printf '%s\n' "$@" > `+rec+` +for a; do last="$a"; done +printf data > "$last"`) + + err := (&audio.FFmpeg{Bin: bin}).ToWAV(context.Background(), "/spool/in", filepath.Join(t.TempDir(), "o.wav")) + + require.NoError(t, err) + args := argvOf(t, rec) + ms, in := indexOf(args, "-max_streams"), indexOf(args, "-i") + require.GreaterOrEqual(t, ms, 0, "argv: %v", args) + assert.Equal(t, "32", args[ms+1]) + assert.Less(t, ms, in, "an input option placed after -i is applied to the output") +} diff --git a/internal/adapters/audio/ffprobe_test.go b/internal/adapters/audio/ffprobe_test.go index 214320b..5190abb 100644 --- a/internal/adapters/audio/ffprobe_test.go +++ b/internal/adapters/audio/ffprobe_test.go @@ -184,3 +184,34 @@ func TestAllowedDemuxers_ExcludeThePlaylistFormats(t *testing.T) { assert.Contains(t, strings.Split(audio.AllowedDemuxers, ","), good) } } + +func TestFFprobeProbe_CapsTheStreamCountBeforeTheInput(t *testing.T) { + // A 1.3 MB file declaring 900 streams cost ~570 MB of RSS in ffprobe (#49) against + // a 512 Mi pod. -max_streams is an input option: it must precede the path. + bin, argvFile := argvStub(t) + + _, err := (&audio.FFprobe{Bin: bin}).Probe(context.Background(), "/spool/upload-1") + + require.NoError(t, err) + args := argvOf(t, argvFile) + ms := indexOf(args, "-max_streams") + require.GreaterOrEqual(t, ms, 0, "argv: %v", args) + assert.Equal(t, "32", args[ms+1]) + assert.Less(t, ms, len(args)-1, "must come before the path, which stays last") +} + +func TestFFprobeProbe_AsksOnlyForTheFieldsParseProbeReads(t *testing.T) { + // -show_format/-show_streams print every tag: a 120 MB WAV produced 491 MB of JSON + // that cmd.Output() buffers in Go (#49). + bin, argvFile := argvStub(t) + + _, err := (&audio.FFprobe{Bin: bin}).Probe(context.Background(), "/spool/upload-1") + + require.NoError(t, err) + args := argvOf(t, argvFile) + assert.Equal(t, -1, indexOf(args, "-show_format"), "argv: %v", args) + assert.Equal(t, -1, indexOf(args, "-show_streams"), "argv: %v", args) + se := indexOf(args, "-show_entries") + require.GreaterOrEqual(t, se, 0, "argv: %v", args) + assert.Equal(t, "format=duration:stream=codec_type:stream_disposition=attached_pic", args[se+1]) +}