[FFmpeg-devel] [PATCH] Don't reset last{pts,dts} on new sequentialized ogg streams. (PR #20637)

2025-10-18 Thread toots via ffmpeg-devel
PR #20637 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20637
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20637.patch

This fixes PTS/DTS discontinuity on sequentialized ogg streams.



>From 98c89233807a1efae0ebaa1cb9ae4ff6c09b8969 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Mon, 4 Aug 2025 09:00:28 -0500
Subject: [PATCH 1/6] ogg/vorbis: implement header packet skip in chained ogg
 bitstreams.

---
 doc/APIchanges |  4 +
 libavformat/oggparsevorbis.c   | 85 +-
 tests/ref/fate/ogg-vorbis-chained-meta.txt |  3 -
 3 files changed, 85 insertions(+), 7 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 9d629f766f..6e7f5d2037 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,10 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-08-xx - xx - lavf 62.6.100 - oggparsevorbis.h oggparseopus.h 
oggparseflac.h
+  Drop header packets from secondary chained ogg/{flac, opus, vorbis} streams
+  from demuxer output.
+
 2025-09-xx - xx - lavu 60.13.100 - hwcontext_d3d12va.h
   Add resource_flags and heap_flags to AVD3D12VADeviceContext
   Add heap_flags to AVD3D12VAFramesContext
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index 62cc2da6de..1af2f21a82 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -215,6 +215,12 @@ struct oggvorbis_private {
 AVVorbisParseContext *vp;
 int64_t final_pts;
 int final_duration;
+uint8_t *header;
+int header_size;
+uint8_t *comment;
+int comment_size;
+uint8_t *setup;
+int setup_size;
 };
 
 static int fixup_vorbis_headers(AVFormatContext *as,
@@ -260,6 +266,10 @@ static void vorbis_cleanup(AVFormatContext *s, int idx)
 av_vorbis_parse_free(&priv->vp);
 for (i = 0; i < 3; i++)
 av_freep(&priv->packet[i]);
+
+av_freep(&priv->header);
+av_freep(&priv->comment);
+av_freep(&priv->setup);
 }
 }
 
@@ -434,6 +444,9 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 struct ogg_stream *os = ogg->streams + idx;
 struct oggvorbis_private *priv = os->private;
 int duration, flags = 0;
+int skip_packet = 0;
+int ret, new_extradata_size;
+PutByteContext pb;
 
 if (!priv->vp)
 return AVERROR_INVALIDDATA;
@@ -496,10 +509,50 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 if (duration < 0) {
 os->pflags |= AV_PKT_FLAG_CORRUPT;
 return 0;
-} else if (flags & VORBIS_FLAG_COMMENT) {
-vorbis_update_metadata(s, idx);
-flags = 0;
 }
+
+if (flags & VORBIS_FLAG_HEADER) {
+ret = vorbis_parse_header(s, s->streams[idx], os->buf + 
os->pstart, os->psize);
+if (ret < 0)
+return ret;
+
+ret = av_reallocp(&priv->header, os->psize);
+if (ret < 0)
+return ret;
+
+memcpy(priv->header, os->buf + os->pstart, os->psize);
+priv->header_size = os->psize;
+
+skip_packet = 1;
+}
+
+if (flags & VORBIS_FLAG_COMMENT) {
+ret = vorbis_update_metadata(s, idx);
+if (ret < 0)
+return ret;
+
+ret = av_reallocp(&priv->comment, os->psize);
+if (ret < 0)
+return ret;
+
+memcpy(priv->comment, os->buf + os->pstart, os->psize);
+priv->comment_size = os->psize;
+
+flags = 0;
+skip_packet = 1;
+}
+
+if (flags & VORBIS_FLAG_SETUP) {
+ret = av_reallocp(&priv->setup, os->psize);
+if (ret < 0)
+return ret;
+
+memcpy(priv->setup, os->buf + os->pstart, os->psize);
+priv->setup_size = os->psize;
+
+skip_packet = 1;
+}
+
 os->pduration = duration;
 }
 
@@ -521,7 +574,31 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 priv->final_duration += os->pduration;
 }
 
-return 0;
+if (priv->header && priv->comment && priv->setup) {
+new_extradata_size = priv->header_size + priv->comment_size + 
priv->setup_size + 6;
+
+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);
+
+av_freep(&priv->header);
+priv->header_siz

