PR #25516 opened by Marti2203
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25516
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25516.patch
When a new chained Vorbis stream starts in an Ogg file, `vorbis_packet()` packs
its three header packets into new extradata with 16-bit big-endian size
prefixes. A header larger than 65535 bytes gets its size truncated. This is
usually a comment header with embedded cover art (`METADATA_BLOCK_PICTURE`).
The Vorbis parser then cannot be reinitialized ("Wrong packet type in Setup
header", "Failed to re-initialize Vorbis parser") and demuxing stops with
"Invalid data found when processing input". The audio of that chained stream is
lost, and so is everything after it. The first stream of a file is not
affected, because `vorbis_header()` builds its extradata with Xiph lacing.
The fix builds the chained-stream extradata with Xiph lacing as well.
`avpriv_split_xiph_headers()`, the Vorbis parser and the decoder already accept
that format.
Verification (master a497ab4d07, release and ASan builds):
- I cut 1 s from `vorbis/moog_small.ogg` with a comment of 1000, 65000, 70000
or 300000 bytes and appended it to the full sample as a second chained stream.
Before the fix, the 70000- and 300000-byte cases lose all 48 packets of the
second stream. With a small third stream appended after it, that one is lost
too (352 of 448 packets demuxed). The 1000- and 65000-byte cases are fine.
After the fix, every case demuxes and decodes completely, and a chained copy
decodes to the same PCM as the file on its own (checked with the file chained
to itself). Both builds are ASan-clean.
- `fate-ogg-vorbis`, `fate-vorbis` (decode tests; `vorbis-encode-1` needs
`audio-reference/`, which I did not have), `fate-oggtheora-demux`,
`fate-oggvp8-demux` and `fate-limited_input_seek` pass unchanged.
- The new `fate-ogg-vorbis-chained-large-comment` (second patch) needs no new
sample. It remuxes two 0.5 s pieces of `vorbis/moog_small.ogg`, the second with
a 70000-byte comment read from a generated ffmetadata file. It then runs
`framecrc -c copy` on their concatenation through the concat protocol. It fails
without the fix (all 26 packets of the second stream are missing) and passes
with it.
This issue was found by an LLM-Enhanced Static Analysis Engine and verified
manually.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
From 2f05793853e2dfbffc5aae7631e58741c4b334ca Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Tue, 27 Oct 2026 11:49:49 +0800
Subject: [PATCH 1/2] avformat/oggparsevorbis: fix chained streams with headers
over 64 KiB
When a chained Vorbis stream starts, its three header packets are
packed into new extradata with 16-bit size prefixes. A header larger
than 65535 bytes, typically a comment header with embedded cover art,
gets its size truncated, so the Vorbis parser cannot be reinitialized
and demuxing fails with "Failed to re-initialize Vorbis parser". The
audio of the new chained stream and everything after it is lost.
Use Xiph lacing instead, as vorbis_header() already does for the
initial extradata.
Signed-off-by: Martin Mirchev <[email protected]>
---
libavformat/oggparsevorbis.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index 3ad72cd69a4..18160ec3ddb 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -463,7 +463,6 @@ static int vorbis_packet(AVFormatContext *s, int idx)
int duration, flags = 0;
int bos, skip_packet = 0;
int ret, new_extradata_size;
- PutByteContext pb;
if (os->psize == 0)
return AVERROR_INVALIDDATA;
@@ -609,20 +608,32 @@ static int vorbis_packet(AVFormatContext *s, int idx)
/* All three headers for the new chained stream have been collected;
* pack them into new extradata to be attached to the next data packet. */
if (priv->header && priv->comment && priv->setup) {
- new_extradata_size = priv->header_size + priv->comment_size +
priv->setup_size + 6;
+ uint64_t total_size = (uint64_t)priv->header_size + priv->comment_size
+
+ priv->setup_size;
+ uint8_t *p;
+
+ /* Use Xiph lacing like vorbis_header() does: 16-bit sizes cannot
+ * describe headers larger than 64 KiB, e.g. a comment header with
+ * embedded cover art. */
+ if (total_size + total_size / 255 + 3 > INT_MAX)
+ return AVERROR_INVALIDDATA;
+ new_extradata_size = 1 + priv->header_size / 255 + 1 +
+ priv->comment_size / 255 + 1 + total_size;
ret = av_reallocp(&os->new_extradata, new_extradata_size);
if (ret < 0)
return ret;
os->new_extradata_size = new_extradata_size;
- bytestream2_init_writer(&pb, os->new_extradata, new_extradata_size);
- bytestream2_put_be16(&pb, priv->header_size);
- bytestream2_put_buffer(&pb, priv->header, priv->header_size);
- bytestream2_put_be16(&pb, priv->comment_size);
- bytestream2_put_buffer(&pb, priv->comment, priv->comment_size);
- bytestream2_put_be16(&pb, priv->setup_size);
- bytestream2_put_buffer(&pb, priv->setup, priv->setup_size);
+ p = os->new_extradata;
+ *p++ = 2;
+ p += av_xiphlacing(p, priv->header_size);
+ p += av_xiphlacing(p, priv->comment_size);
+ memcpy(p, priv->header, priv->header_size);
+ p += priv->header_size;
+ memcpy(p, priv->comment, priv->comment_size);
+ p += priv->comment_size;
+ memcpy(p, priv->setup, priv->setup_size);
av_freep(&priv->header);
priv->header_size = 0;
--
2.54.0
From 38b5196d3fbb259f11b567e2723738949a1f2aa2 Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Tue, 27 Oct 2026 11:49:49 +0800
Subject: [PATCH 2/2] fate/ogg-vorbis: add a test for a chained stream with a
large comment
Remux two short streams from an existing sample, the second one with a
70000-byte comment header, and demux their concatenation.
Signed-off-by: Martin Mirchev <[email protected]>
---
tests/fate/ogg-vorbis.mak | 13 +++++
.../ref/fate/ogg-vorbis-chained-large-comment | 58 +++++++++++++++++++
2 files changed, 71 insertions(+)
create mode 100644 tests/ref/fate/ogg-vorbis-chained-large-comment
diff --git a/tests/fate/ogg-vorbis.mak b/tests/fate/ogg-vorbis.mak
index e9151b63157..51d6a9e4d6a 100644
--- a/tests/fate/ogg-vorbis.mak
+++ b/tests/fate/ogg-vorbis.mak
@@ -7,6 +7,19 @@ fate-ogg-vorbis-copy-chained-meta:
$(APITESTSDIR)/api-dump-stream-meta-test$(EXE
fate-ogg-vorbis-copy-chained-meta: REF =
$(SRC_PATH)/tests/ref/fate/ogg-vorbis-chained-meta.txt
fate-ogg-vorbis-copy-chained-meta: CMD = run_with_temp "$(FFMPEG) -nostdin
-hide_banner -loglevel quiet -i $(TARGET_SAMPLES)/ogg-vorbis/chained-meta.ogg
-c copy -f ogg -y" "$(APITESTSDIR)/api-dump-stream-meta-test$(EXESUF)" ogg
+# Chain two streams cut from the same sample, the second one with a comment
+# header larger than 64 KiB (as with embedded cover art).
+FATE_OGG_COPY_VORBIS-$(call FRAMECRC, OGG FFMETADATA, VORBIS, OGG_MUXER
CONCAT_PROTOCOL) += fate-ogg-vorbis-chained-large-comment
+fate-ogg-vorbis-chained-large-comment: CMD = \
+ cleanfiles="$${cleanfiles} $${outfile}.txt $${outfile}.1.ogg
$${outfile}.2.ogg"; \
+ printf ";FFMETADATA1\ncomment=%070000d\n" 0 > "$${outfile}.txt" && \
+ ffmpeg -i $(TARGET_SAMPLES)/vorbis/moog_small.ogg -c copy -t 0.5 -fflags
+bitexact \
+ -y "$$(target_path "$${outfile}.1.ogg")" && \
+ ffmpeg -i $(TARGET_SAMPLES)/vorbis/moog_small.ogg -i "$$(target_path
"$${outfile}.txt")" \
+ -map 0 -map_metadata 1 -c copy -t 0.5 -fflags +bitexact -serial_offset
1 \
+ -y "$$(target_path "$${outfile}.2.ogg")" && \
+ framecrc -i "concat:$$(target_path "$${outfile}.1.ogg")|$$(target_path
"$${outfile}.2.ogg")" -c copy
+
FATE_OGG_VORBIS_PROBE-$(call DEMDEC, OGG, VORBIS) +=
fate-ogg-vorbis-initial-padding-chained
fate-ogg-vorbis-initial-padding-chained: CMD = ffprobe_demux -of default
-show_entries stream=codec_name,initial_padding
$(TARGET_SAMPLES)/ogg-vorbis/chained-meta.ogg
diff --git a/tests/ref/fate/ogg-vorbis-chained-large-comment
b/tests/ref/fate/ogg-vorbis-chained-large-comment
new file mode 100644
index 00000000000..20ca11e82cd
--- /dev/null
+++ b/tests/ref/fate/ogg-vorbis-chained-large-comment
@@ -0,0 +1,58 @@
+#extradata 0: 12456, 0xa1161932
+#tb 0: 1/44100
+#media_type 0: audio
+#codec_id 0: vorbis
+#sample_rate 0: 44100
+#channel_layout_name 0: stereo
+0, -128, -128, 128, 3, 0x00000000, S=1, Strings
Metadata, 106, 0xe088249e
+0, 0, 0, 576, 4, 0x0028000a
+0, 576, 576, 1024, 4, 0x0038000e
+0, 1600, 1600, 1024, 4, 0x0038000e
+0, 2624, 2624, 1024, 4, 0x00180006
+0, 3648, 3648, 576, 3, 0x00000000
+0, 4224, 4224, 128, 54, 0x014c1a96
+0, 4352, 4352, 128, 55, 0x2f911b84
+0, 4480, 4480, 576, 420, 0xf6dbdbbc
+0, 5056, 5056, 1024, 387, 0x0c56c7ba
+0, 6080, 6080, 1024, 393, 0x6327c817
+0, 7104, 7104, 1024, 358, 0x578bb0b5
+0, 8128, 8128, 1024, 301, 0x3f658f2f
+0, 9152, 9152, 1024, 303, 0xe1a2955f
+0, 10176, 10176, 1024, 311, 0x4f829c54
+0, 11200, 11200, 1024, 308, 0x1d1a9ae7
+0, 12224, 12224, 1024, 282, 0x10428728
+0, 13248, 13248, 1024, 274, 0xd201846b
+0, 14272, 14272, 1024, 297, 0x688a8dee
+0, 15296, 15296, 1024, 279, 0x01fc85c1
+0, 16320, 16320, 1024, 299, 0xeb658ff2
+0, 17344, 17344, 1024, 286, 0x01569307
+0, 18368, 18368, 1024, 307, 0x331a8a6a
+0, 19392, 19392, 1024, 293, 0x59eb908a
+0, 20416, 20416, 1024, 294, 0x11dc9474
+0, 21440, 21440, 1024, 300, 0x7c9d9254, S=1, Skip Samples,
10, 0x03000080
+0, 22464, 22464, 128, 3, 0x00000000, S=2, Strings
Metadata, 70115, 0xf8df6f8e, New Extradata, 82871, 0x33479e75
+0, 22592, 22592, 576, 4, 0x0028000a
+0, 23168, 23168, 1024, 4, 0x0038000e
+0, 24192, 24192, 1024, 4, 0x0038000e
+0, 25216, 25216, 1024, 4, 0x00180006
+0, 26240, 26240, 576, 3, 0x00000000
+0, 26816, 26816, 128, 54, 0x014c1a96
+0, 26944, 26944, 128, 55, 0x2f911b84
+0, 27072, 27072, 576, 420, 0xf6dbdbbc
+0, 27648, 27648, 1024, 387, 0x0c56c7ba
+0, 28672, 28672, 1024, 393, 0x6327c817
+0, 29696, 29696, 1024, 358, 0x578bb0b5
+0, 30720, 30720, 1024, 301, 0x3f658f2f
+0, 31744, 31744, 1024, 303, 0xe1a2955f
+0, 32768, 32768, 1024, 311, 0x4f829c54
+0, 33792, 33792, 1024, 308, 0x1d1a9ae7
+0, 34816, 34816, 1024, 282, 0x10428728
+0, 35840, 35840, 1024, 274, 0xd201846b
+0, 36864, 36864, 1024, 297, 0x688a8dee
+0, 37888, 37888, 1024, 279, 0x01fc85c1
+0, 38912, 38912, 1024, 299, 0xeb658ff2
+0, 39936, 39936, 1024, 286, 0x01569307
+0, 40960, 40960, 1024, 307, 0x331a8a6a
+0, 41984, 41984, 1024, 293, 0x59eb908a
+0, 43008, 43008, 1024, 294, 0x11dc9474
+0, 44032, 44032, 1024, 300, 0x7c9d9254, S=1, Skip Samples,
10, 0x03000080
--
2.54.0
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]