PR #24084 opened by OursCodeur
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24084
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24084.patch

Opening a canonical PCM wav runs a content probe over the early packet data 
before the stream is finalized; debug log on any pcm_s16le file:

```
[wav @ ...] Probe with size=8192, packets=2470 detected mp3 with score=1
[wav @ ...] probed stream 0
```

The mp3 "detection" scores 1 (the junk floor), and the stream settles on 
exactly what the fmt chunk already said. handle_stream_probing() requests this 
for PCM_S16LE deliberately, and for mislabelled files it is crucial, so this PR 
does not change the default. It adds an opt-out for callers that trust their 
container:

- ~3.3ms of CPU per open on an i7-13700KF, on the calling thread, inside the 
first av_read_frame calls.
- For a game engine, effect sounds are (often) small wavs opened and (also 
often) decoded synchronously at play time, dozens per minute; 3.3ms is a large 
budget if you want to hold 60+ FPS, paid even when every file is canonical PCM.
- Found it while validating storage-latency work in OpenMW 
(https://gitlab.com/OpenMW/openmw/-/merge_requests/5488 and follow-ups); it 
reproduces from page cache and through bare ffprobe.

Validation (patched ffprobe):
- default + honest pcm_s16le: probe runs, stream pcm_s16le (unchanged)
- `-stream_probe 0` + accurate pcm: no probe, stream pcm_s16le
- default + crafted mislabelled file (PCM tag, mp3 data): mp3 detected 
(unchanged)
- `-stream_probe 0` + mislabelled: header trusted, reports pcm_s16le (as 
intended if you opt out)


>From 192cff0bdc66f075620ac810de5b34bc61362b32 Mon Sep 17 00:00:00 2001
From: Thomas Portal <[email protected]>
Date: Tue, 11 Aug 2026 19:21:28 +0200
Subject: [PATCH] avformat/wavdec: add stream_probe option to allow skipping
 content probing

The wav demuxer requests a codec probe of the packet data for
PCM_S16LE streams to catch mislabelled files (mp3 data carrying a PCM
codec tag). The probe runs the format probe battery over the first
packets on every open: ~3.3ms of CPU on an i7-13700KF, on the calling
thread, and proportionally more on weaker machines. Callers that open
many known-good files at interactive latency (a game engine decoding
its own effect assets at play time) have no way to skip it.

Add a stream_probe bool option next to ignore_length, default on, so
such callers can opt out and trust the header. Covers the w64 demuxer
through the shared options table. Default behavior is unchanged.

Signed-off-by: Thomas Portal <[email protected]>
---
 doc/demuxers.texi     |  8 ++++++++
 libavformat/version.h |  2 +-
 libavformat/wavdec.c  | 12 +++++++++---
 3 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index a1dd879b59..ca7b567ae3 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -1172,6 +1172,9 @@ This demuxer accepts the following options:
 @table @option
 @item max_size
 See the same option for the @ref{wav} demuxer.
+
+@item stream_probe
+See the same option for the @ref{wav} demuxer.
 @end table
 
 @anchor{wav}
@@ -1191,6 +1194,11 @@ Default is disabled.
 Specify the maximum packet size in bytes for the demuxed packets. By default
 this is set to 0, which means that a sensible value is chosen based on the
 input format.
+
+@item stream_probe @var{bool}
+Probe the packet content of PCM streams to detect mislabelled files (mp3 data
+carrying a PCM codec tag). Disabling skips this check and trusts the header,
+saving the per-open CPU cost on known-good files. Default is enabled.
 @end table
 
 @section webp
diff --git a/libavformat/version.h b/libavformat/version.h
index 384cbd49cc..fab766fccd 100644
--- a/libavformat/version.h
+++ b/libavformat/version.h
@@ -32,7 +32,7 @@
 #include "version_major.h"
 
 #define LIBAVFORMAT_VERSION_MINOR   5
-#define LIBAVFORMAT_VERSION_MICRO 101
+#define LIBAVFORMAT_VERSION_MICRO 102
 
 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \
                                                LIBAVFORMAT_VERSION_MINOR, \
diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c
index 8501d94deb..718550406d 100644
--- a/libavformat/wavdec.c
+++ b/libavformat/wavdec.c
@@ -62,6 +62,7 @@ typedef struct WAVDemuxContext {
     int audio_eof;
     int ignore_length;
     int max_size;
+    int stream_probe;
     int spdif;
     int smv_given_first;
     int unaligned; // e.g. if an odd number of bytes ID3 tag was prepended
@@ -76,6 +77,7 @@ static const AVOption demux_options[] = {
     { "ignore_length", "Ignore length", OFFSET(ignore_length), 
AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC },
 #endif
     { "max_size",      "max size of single packet", OFFSET(max_size), 
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1 << 22, DEC },
+    { "stream_probe",  "probe packet content for codecs the header cannot 
vouch for", OFFSET(stream_probe), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, DEC },
     { NULL },
 };
 
@@ -177,8 +179,12 @@ static int wav_probe(const AVProbeData *p)
     return 0;
 }
 
-static void handle_stream_probing(AVStream *st)
+static void handle_stream_probing(AVFormatContext *s, AVStream *st)
 {
+    WAVDemuxContext *wav = s->priv_data;
+
+    if (!wav->stream_probe)
+        return;
     if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16LE) {
         FFStream *const sti = ffstream(st);
         sti->request_probe = AVPROBE_SCORE_EXTENSION + 1;
@@ -196,7 +202,7 @@ static int wav_parse_fmt_tag(AVFormatContext *s, int64_t 
size, AVStream *st)
     ret = ff_get_wav_header(s, pb, st->codecpar, size, wav->rifx);
     if (ret < 0)
         return ret;
-    handle_stream_probing(st);
+    handle_stream_probing(s, st);
 
     ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
 
@@ -1007,7 +1013,7 @@ static int w64_read_header(AVFormatContext *s)
     ff_metadata_conv_ctx(s, NULL, wav_metadata_conv);
     ff_metadata_conv_ctx(s, NULL, ff_riff_info_conv);
 
-    handle_stream_probing(st);
+    handle_stream_probing(s, st);
     ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
 
     avio_seek(pb, data_ofs, SEEK_SET);
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to