* [FFmpeg-devel] [PR] avformat/caf: fix setting stream and packet durations (PR #21572)
@ 2026-01-24 17:40 James Almer via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: James Almer via ffmpeg-devel @ 2026-01-24 17:40 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: James Almer
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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
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 <jamrial@gmail.com>
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 <jamrial@gmail.com>
---
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 -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-01-24 17:40 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-24 17:40 [FFmpeg-devel] [PR] avformat/caf: fix setting stream and packet durations (PR #21572) James Almer via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git