PR #21572 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21572
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21572.patch

Supersedes #21553


>From c6015ed5edf7d7605134d4cb68f30146bdd54fd0 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Sat, 24 Jan 2026 14:02:58 -0300
Subject: [PATCH 1/3] avcodec/opus/enc: set avctx->frame_size to a better guess
 based on encoder configuration

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/opus/enc.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/libavcodec/opus/enc.c b/libavcodec/opus/enc.c
index 8d20b6c192..1bbeb4bf6e 100644
--- a/libavcodec/opus/enc.c
+++ b/libavcodec/opus/enc.c
@@ -638,12 +638,8 @@ static av_cold int opus_encode_init(AVCodecContext *avctx)
     s->avctx = avctx;
     s->channels = avctx->ch_layout.nb_channels;
 
-    /* Opus allows us to change the framesize on each packet (and each packet 
may
-     * have multiple frames in it) but we can't change the codec's frame size 
on
-     * runtime, so fix it to the lowest possible number of samples and use a 
queue
-     * to accumulate AVFrames until we have enough to encode whatever the 
encoder
-     * decides is the best */
-    avctx->frame_size = 120;
+    int max_delay_samples = (s->options.max_delay_ms * s->avctx->sample_rate) 
/ 1000;
+    avctx->frame_size = 
OPUS_BLOCK_SIZE(FFMIN(OPUS_SAMPLES_TO_BLOCK_SIZE(max_delay_samples), 
CELT_BLOCK_960));
     /* Initial padding will change if SILK is ever supported */
     avctx->initial_padding = 120;
 
-- 
2.52.0


>From 9c76f2a017bd5bcfc07bc8d3317d78fa406030da Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Sat, 24 Jan 2026 14:04:31 -0300
Subject: [PATCH 2/3] avformat/cafdec: fix setting stream and packet durations

Take into account priming frames, exported as start time, and remainder frames,
substracted from the stream duration as well as exported as discard padding
side data in the last packet.

Signed-off-by: James Almer <[email protected]>
---
 libavformat/cafdec.c          | 21 +++++++++++++++++++--
 tests/ref/fate/caf-alac-remux |  6 +++---
 tests/ref/fate/caf-qdm2-remux |  6 +++---
 3 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/libavformat/cafdec.c b/libavformat/cafdec.c
index 99ae041364..0a67141773 100644
--- a/libavformat/cafdec.c
+++ b/libavformat/cafdec.c
@@ -50,6 +50,8 @@ typedef struct CafContext {
 
     int64_t data_start;             ///< data start position, in bytes
     int64_t data_size;              ///< raw data size, in bytes
+
+    unsigned remainder;             ///< frames to discard from the last packet
 } CafContext;
 
 static int probe(const AVProbeData *p)
@@ -254,8 +256,8 @@ static int read_pakt_chunk(AVFormatContext *s, int64_t size)
         return AVERROR_INVALIDDATA;
 
     st->nb_frames  = avio_rb64(pb); /* valid frames */
-    st->nb_frames += avio_rb32(pb); /* priming frames */
-    st->nb_frames += avio_rb32(pb); /* remainder frames */
+    st->start_time = -(int64_t)avio_rb32(pb); /* priming frames */
+    caf->remainder = avio_rb32(pb); /* remainder frames */
 
     if (caf->bytes_per_packet > 0 && caf->frames_per_packet > 0) {
         st->duration = caf->frames_per_packet * num_packets;
@@ -272,6 +274,9 @@ static int read_pakt_chunk(AVFormatContext *s, int64_t size)
             st->duration += caf->frames_per_packet ? caf->frames_per_packet : 
ff_mp4_read_descr_len(pb);
         }
     }
+    st->duration -= caf->remainder;
+    if (st->duration < 0)
+        return AVERROR_INVALIDDATA;
 
     if (avio_tell(pb) - ccount > size || size > INT64_MAX - ccount) {
         av_log(s, AV_LOG_ERROR, "error reading packet table\n");
@@ -433,6 +438,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
     FFStream *const sti = ffstream(st);
     CafContext *caf   = s->priv_data;
     int res, pkt_size = 0, pkt_frames = 0;
+    unsigned remainder = 0;
     int64_t left      = CAF_MAX_PKT_SIZE;
 
     if (avio_feof(pb))
@@ -461,6 +467,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
         } else if (caf->packet_cnt == sti->nb_index_entries - 1) {
             pkt_size   = caf->num_bytes - 
sti->index_entries[caf->packet_cnt].pos;
             pkt_frames = st->duration   - 
sti->index_entries[caf->packet_cnt].timestamp;
+            remainder  = caf->remainder;
         } else {
             return AVERROR_INVALIDDATA;
         }
@@ -473,6 +480,16 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt)
     if (res < 0)
         return res;
 
+    if (remainder > 0) {
+        uint8_t* side_data = av_packet_new_side_data(pkt,
+                                                     AV_PKT_DATA_SKIP_SAMPLES,
+                                                     10);
+        if (!side_data)
+            return AVERROR(ENOMEM);
+        AV_WL32(side_data + 4, caf->remainder);
+    }
+
+    pkt->duration       = pkt_frames;
     pkt->size           = res;
     pkt->stream_index   = 0;
     pkt->dts = pkt->pts = caf->frame_cnt;
