From 1f8bd849fe01c47519ebe1766034491cf1dd360a Mon Sep 17 00:00:00 2001 From: Mathias Date: Sat, 3 Oct 2026 20:56:28 +0200 Subject: [PATCH] fix(audio): cap ffprobe/ffmpeg streams at 32 and narrow the probe output (#49) A 900-stream file cost ~570 MB RSS in each tool; with the cap the same file fails in ~18 MB and is reported as unreadable. Co-Authored-By: Claude Sonnet 5.5 --- internal/adapters/audio/ffprobe.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/adapters/audio/ffprobe.go b/internal/adapters/audio/ffprobe.go index 5b75b08..aadf231 100644 --- a/internal/adapters/audio/ffprobe.go +++ b/internal/adapters/audio/ffprobe.go @@ -30,9 +30,22 @@ type FFprobe struct { // formats. "mov" covers .mp4/.m4a/.3gp; "matroska" covers .webm. const AllowedDemuxers = "wav,mov,mp4,m4a,3gp,mp3,ogg,matroska,webm,flac,aac,opus,aiff,amr,asf" +// MaxStreams bounds how many streams a file may declare. A 1.3 MB file declaring 900 of +// them cost ~570 MB of RSS in each of ffprobe and ffmpeg (#49), against a 512 Mi pod; +// real recordings have a handful. +const MaxStreams = "32" + // inputRestrictions are ffmpeg/ffprobe INPUT options and must precede the input. -// Local files and pipes only: no network, no other protocols. -var inputRestrictions = []string{"-protocol_whitelist", "file,pipe", "-format_whitelist", AllowedDemuxers} +// Local files and pipes only: no network, no other protocols, and a bounded stream count. +var inputRestrictions = []string{ + "-protocol_whitelist", "file,pipe", + "-format_whitelist", AllowedDemuxers, + "-max_streams", MaxStreams, +} + +// probeEntries is exactly what ParseProbe reads. -show_format/-show_streams print every +// tag too, and a 120 MB WAV made 491 MB of JSON that Output() buffers. +const probeEntries = "format=duration:stream=codec_type:stream_disposition=attached_pic" // killGrace bounds how long Probe waits for a cancelled ffprobe's pipes to close. const killGrace = 2 * time.Second @@ -48,7 +61,7 @@ func (f *FFprobe) Probe(ctx context.Context, path string) (uploads.Probe, error) bin = "ffprobe" } args := append([]string{"-v", "error"}, inputRestrictions...) - args = append(args, "-print_format", "json", "-show_format", "-show_streams", path) + args = append(args, "-print_format", "json", "-show_entries", probeEntries, path) cmd := exec.CommandContext(ctx, bin, args...) cmd.WaitDelay = killGrace out, err := cmd.Output()