Commit 2e0d40de6f for ffmpeg
commit 2e0d40de6f4b71b97825cb75e30a102c5b9f8eba
Author: Wesley Maa <wesley.maa@gmail.com>
Date: Sun Nov 8 14:03:50 2026 -0500
avcodec/audiotoolboxenc: fix pts of the trailing packet
On flush, AudioToolbox can return one more packet after all input
samples have been consumed. It was taken from an empty frame queue and
got a stale pts past the end of the stream, which made the mov muxer
write an edit list longer than the input (241152 instead of 240000
samples for 5 s of HE-AAC at 48 kHz).
Give that packet the end pts and mark it as fully discarded. The packet
is kept, since Apple's decoder needs it to output the last samples of
HE-AAC at some sample rates.
Signed-off-by: Wesley Maa <wesley.maa@gmail.com>
diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c
index a006d5faa2..1e5fb08629 100644
--- a/libavcodec/audiotoolboxenc.c
+++ b/libavcodec/audiotoolboxenc.c
@@ -51,6 +51,7 @@ typedef struct ATDecodeContext {
unsigned pkt_size;
AudioFrameQueue afq;
int eof;
+ int64_t end_pts;
int frame_size;
AVFrame* encoding_frame;
@@ -575,13 +576,24 @@ static int ffat_encode(AVCodecContext *avctx, AVPacket *avpkt,
if ((!ret || ret == 1) && *got_packet_ptr) {
avpkt->size = out_buffers.mBuffers[0].mDataByteSize;
+ avpkt->flags |= AV_PKT_FLAG_KEY;
+ if (at->eof && !at->afq.remaining_samples) {
+ uint8_t *sd = av_packet_new_side_data(avpkt,
+ AV_PKT_DATA_SKIP_SAMPLES, 10);
+ if (!sd)
+ return AVERROR(ENOMEM);
+ AV_WL32(sd + 4, avctx->frame_size);
+ avpkt->pts = at->end_pts;
+ return 0;
+ }
ret = ff_af_queue_remove(&at->afq, out_pkt_desc.mVariableFramesInPacket ?
out_pkt_desc.mVariableFramesInPacket :
avctx->frame_size,
avpkt);
if (ret < 0)
return ret;
- avpkt->flags |= AV_PKT_FLAG_KEY;
+ at->end_pts = avpkt->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE :
+ avpkt->pts + avpkt->duration;
} else if (ret && ret != 1) {
av_log(avctx, AV_LOG_ERROR, "Encode error: %i\n", ret);
return AVERROR_EXTERNAL;