This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit afe9d68be1cc64f7cd0664fa7f27549f1b39b09c Author: Romain Beauxis <[email protected]> AuthorDate: Sun Sep 27 12:07:26 2026 -0500 Commit: Romain Beauxis <[email protected]> CommitDate: Mon Sep 28 13:55:51 2026 +0000 avformat/oggenc: derive bitexact serial numbers from the stream headers Bitexact outputs all used serial_offset + index, with serial_offset defaulting to 0, so chaining them broke the RFC 3533 requirement of a unique serial number per chained stream. Default serial_offset to -1, which derives the serial number from a CRC of the stream's headers. Links with different headers or tags then rarely share one. An explicit offset still allocates consecutive serial numbers. --- doc/muxers.texi | 18 ++++++++-- libavformat/oggenc.c | 56 +++++++++++++++++++++++--------- tests/ref/fate/limited_input_seek | 2 +- tests/ref/fate/limited_input_seek-copyts | 2 +- tests/ref/fate/ogg-flac-serial-default | 12 +++---- tests/ref/lavf-fate/vp3.ogg | 2 +- tests/ref/lavf-fate/vp8.ogg | 2 +- tests/ref/lavf/ogg | 2 +- 8 files changed, 67 insertions(+), 29 deletions(-) diff --git a/doc/muxers.texi b/doc/muxers.texi index 95f7ea33a7..af599893b2 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -3414,9 +3414,21 @@ possible. A value of 1 will effectively use 1 packet-per-page in most situations, giving a small seek granularity at the cost of additional container overhead. @item -serial_offset @var{value} -Serial value from which to set the streams serial number. -Setting it to different and sufficiently large values ensures that the produced -ogg files can be safely chained. +Serial number of the first stream in bitexact mode, the others following +consecutively. +Chained links need distinct serial numbers, which disjoint ranges of values +guarantee. +The default of -1 derives each serial number from the stream's headers +instead. +This makes links with different headers or tags unlikely to share a serial +number, without ruling it out. +Links with identical headers and tags always share one, which separately muxed +outputs avoid with explicit offsets. + +A link the muxer starts itself on new stream metadata keeps the offset of the +link before it. +With an explicit offset it then reuses its serial number. +With the default it does so when its headers and tags are unchanged. @end table diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index 5c7e3da0bc..f75923e4a7 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -88,8 +88,8 @@ typedef struct OGGContext { static int ogg_write_trailer(AVFormatContext *s); static const AVOption options[] = { - { "serial_offset", "serial number offset", - OFFSET(serial_offset), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, PARAM }, + { "serial_offset", "serial number offset, -1 to derive it from the stream headers", + OFFSET(serial_offset), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, PARAM }, { "page_duration", "preferred page duration, in microseconds", OFFSET(pref_duration), AV_OPT_TYPE_INT64, { .i64 = 1000000 }, 0, INT64_MAX, PARAM }, { NULL }, @@ -486,17 +486,43 @@ static void ogg_write_pages(AVFormatContext *s, int flush) ogg->page_list = p; } +/** + * Derive a bitexact serial number from the stream's header packets, which + * makes links muxed apart unlikely to share one, though not certain not to. + */ +static unsigned ogg_bitexact_serial(const OGGStreamContext *oggstream, unsigned seed) +{ + const AVCRC *table = av_crc_get_table(AV_CRC_32_IEEE); + uint32_t crc = seed; + + for (int i = 0; i < 3; i++) + if (oggstream->header_len[i]) + crc = av_crc(table, crc, oggstream->header[i], oggstream->header_len[i]); + + return crc; +} + +static int ogg_serial_in_use(AVFormatContext *s, int nb_streams, unsigned serial_num) +{ + for (int i = 0; i < nb_streams; i++) { + const OGGStreamContext *oggstream = s->streams[i]->priv_data; + if (oggstream->serial_num == serial_num) + return 1; + } + return 0; +} + // This function can be used on an initialized context to reinitialize the // streams. static int ogg_init(AVFormatContext *s) { OGGContext *ogg = s->priv_data; OGGStreamContext *oggstream = NULL; - int i, j; + int i; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - unsigned serial_num = i + ogg->serial_offset; + unsigned serial_num; if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) @@ -535,17 +561,6 @@ static int ogg_init(AVFormatContext *s) oggstream->page.stream_index = i; - if (!(s->flags & AVFMT_FLAG_BITEXACT)) - do { - serial_num = av_get_random_seed(); - for (j = 0; j < i; j++) { - OGGStreamContext *sc = s->streams[j]->priv_data; - if (serial_num == sc->serial_num) - break; - } - } while (j < i); - oggstream->serial_num = serial_num; - av_dict_copy(&st->metadata, s->metadata, AV_DICT_DONT_OVERWRITE); if (st->codecpar->codec_id == AV_CODEC_ID_FLAC) { @@ -620,6 +635,17 @@ static int ogg_init(AVFormatContext *s) oggstream->kfgshift, oggstream->vrev); } } + + if (s->flags & AVFMT_FLAG_BITEXACT && ogg->serial_offset >= 0) + serial_num = i + ogg->serial_offset; + else if (s->flags & AVFMT_FLAG_BITEXACT) + serial_num = ogg_bitexact_serial(oggstream, i); + else + serial_num = av_get_random_seed(); + while (ogg_serial_in_use(s, i, serial_num)) + serial_num = s->flags & AVFMT_FLAG_BITEXACT ? serial_num + 1 + : av_get_random_seed(); + oggstream->serial_num = serial_num; } return 0; diff --git a/tests/ref/fate/limited_input_seek b/tests/ref/fate/limited_input_seek index 7a5715cf17..95f50a107f 100644 --- a/tests/ref/fate/limited_input_seek +++ b/tests/ref/fate/limited_input_seek @@ -1 +1 @@ -4498ed5370e5a15904bad5d5a716d0b9 +e1068afb583b5f21a6faff94b458fd8f diff --git a/tests/ref/fate/limited_input_seek-copyts b/tests/ref/fate/limited_input_seek-copyts index 527a1fb0ad..f9b47b070e 100644 --- a/tests/ref/fate/limited_input_seek-copyts +++ b/tests/ref/fate/limited_input_seek-copyts @@ -1 +1 @@ -7a0febe8623a2838ac5878f58159c74f +63e0dd3f351d2fb43f0cdfd12e517496 diff --git a/tests/ref/fate/ogg-flac-serial-default b/tests/ref/fate/ogg-flac-serial-default index a578948769..d2bfab60a2 100644 --- a/tests/ref/fate/ogg-flac-serial-default +++ b/tests/ref/fate/ogg-flac-serial-default @@ -1,6 +1,6 @@ -pos=0 serial=0 sequence=0 granule=0 flags=-b- segments=1 size=51 -pos=79 serial=0 sequence=1 granule=0 flags=--- segments=1 size=70 -pos=177 serial=0 sequence=2 granule=8820 flags=--e segments=10 size=2418 -pos=2632 serial=0 sequence=0 granule=0 flags=-b- segments=1 size=51 -pos=2711 serial=0 sequence=1 granule=0 flags=--- segments=1 size=71 -pos=2810 serial=0 sequence=2 granule=17640 flags=--e segments=10 size=2418 +pos=0 serial=1798652137 sequence=0 granule=0 flags=-b- segments=1 size=51 +pos=79 serial=1798652137 sequence=1 granule=0 flags=--- segments=1 size=70 +pos=177 serial=1798652137 sequence=2 granule=8820 flags=--e segments=10 size=2418 +pos=2632 serial=670444992 sequence=0 granule=0 flags=-b- segments=1 size=51 +pos=2711 serial=670444992 sequence=1 granule=0 flags=--- segments=1 size=71 +pos=2810 serial=670444992 sequence=2 granule=17640 flags=--e segments=10 size=2418 diff --git a/tests/ref/lavf-fate/vp3.ogg b/tests/ref/lavf-fate/vp3.ogg index f4e22dc16b..28491cec4e 100644 --- a/tests/ref/lavf-fate/vp3.ogg +++ b/tests/ref/lavf-fate/vp3.ogg @@ -1,3 +1,3 @@ -4bd51dac3194fa88ae33767c25b4b1e6 *tests/data/lavf-fate/lavf.vp3.ogg +f89ded5881b4b002905594c3ff90f8ec *tests/data/lavf-fate/lavf.vp3.ogg 417621 tests/data/lavf-fate/lavf.vp3.ogg tests/data/lavf-fate/lavf.vp3.ogg CRC=0x037e3e79 diff --git a/tests/ref/lavf-fate/vp8.ogg b/tests/ref/lavf-fate/vp8.ogg index dd4ed162f9..8a5ef0909a 100644 --- a/tests/ref/lavf-fate/vp8.ogg +++ b/tests/ref/lavf-fate/vp8.ogg @@ -1,3 +1,3 @@ -20f1e9b1714513a0ba85ca636e818784 *tests/data/lavf-fate/lavf.vp8.ogg +c396feea7c83ccc361b94af00967da2a *tests/data/lavf-fate/lavf.vp8.ogg 95009 tests/data/lavf-fate/lavf.vp8.ogg tests/data/lavf-fate/lavf.vp8.ogg CRC=0xfb8d7a66 diff --git a/tests/ref/lavf/ogg b/tests/ref/lavf/ogg index 3ac10e6f7c..0e7fa29933 100644 --- a/tests/ref/lavf/ogg +++ b/tests/ref/lavf/ogg @@ -1,3 +1,3 @@ -81b9366cacb23644c2803585dced9996 *tests/data/lavf/lavf.ogg +f3e4bad31e324f91ffe525106dd53148 *tests/data/lavf/lavf.ogg 13516 tests/data/lavf/lavf.ogg tests/data/lavf/lavf.ogg CRC=0x3a1da17e -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