diff --git a/tests/ref/fate/caf-alac-remux b/tests/ref/fate/caf-alac-remux
index f33182b721..2a1d24092b 100644
--- a/tests/ref/fate/caf-alac-remux
+++ b/tests/ref/fate/caf-alac-remux
@@ -6,9 +6,9 @@
 #codec_id 0: alac
 #sample_rate 0: 44100
 #channel_layout_name 0: stereo
-0,          0,          0,        0,       32, 0xa0af0dfe
-0,       4096,       4096,        0,     6701, 0xa9ddc14e
-0,       8192,       8192,        0,     6639, 0x3ccda8d6
+0,          0,          0,     4096,       32, 0xa0af0dfe
+0,       4096,       4096,     4096,     6701, 0xa9ddc14e
+0,       8192,       8192,     4096,     6639, 0x3ccda8d6
 [FORMAT]
 TAG:track=5/13
 TAG:minor_version=0
diff --git a/tests/ref/fate/caf-qdm2-remux b/tests/ref/fate/caf-qdm2-remux
index d4f658c163..e0e96eaf5e 100644
--- a/tests/ref/fate/caf-qdm2-remux
+++ b/tests/ref/fate/caf-qdm2-remux
@@ -6,6 +6,6 @@
 #codec_id 0: qdm2
 #sample_rate 0: 44100
 #channel_layout_name 0: stereo
-0,          0,          0,        0,      370, 0x4d1897fc
-0,       4096,       4096,        0,      370, 0xea999da0
-0,       8192,       8192,        0,      370, 0xca259462
+0,          0,          0,     4096,      370, 0x4d1897fc
+0,       4096,       4096,     4096,      370, 0xea999da0
+0,       8192,       8192,     4096,      370, 0xca259462
-- 
2.52.0


>From 82a91f1d5cca40bc39d51b7831a1b20b5725c440 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Sat, 24 Jan 2026 14:09:20 -0300
Subject: [PATCH 3/3] avformat/cafenc: fix setting frame count fields in Packet
 Table Description

st->duration is not guaranteed to be set, so store the sum of packet durations 
instead.
Also, set mPrimingFrames and mRemainderFrames to correct values.

Based on a patch by Jun Zhao.

Signed-off-by: James Almer <[email protected]>
---
 libavformat/cafenc.c          | 17 +++++++++++------
 tests/ref/fate/caf-alac-remux |  2 +-
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c
index 89ecb51e53..df9520a91b 100644
--- a/libavformat/cafenc.c
+++ b/libavformat/cafenc.c
@@ -32,9 +32,10 @@
 
 typedef struct {
     int64_t data;
+    int64_t total_duration;
+    int64_t packets;
     int size_buffer_size;
     int size_entries_used;
-    int packets;
 } CAFContext;
 
 static uint32_t codec_flags(enum AVCodecID codec_id) {
@@ -235,6 +236,7 @@ static int caf_write_packet(AVFormatContext *s, AVPacket 
*pkt)
         }
         pkt_sizes[caf->size_entries_used++] = pkt->size & 127;
         caf->packets++;
+        caf->total_duration += pkt->duration;
     }
     avio_write(s->pb, pkt->data, pkt->size);
     return 0;
@@ -253,9 +255,12 @@ static int caf_write_trailer(AVFormatContext *s)
         avio_seek(pb, caf->data, SEEK_SET);
         avio_wb64(pb, file_size - caf->data - 8);
         if (!par->block_align) {
-            int packet_size = samples_per_packet(par);
+            unsigned packet_size = samples_per_packet(par);
+            int64_t valid_frames = packet_size ? caf->packets * packet_size : 
caf->total_duration;
+            unsigned remainder_frames = valid_frames > caf->total_duration
+                                      ? valid_frames - caf->total_duration : 0;
             if (!packet_size) {
-                packet_size = st->duration / (caf->packets - 1);
+                packet_size = caf->total_duration / (caf->packets - 1);
                 avio_seek(pb, FRAME_SIZE_OFFSET, SEEK_SET);
                 avio_wb32(pb, packet_size);
             }
@@ -263,9 +268,9 @@ static int caf_write_trailer(AVFormatContext *s)
             ffio_wfourcc(pb, "pakt");
             avio_wb64(pb, caf->size_entries_used + 24U);
             avio_wb64(pb, caf->packets); ///< mNumberPackets
-            avio_wb64(pb, caf->packets * packet_size); ///< mNumberValidFrames
-            avio_wb32(pb, 0); ///< mPrimingFrames
-            avio_wb32(pb, 0); ///< mRemainderFrames
+            avio_wb64(pb, valid_frames); ///< mNumberValidFrames
+            avio_wb32(pb, par->initial_padding); ///< mPrimingFrames
+            avio_wb32(pb, remainder_frames); ///< mRemainderFrames
             avio_write(pb, st->priv_data, caf->size_entries_used);
         }
     }
diff --git a/tests/ref/fate/caf-alac-remux b/tests/ref/fate/caf-alac-remux
index 2a1d24092b..72ad90998a 100644
--- a/tests/ref/fate/caf-alac-remux
+++ b/tests/ref/fate/caf-alac-remux
@@ -1,4 +1,4 @@
-9ef40186fb3e24789df03f8c08110486 *tests/data/fate/caf-alac-remux.caf
+4d616f58fea0c39ee725a85eab4e67b6 *tests/data/fate/caf-alac-remux.caf
 1292684 tests/data/fate/caf-alac-remux.caf
 #extradata 0:       36, 0x562b05d8
 #tb 0: 1/44100
-- 
2.52.0

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

Reply via email to