[FFmpeg-devel] [PATCH] libavformat/oggparseopus.c: Parse comments from secondary chained streams header packet. (PR #20327)

2025-08-24 Thread toots via ffmpeg-devel
PR #20327 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20327
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20327.patch


>From 67dae45b13b6cc5468178b81faa0124b62c100d5 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Mon, 4 Aug 2025 09:00:28 -0500
Subject: [PATCH 1/5] ogg/vorbis: implement header packet skip in chained ogg
 bitstreams.

---
 doc/APIchanges |  4 +
 libavformat/oggparsevorbis.c   | 85 +-
 tests/ref/fate/ogg-vorbis-chained-meta.txt |  3 -
 3 files changed, 85 insertions(+), 7 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 5d4fb8d127..a8bc75a571 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,10 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-08-xx - xx - lavf 62.4.100 - oggparsevorbis.h oggparseopus.h 
oggparseflac.h
+  Drop header packets from secondary chained ogg/{flac, opus, vorbis} streams
+  from demuxer output.
+
 2025-08-xx -  - lavc 62.13.101 - exif.h
   Add AV_EXIF_FLAG_RECURSIVE
 
diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c
index 62cc2da6de..1af2f21a82 100644
--- a/libavformat/oggparsevorbis.c
+++ b/libavformat/oggparsevorbis.c
@@ -215,6 +215,12 @@ struct oggvorbis_private {
 AVVorbisParseContext *vp;
 int64_t final_pts;
 int final_duration;
+uint8_t *header;
+int header_size;
+uint8_t *comment;
+int comment_size;
+uint8_t *setup;
+int setup_size;
 };
 
 static int fixup_vorbis_headers(AVFormatContext *as,
@@ -260,6 +266,10 @@ static void vorbis_cleanup(AVFormatContext *s, int idx)
 av_vorbis_parse_free(&priv->vp);
 for (i = 0; i < 3; i++)
 av_freep(&priv->packet[i]);
+
+av_freep(&priv->header);
+av_freep(&priv->comment);
+av_freep(&priv->setup);
 }
 }
 
@@ -434,6 +444,9 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 struct ogg_stream *os = ogg->streams + idx;
 struct oggvorbis_private *priv = os->private;
 int duration, flags = 0;
+int skip_packet = 0;
+int ret, new_extradata_size;
+PutByteContext pb;
 
 if (!priv->vp)
 return AVERROR_INVALIDDATA;
@@ -496,10 +509,50 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 if (duration < 0) {
 os->pflags |= AV_PKT_FLAG_CORRUPT;
 return 0;
-} else if (flags & VORBIS_FLAG_COMMENT) {
-vorbis_update_metadata(s, idx);
-flags = 0;
 }
+
+if (flags & VORBIS_FLAG_HEADER) {
+ret = vorbis_parse_header(s, s->streams[idx], os->buf + 
os->pstart, os->psize);
+if (ret < 0)
+return ret;
+
+ret = av_reallocp(&priv->header, os->psize);
+if (ret < 0)
+return ret;
+
+memcpy(priv->header, os->buf + os->pstart, os->psize);
+priv->header_size = os->psize;
+
+skip_packet = 1;
+}
+
+if (flags & VORBIS_FLAG_COMMENT) {
+ret = vorbis_update_metadata(s, idx);
+if (ret < 0)
+return ret;
+
+ret = av_reallocp(&priv->comment, os->psize);
+if (ret < 0)
+return ret;
+
+memcpy(priv->comment, os->buf + os->pstart, os->psize);
+priv->comment_size = os->psize;
+
+flags = 0;
+skip_packet = 1;
+}
+
+if (flags & VORBIS_FLAG_SETUP) {
+ret = av_reallocp(&priv->setup, os->psize);
+if (ret < 0)
+return ret;
+
+memcpy(priv->setup, os->buf + os->pstart, os->psize);
+priv->setup_size = os->psize;
+
+skip_packet = 1;
+}
+
 os->pduration = duration;
 }
 
@@ -521,7 +574,31 @@ static int vorbis_packet(AVFormatContext *s, int idx)
 priv->final_duration += os->pduration;
 }
 
-return 0;
+if (priv->header && priv->comment && priv->setup) {
+new_extradata_size = priv->header_size + priv->comment_size + 
priv->setup_size + 6;
+
+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);
+
+av_freep(&priv->header);
+priv->header_size = 0;
+av_freep(&priv->comment);
+priv->comment_size = 0;
+av_freep(&priv->setup);
+priv->setup_size = 0;
+}
+
+ret

