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 <noreply@anthropic.com>
This commit is contained in:
@@ -30,9 +30,22 @@ type FFprobe struct {
|
|||||||
// formats. "mov" covers .mp4/.m4a/.3gp; "matroska" covers .webm.
|
// 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"
|
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.
|
// inputRestrictions are ffmpeg/ffprobe INPUT options and must precede the input.
|
||||||
// Local files and pipes only: no network, no other protocols.
|
// 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}
|
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.
|
// killGrace bounds how long Probe waits for a cancelled ffprobe's pipes to close.
|
||||||
const killGrace = 2 * time.Second
|
const killGrace = 2 * time.Second
|
||||||
@@ -48,7 +61,7 @@ func (f *FFprobe) Probe(ctx context.Context, path string) (uploads.Probe, error)
|
|||||||
bin = "ffprobe"
|
bin = "ffprobe"
|
||||||
}
|
}
|
||||||
args := append([]string{"-v", "error"}, inputRestrictions...)
|
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 := exec.CommandContext(ctx, bin, args...)
|
||||||
cmd.WaitDelay = killGrace
|
cmd.WaitDelay = killGrace
|
||||||
out, err := cmd.Output()
|
out, err := cmd.Output()
|
||||||
|
|||||||
Reference in New Issue
Block a user