[FFmpeg-devel] [PATCH] Don't reset last{pts,dts} on new sequentialized ogg streams. (PR #20637)
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)
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)
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)
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)
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)
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)
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)
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)
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]
