Skip avformat_find_stream_info when the header fills the codec parameters

Related to #4880 (removes the frame-stalling cost, mp3 note at the end).

FFmpegDecoder::open() calls avformat_find_stream_info unconditionally. For wav files the scan reads packets across the whole file to estimate duration and bitrate; the decoder reads neither (playback position comes from packet pts and the sample rate). Everything open() does consume (codec id, channels, sample rate, stream time base) is already filled by the demuxer from the file header during avformat_open_input.

The change finds the audio stream after open and skips the scan when its codec parameters are complete, falling back to the scan otherwise.

i5-8365U, NVMe, system ffmpeg 8.1.2, Steam Morrowind GOTY

cold = per-file page-cache eviction via posix_fadvise

Standalone per-file stream init (open + find_stream_info):

p50 p95 max
wav today, cold 3.85 ms 12.1 ms 32.0 ms
wav today, warm 3.51 ms 11.3 ms 22.5 ms
wav with this change 0.49 ms 1.2 ms 4.1 ms
mp3 today, cold 0.42 ms 0.77 ms 1.8 ms

Under emulated slow storage (FUSE passthrough adding 30 ms per open and 8 ms per read, the class of device in the original report): today 110.5 ms p50 / 189 ms max per wav; with this change 56.9 ms p50 / 74 ms max. The remainder is the storage itself.

In-game, on the #4880 Sadrith Mora save, 180-second idle run, timing every avformat call with an interposer:

leg find_stream_info calls over 1 ms max
baseline, fast storage 16 of 30 11.6 ms
this change, fast storage 0 of 11 0.79 ms
baseline, slow storage 12 of 25 9.9 ms
this change, slow storage 0 of 16 0.77 ms

The lower call count is the wavs skipping my scan, each removed call was a frame-thread stall.

Across all shipped files, every wav (709) has complete codec parameters straight from the header, identical to the post-scan values; every mp3 (6447) reports incomplete parameters after open and takes the (unchanged) fallback path. The skip only engages where the scan is proven as useless.

avformat_open_input itself shows a ~50 ms tail on a few calls (present equally in baseline and patched code), likely the format probe reading the head of large music mp3s.

Merge request reports

Loading