[FFmpeg-devel] [PATCH] Cleanup packet-level BOS/EOS logic. (PR #20640)

2025-10-01 Thread toots via ffmpeg-devel
PR #20640 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20640
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20640.patch


>From 3a9233d70c02a336a59d85bae753eadc09d86a53 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Wed, 1 Oct 2025 18:01:13 -0500
Subject: [PATCH] Cleanup packet-level BOS/EOS logic.

---
 libavformat/oggdec.c   |  6 ++--
 libavformat/oggdec.h   |  4 +--
 libavformat/oggparsecelt.c |  2 +-
 libavformat/oggparsedirac.c|  4 +--
 libavformat/oggparseflac.c |  6 ++--
 libavformat/oggparseogm.c  |  6 ++--
 libavformat/oggparseopus.c | 36 +++--
 libavformat/oggparseskeleton.c |  4 +--
 libavformat/oggparsespeex.c|  6 ++--
 libavformat/oggparsetheora.c   |  6 ++--
 libavformat/oggparsevorbis.c   | 58 ++
 libavformat/oggparsevp8.c  |  6 ++--
 12 files changed, 33 insertions(+), 111 deletions(-)

diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c
index 9f3a92a5ea..2bd2ec1b65 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -567,7 +567,8 @@ static int ogg_packet(AVFormatContext *s, int *sid, int 
*dstart, int *dsize,
 os->incomplete = 0;
 
 if (os->header) {
-if ((ret = os->codec->header(s, idx)) < 0) {
+int is_first = os->flags & OGG_FLAG_BOS && !os->nb_header;
+if ((ret = os->codec->header(s, idx, is_first)) < 0) {
 av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", 
av_err2str(ret));
 return ret;
 }
@@ -605,7 +606,8 @@ static int ogg_packet(AVFormatContext *s, int *sid, int 
*dstart, int *dsize,
 
 ret = 0;
 if (os->codec && os->codec->packet) {
-if ((ret = os->codec->packet(s, idx)) < 0) {
+int is_last_packet = os->flags & OGG_FLAG_EOS && os->page_end;
+if ((ret = os->codec->packet(s, idx, is_last_packet)) < 0) {
 av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", 
av_err2str(ret));
 return ret;
 }
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index b051b651e3..76d1c0f0eb 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -37,7 +37,7 @@ struct ogg_codec {
  * 0 if the packet was not a header (was a data packet)
  * -1 if an error occurred or for unsupported stream
  */
-int (*header)(AVFormatContext *, int);
+int (*header)(AVFormatContext *, int, int);
 /**
  * Attempt to process a packet as a data packet
  * @return < 0 (AVERROR) code or -1 on error
@@ -45,7 +45,7 @@ struct ogg_codec {
  * == 1 if the packet was a header from a chained bitstream.
  *This will cause the packet to be skipped in calling code 
(ogg_packet()
  */
-int (*packet)(AVFormatContext *, int);
+int (*packet)(AVFormatContext *, int, int);
 /**
  * Translate a granule into a timestamp.
  * Will set dts if non-null and known.
diff --git a/libavformat/oggparsecelt.c b/libavformat/oggparsecelt.c
index 626e1ab27d..683e075bf7 100644
--- a/libavformat/oggparsecelt.c
+++ b/libavformat/oggparsecelt.c
@@ -31,7 +31,7 @@ struct oggcelt_private {
 int extra_headers_left;
 };
 
-static int celt_header(AVFormatContext *s, int idx)
+static int celt_header(AVFormatContext *s, int idx, int is_first)
 {
 struct ogg *ogg = s->priv_data;
 struct ogg_stream *os = ogg->streams + idx;
diff --git a/libavformat/oggparsedirac.c b/libavformat/oggparsedirac.c
index c5bd43a757..62ded6e592 100644
--- a/libavformat/oggparsedirac.c
+++ b/libavformat/oggparsedirac.c
@@ -26,7 +26,7 @@
 #include "internal.h"
 #include "oggdec.h"
 
-static int dirac_header(AVFormatContext *s, int idx)
+static int dirac_header(AVFormatContext *s, int idx, int is_first)
 {
 struct ogg *ogg = s->priv_data;
 struct ogg_stream *os = ogg->streams + idx;
@@ -84,7 +84,7 @@ static uint64_t dirac_gptopts(AVFormatContext *s, int idx, 
uint64_t granule,
 return pts;
 }
 
-static int old_dirac_header(AVFormatContext *s, int idx)
+static int old_dirac_header(AVFormatContext *s, int idx, int is_first)
 {
 struct ogg *ogg = s->priv_data;
 struct ogg_stream *os = ogg->streams + idx;
diff --git a/libavformat/oggparseflac.c b/libavformat/oggparseflac.c
index e81e4021a1..ec68ebb6b8 100644
--- a/libavformat/oggparseflac.c
+++ b/libavformat/oggparseflac.c
@@ -31,7 +31,7 @@
 #define OGG_FLAC_MAGIC_SIZE sizeof(OGG_FLAC_MAGIC)-1
 
 static int
-flac_header (AVFormatContext * s, int idx)
+flac_header (AVFormatContext * s, int idx, int is_first)
 {
 struct ogg *ogg = s->priv_data;
 struct ogg_stream *os = ogg->streams + idx;
@@ -81,7 +81,7 @@ flac_header (AVFormatContext * s, int idx)
 }
 
 static int
-flac_packet (AVFormatContext * s, int idx)
+flac_packet (AVFormatContext * s, int idx, int is_last)
 {
 struct ogg *ogg = s->priv_data;
 struct ogg_stream *os = ogg->streams + idx;
@@ -109,7 +109,7 @@ flac_packet (AVFormatCon

[FFmpeg-devel] [PATCH] Handle errors in ogg reinit, make sure we free private data before new (PR #20877)

2025-11-09 Thread toots via ffmpeg-devel
PR #20877 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20877
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20877.patch


>From 389a1df1e310c7a76f857137d321d455271d5719 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Sun, 9 Nov 2025 12:49:32 -0600
Subject: [PATCH] Handle errors in ogg reinit, make sure we free private data
 before new init.

---
 libavformat/oggenc.c | 17 ++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index 5cd94b49bc..080af2295f 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -649,16 +649,27 @@ static int ogg_write_packet_internal(AVFormatContext *s, 
AVPacket *pkt)
 
 side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, 
&size);
 if (side_metadata && oggstream->packet_written) {
-ogg_write_trailer(s);
+ret = ogg_write_trailer(s);
+if (ret < 0)
+return ret;
+
 ogg_deinit(s);
+av_freep(&st->priv_data);
 
 av_dict_free(&st->metadata);
 ret = av_packet_unpack_dictionary(side_metadata, size, &st->metadata);
 if (ret < 0)
 return ret;
 
-ogg_init(s);
-ogg_write_header(s);
+ret = ogg_init(s);
+if (ret < 0)
+return ret;
+
+oggstream = st->priv_data;
+
+ret = ogg_write_header(s);
+if (ret < 0)
+return ret;
 }
 
 oggstream->packet_written = 1;
-- 
2.49.1

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


[FFmpeg-devel] [PATCH] Re-initialize stream on new metadata. (PR #20876)

2025-11-09 Thread toots via ffmpeg-devel
PR #20876 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20876
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20876.patch


>From e4ae6472ff667d22826a2fb0f48e9bd8e9daa3c2 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Fri, 14 Mar 2025 00:27:04 -0500
Subject: [PATCH] Re-initialize stream on new metadata.

---
 libavformat/oggenc.c  | 38 --
 tests/fate/ogg-flac.mak   |  4 
 tests/fate/ogg-opus.mak   |  4 
 tests/fate/ogg-vorbis.mak |  4 
 4 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index e1bb7dd972..26d9b06c6b 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -40,6 +40,9 @@
 
 #define MAX_PAGE_SIZE 65025
 
+static int ogg_write_trailer(AVFormatContext *s);
+static void ogg_deinit(AVFormatContext *s);
+
 typedef struct OGGPage {
 int64_t start_granule;
 int64_t granule;
@@ -66,6 +69,7 @@ typedef struct OGGStreamContext {
 OGGPage page; ///< current page
 unsigned serial_num; ///< serial number
 int64_t last_granule; ///< last packet granule
+int packet_written;
 } OGGStreamContext;
 
 typedef struct OGGPageList {
@@ -640,6 +644,28 @@ static int ogg_write_packet_internal(AVFormatContext *s, 
AVPacket *pkt)
 OGGStreamContext *oggstream = st->priv_data;
 int ret;
 int64_t granule;
+const uint8_t *side_metadata;
+size_t size;
+
+side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, 
&size);
+if (side_metadata && oggstream->packet_written) {
+if (1 < s->nb_streams) {
+av_log(s, AV_LOG_WARNING, "Multiple streams present: cannot insert 
new metadata!\n");
+} else {
+ogg_write_trailer(s);
+ogg_deinit(s);
+ogg_init(s);
+
+av_dict_free(&st->metadata);
+ret = av_packet_unpack_dictionary(side_metadata, size, 
&st->metadata);
+if (ret < 0)
+return ret;
+
+ogg_write_header(s);
+}
+}
+
+oggstream->packet_written = 1;
 
 if (st->codecpar->codec_id == AV_CODEC_ID_THEORA) {
 int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + 
pkt->duration;
@@ -720,7 +746,7 @@ static int ogg_write_trailer(AVFormatContext *s)
 return 0;
 }
 
-static void ogg_free(AVFormatContext *s)
+static void ogg_deinit(AVFormatContext *s)
 {
 OGGContext *ogg = s->priv_data;
 OGGPageList *p = ogg->page_list;
@@ -772,7 +798,7 @@ const FFOutputFormat ff_ogg_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -791,7 +817,7 @@ const FFOutputFormat ff_oga_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -813,7 +839,7 @@ const FFOutputFormat ff_ogv_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -832,7 +858,7 @@ const FFOutputFormat ff_spx_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -851,7 +877,7 @@ const FFOutputFormat ff_opus_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
diff --git a/tests/fate/ogg-flac.mak b/tests/fate/ogg-flac.mak
index 07bdb232cb..083e99e852 100644
--- a/tests/fate/ogg-flac.mak
+++ b/tests/fate/ogg-flac.mak
@@ -2,6 +2,10 @@ FATE_OGG_FLAC += fate-ogg-flac-chained-meta
 fate-ogg-flac-chained-meta: REF = 
$(SRC_PATH)/tests/ref/fate/ogg-flac-chained-meta.txt
 fate-ogg-flac-chained-meta: CMD = run 
$(APITESTSDIR)/api-dump-stream-meta-test$(EXESUF) 
$(TARGET_SAMPLES)/ogg-f

[FFmpeg-devel] [PATCH] Re-initialize stream on new metadata. (PR #20890)

2025-11-10 Thread toots via ffmpeg-devel
PR #20890 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20890
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20890.patch


>From 7993a24cf4062fc4ed943ec5f3e66b0bbb325741 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Fri, 14 Mar 2025 00:27:04 -0500
Subject: [PATCH] Re-initialize stream on new metadata.

---
 libavformat/oggenc.c  | 62 ++-
 tests/fate-run.sh |  9 ++
 tests/fate/ogg-flac.mak   |  5 
 tests/fate/ogg-opus.mak   |  5 
 tests/fate/ogg-vorbis.mak |  5 
 5 files changed, 79 insertions(+), 7 deletions(-)

diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c
index e1bb7dd972..943fc71c12 100644
--- a/libavformat/oggenc.c
+++ b/libavformat/oggenc.c
@@ -40,6 +40,9 @@
 
 #define MAX_PAGE_SIZE 65025
 
+static int ogg_write_trailer(AVFormatContext *s);
+static void ogg_deinit(AVFormatContext *s);
+
 typedef struct OGGPage {
 int64_t start_granule;
 int64_t granule;
@@ -634,13 +637,57 @@ static int ogg_write_header(AVFormatContext *s)
 return 0;
 }
 
+static int ogg_check_new_metadata(AVFormatContext *s, AVPacket *pkt)
+{
+int ret = 0;
+size_t size;
+AVStream *st = s->streams[pkt->stream_index];
+const uint8_t *side_metadata = av_packet_get_side_data(pkt, 
AV_PKT_DATA_STRINGS_METADATA, &size);
+
+if (!side_metadata)
+return 0;
+
+if (s->nb_streams > 1) {
+av_log(s, AV_LOG_WARNING, "Multiple streams present: cannot insert new 
metadata!\n");
+return 0;
+}
+
+if (st->codecpar->codec_id != AV_CODEC_ID_VORBIS &&
+st->codecpar->codec_id != AV_CODEC_ID_FLAC &&
+st->codecpar->codec_id != AV_CODEC_ID_OPUS) {
+av_log(s, AV_LOG_WARNING, "Inserting in-base metadata is only 
supported for vorbis, flac and opus streams!\n");
+return 0;
+}
+
+ret = ogg_write_trailer(s);
+if (ret < 0)
+return ret;
+
+ogg_deinit(s);
+
+av_dict_free(&st->metadata);
+ret = av_packet_unpack_dictionary(side_metadata, size, &st->metadata);
+if (ret < 0)
+return ret;
+
+ret = ogg_init(s);
+if (ret < 0)
+return ret;
+
+return ogg_write_header(s);
+}
+
 static int ogg_write_packet_internal(AVFormatContext *s, AVPacket *pkt)
 {
 AVStream *st = s->streams[pkt->stream_index];
-OGGStreamContext *oggstream = st->priv_data;
+OGGStreamContext *oggstream;
 int ret;
 int64_t granule;
 
+ogg_check_new_metadata(s, pkt);
+
+oggstream = st->priv_data;
+
 if (st->codecpar->codec_id == AV_CODEC_ID_THEORA) {
 int64_t pts = oggstream->vrev < 1 ? pkt->pts : pkt->pts + 
pkt->duration;
 int pframe_count;
@@ -720,7 +767,7 @@ static int ogg_write_trailer(AVFormatContext *s)
 return 0;
 }
 
-static void ogg_free(AVFormatContext *s)
+static void ogg_deinit(AVFormatContext *s)
 {
 OGGContext *ogg = s->priv_data;
 OGGPageList *p = ogg->page_list;
@@ -738,6 +785,7 @@ static void ogg_free(AVFormatContext *s)
 av_freep(&oggstream->header[0]);
 }
 av_freep(&oggstream->header[1]);
+av_freep(&st->priv_data);
 }
 
 while (p) {
@@ -772,7 +820,7 @@ const FFOutputFormat ff_ogg_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -791,7 +839,7 @@ const FFOutputFormat ff_oga_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -813,7 +861,7 @@ const FFOutputFormat ff_ogv_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE | AVFMT_TS_NONSTRICT,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -832,7 +880,7 @@ const FFOutputFormat ff_spx_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_trailer = ogg_write_trailer,
-.deinit= ogg_free,
+.deinit= ogg_deinit,
 .p.flags   = AVFMT_TS_NEGATIVE,
 .p.priv_class  = &ogg_muxer_class,
 .flags_internal= FF_OFMT_FLAG_ALLOW_FLUSH,
@@ -851,7 +899,7 @@ const FFOutputFormat ff_opus_muxer = {
 .write_header  = ogg_write_header,
 .write_packet  = ogg_write_packet,
 .write_

[FFmpeg-devel] [PATCH] ffplay: print new metadata (PR #20867)

2025-11-08 Thread toots via ffmpeg-devel
PR #20867 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20867
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20867.patch


>From f3a114f7dea9f31888dc9deb39bbe5ee5e808c0c Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Sat, 8 Nov 2025 10:19:30 -0600
Subject: [PATCH 1/3] libavformat: export av_dump_dictionary

---
 doc/APIchanges |  3 +++
 libavformat/avformat.h | 14 ++
 libavformat/dump.c | 12 ++--
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 9d128ae77b..42bc3dba35 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-11-08 - xx - lavf 62.6.101 - avformat.h
+  Added av_dump_dictionary().
+
 2025-11-01 - xx - lavc 62.19.100 - avcodec.h
   Schedule AVCodecParser and av_parser_init() to use enum AVCodecID
   for codec ids on the next major version bump.
diff --git a/libavformat/avformat.h b/libavformat/avformat.h
index a7446546e5..a6cf9b0dfa 100644
--- a/libavformat/avformat.h
+++ b/libavformat/avformat.h
@@ -2818,6 +2818,20 @@ void av_dump_format(AVFormatContext *ic,
 const char *url,
 int is_output);
 
+/**
+ * Print the given dictionary.
+ *
+ * @param ctx   the logging context
+ * @param m the dictionay to print
+ * @param name  name of the dictionary
+ * @param indentintendation to use between key and values
+ * @param log_level log level to use for printing
+ */
+void av_dump_dictionary(void *ctx,
+const AVDictionary *m,
+const char *name,
+const char *indent,
+int log_level);
 
 #define AV_FRAME_FILENAME_FLAGS_MULTIPLE  1  ///< Allow multiple %d
 #define AV_FRAME_FILENAME_FLAGS_IGNORE_TRUNCATION 2  ///< Ignore truncated 
output instead of returning an error
diff --git a/libavformat/dump.c b/libavformat/dump.c
index 2948189432..d30732fbef 100644
--- a/libavformat/dump.c
+++ b/libavformat/dump.c
@@ -139,9 +139,9 @@ static void print_fps(double d, const char *postfix, int 
log_level)
 av_log(NULL, log_level, "%1.0fk %s", d / 1000, postfix);
 }
 
-static void dump_dictionary(void *ctx, const AVDictionary *m,
-const char *name, const char *indent,
-int log_level)
+void av_dump_dictionary(void *ctx, const AVDictionary *m,
+const char *name, const char *indent,
+int log_level)
 {
 const AVDictionaryEntry *tag = NULL;
 
@@ -170,7 +170,7 @@ static void dump_metadata(void *ctx, const AVDictionary *m, 
const char *indent,
   int log_level)
 {
 if (m && !(av_dict_count(m) == 1 && av_dict_get(m, "language", NULL, 0)))
-dump_dictionary(ctx, m, "Metadata", indent, log_level);
+av_dump_dictionary(ctx, m, "Metadata", indent, log_level);
 }
 
 /* param change side data*/
@@ -734,7 +734,7 @@ static void dump_stream_group(const AVFormatContext *ic, 
uint8_t *printed,
 dump_disposition(stg->disposition, AV_LOG_INFO);
 av_log(NULL, AV_LOG_INFO, "\n");
 dump_metadata(NULL, stg->metadata, "", AV_LOG_INFO);
-dump_dictionary(NULL, mix_presentation->annotations, "Annotations", "  
  ", AV_LOG_INFO);
+av_dump_dictionary(NULL, mix_presentation->annotations, "Annotations", 
"", AV_LOG_INFO);
 for (int j = 0; j < mix_presentation->nb_submixes; j++) {
 AVIAMFSubmix *sub_mix = mix_presentation->submixes[j];
 av_log(NULL, AV_LOG_INFO, "Submix %d:\n", j);
@@ -753,7 +753,7 @@ static void dump_stream_group(const AVFormatContext *ic, 
uint8_t *printed,
 if (flags & AVFMT_SHOW_IDS)
 av_log(NULL, AV_LOG_INFO, "[0x%"PRIx64"]", 
audio_element->id);
 av_log(NULL, AV_LOG_INFO, "\n");
-dump_dictionary(NULL, submix_element->annotations, 
"Annotations", "", AV_LOG_INFO);
+av_dump_dictionary(NULL, submix_element->annotations, 
"Annotations", "", AV_LOG_INFO);
 }
 }
 for (int k = 0; k < sub_mix->nb_layouts; k++) {
-- 
2.49.1


>From 020070a61204ab3b227f1f977abbb466b3316859 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Sat, 8 Nov 2025 12:03:32 -0600
Subject: [PATCH 2/3] libavutil: add av_dict_md5_sum.

---
 doc/APIchanges   |  3 +++
 libavutil/dict.c | 22 ++
 libavutil/dict.h | 12 
 3 files changed, 37 insertions(+)

diff --git a/doc/APIchanges b/doc/APIchanges
index 42bc3dba35..7c9c864577 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-11-08 -  xx - lavu 60.17.100 - dict.h
+  A

[FFmpeg-devel] [PATCH] Don't reset last{pts,dts} on new sequentialized ogg streams. (PR #20868)

2025-11-08 Thread toots via ffmpeg-devel
PR #20868 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20868
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20868.patch

This fixes PTS/DTS discontinuity on sequentialized ogg streams.



>From 9656eb8a9a0f10b28b95ca35f98ad165e5e3c41a Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Tue, 30 Sep 2025 20:23:04 -0500
Subject: [PATCH] Don't reset last{pts,dts} on new sequentialized ogg streams.

This fixes PTS/DTS discontinuity on sequentialized ogg streams.
---
 libavformat/oggdec.c   |  7 +++
 libavformat/oggdec.h   |  1 +
 tests/ref/fate/ogg-flac-chained-meta.txt   |  8 
 tests/ref/fate/ogg-opus-chained-meta.txt   | 24 +++---
 tests/ref/fate/ogg-vorbis-chained-meta.txt | 12 +--
 5 files changed, 30 insertions(+), 22 deletions(-)

diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c
index 9f3a92a5ea..18ca3a6f68 100644
--- a/libavformat/oggdec.c
+++ b/libavformat/oggdec.c
@@ -237,8 +237,10 @@ static int ogg_replace_stream(AVFormatContext *s, uint32_t 
serial, char *magic,
 os->serial  = serial;
 os->lastpts = 0;
 os->lastdts = 0;
+os->flags   = 0;
 os->start_trimming = 0;
 os->end_trimming = 0;
+os->replace = 1;
 
 return i;
 }
@@ -879,6 +881,11 @@ retry:
 os->end_trimming = 0;
 }
 
+if (os->replace) {
+os->replace = 0;
+pkt->dts = pkt->pts = AV_NOPTS_VALUE;
+}
+
 if (os->new_metadata) {
 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA,
   os->new_metadata, os->new_metadata_size);
diff --git a/libavformat/oggdec.h b/libavformat/oggdec.h
index b051b651e3..f29912bca8 100644
--- a/libavformat/oggdec.h
+++ b/libavformat/oggdec.h
@@ -92,6 +92,7 @@ struct ogg_stream {
 int nb_header; ///< set to the number of parsed headers
 int start_trimming; ///< set the number of packets to drop from the start
 int end_trimming; ///< set the number of packets to drop from the end
+int replace; // < set to 1 after initializing a new chained stream
 uint8_t *new_metadata;
 size_t new_metadata_size;
 uint8_t *new_extradata;
diff --git a/tests/ref/fate/ogg-flac-chained-meta.txt 
b/tests/ref/fate/ogg-flac-chained-meta.txt
index 5abf37dcee..877b3f3173 100644
--- a/tests/ref/fate/ogg-flac-chained-meta.txt
+++ b/tests/ref/fate/ogg-flac-chained-meta.txt
@@ -4,8 +4,8 @@ Stream ID: 0, new metadata: encoder=Lavc61.19.100 
flac:title=First Stream
 Stream ID: 0, frame PTS: 0, metadata: N/A
 Stream ID: 0, packet PTS: 4608, packet DTS: 4608
 Stream ID: 0, frame PTS: 4608, metadata: N/A
-Stream ID: 0, packet PTS: 0, packet DTS: 0
+Stream ID: 0, packet PTS: 8820, packet DTS: 8820
 Stream ID: 0, new metadata: encoder=Lavc61.19.100 flac:title=Second Stream
-Stream ID: 0, frame PTS: 0, metadata: encoder=Lavc61.19.100 flac:title=Second 
Stream
-Stream ID: 0, packet PTS: 4608, packet DTS: 4608
-Stream ID: 0, frame PTS: 4608, metadata: N/A
+Stream ID: 0, frame PTS: 8820, metadata: encoder=Lavc61.19.100 
flac:title=Second Stream
+Stream ID: 0, packet PTS: 13428, packet DTS: 13428
+Stream ID: 0, frame PTS: 13428, metadata: N/A
diff --git a/tests/ref/fate/ogg-opus-chained-meta.txt 
b/tests/ref/fate/ogg-opus-chained-meta.txt
index aad9b83700..5c2b9d0d44 100644
--- a/tests/ref/fate/ogg-opus-chained-meta.txt
+++ b/tests/ref/fate/ogg-opus-chained-meta.txt
@@ -12,16 +12,16 @@ Stream ID: 0, packet PTS: 3528, packet DTS: 3528
 Stream ID: 0, frame PTS: 3528, metadata: N/A
 Stream ID: 0, packet PTS: 4488, packet DTS: 4488
 Stream ID: 0, frame PTS: 4488, metadata: N/A
-Stream ID: 0, packet PTS: -312, packet DTS: -312
+Stream ID: 0, packet PTS: 4800, packet DTS: 4800
 Stream ID: 0, new metadata: encoder=Lavc61.19.100 libopus:title=Second Stream
-Stream ID: 0, frame PTS: -312, metadata: encoder=Lavc61.19.100 
libopus:title=Second Stream
-Stream ID: 0, packet PTS: 648, packet DTS: 648
-Stream ID: 0, frame PTS: 648, metadata: N/A
-Stream ID: 0, packet PTS: 1608, packet DTS: 1608
-Stream ID: 0, frame PTS: 1608, metadata: N/A
-Stream ID: 0, packet PTS: 2568, packet DTS: 2568
-Stream ID: 0, frame PTS: 2568, metadata: N/A
-Stream ID: 0, packet PTS: 3528, packet DTS: 3528
-Stream ID: 0, frame PTS: 3528, metadata: N/A
-Stream ID: 0, packet PTS: 4488, packet DTS: 4488
-Stream ID: 0, frame PTS: 4488, metadata: N/A
+Stream ID: 0, frame PTS: 4800, metadata: encoder=Lavc61.19.100 
libopus:title=Second Stream
+Stream ID: 0, packet PTS: 5760, packet DTS: 5760
+Stream ID: 0, frame PTS: 5760, metadata: N/A
+Stream ID: 0, packet PTS: 6720, packet DTS: 6720
+Stream ID: 0, frame PTS: 6720, metadata: N/A
+Stream ID: 0, packet PTS: 7680, packet DTS: 7680
+Stream ID: 0, frame PTS: 7680, metadata: N/A
+Stream ID: 0, packet PTS: 8640, packet DTS: 8640
+Stream ID: 0, frame PTS: 8640, metadata: N/A
+Stream ID: 0, packet PTS: 9600, packet DTS: 9600
+Stream ID: 0, frame PTS: 9600, metadata: N/A
diff --git a/tests/ref/fate/ogg-v

[FFmpeg-devel] [PATCH] Add myself as maintainer to the various ogg files. (PR #20961)

2025-11-18 Thread toots via ffmpeg-devel
PR #20961 opened by toots
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20961
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20961.patch


>From ade83020b43d572b4b9f1d1c821fe9f558d31768 Mon Sep 17 00:00:00 2001
From: Romain Beauxis 
Date: Tue, 18 Nov 2025 16:58:59 -0600
Subject: [PATCH] Add myself as maintainer to the various ogg files.

---
 .forgejo/CODEOWNERS | 1 +
 MAINTAINERS | 6 +++---
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/.forgejo/CODEOWNERS b/.forgejo/CODEOWNERS
index 45f501a4c3..1200f0404a 100644
--- a/.forgejo/CODEOWNERS
+++ b/.forgejo/CODEOWNERS
@@ -148,6 +148,7 @@ libavformat/mlv.* @pross
 libavformat/mm.* @pross
 libavformat/msp.* @pross
 libavformat/mv.* @pross
+libavformat/ogg* @toots
 libavformat/pp_bnk.* @zane
 libavformat/rm.* @pross
 libavformat/sauce.* @pross
diff --git a/MAINTAINERS b/MAINTAINERS
index cef58ef0e7..cef8e99fb6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -442,9 +442,9 @@ Muxers/Demuxers:
   nsvdec.c  Francois Revol
   nut*  Michael Niedermayer
   nuv.c Reimar Doeffinger
-  oggdec.c, oggdec.hDavid Conrad
-  oggenc.c  Baptiste Coudurier
-  oggparse*.c   David Conrad
+  oggdec.c, oggdec.hDavid Conrad, Romain Beauxis
+  oggenc.c  Baptiste Coudurier, Romain Beauxis
+  oggparse*.c   David Conrad, Romain Beauxis
   oma.c Maxim Poliakovski
   pp_bnk.c  Zane van Iperen
   psxstr.c  Mike Melanson
-- 
2.49.1

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