Commit ff11cdbcac for ffmpeg
commit ff11cdbcac6fbe8b61937beee334e65c3db2c9b2
Author: Jun Zhao <barryjzhao@tencent.com>
Date: Tue Nov 10 09:02:06 2026 +0800
fftools/sync_queue: fix -shortest with frames smaller than the encoder frame size
When an audio encoder requires fixed-size output frames (the native AAC
encoder uses 1024 samples) but the frames reaching the sync queue are
smaller, receive_for_stream() releases frame_samples-sized chunks and
compares the chunk end against the queue head:
ts = frame_end(sq, peek, nb_samples);
overflow_heartbeat() instead used the first queued frame's own end:
tail_ts = frame_end(sq, frame, 0);
The heartbeat therefore lifted the lagging streams to a timestamp a little
short of the chunk end, so the chunk was never released. The audio FIFO then
grew without bound until av_fifo_write() hit the 1 MiB auto-grow limit and
returned AVERROR(ENOSPC), reported as "No space left on device" although no
disk is involved. -shortest is required, and the audio must run ahead of the
video by more than -shortest_buf_duration.
Keep the existing end calculation while a queued frame has at least
frame_samples samples; shorter queued frames, including remainders of larger
input frames, use the output chunk end. Packet streams (sq_frame_samples()
only applies to SYNC_QUEUE_FRAMES) and streams without a fixed frame size
keep frame_end(..., 0).
The mismatch was introduced by f9d3c06533 (2023-03-23), which added
frame_end(..., nb_samples) for receive but used frame_end(..., 0) in the
heartbeat. The stalled queue then grows until av_fifo_write() hits the
1 MiB auto-grow limit in libavutil/fifo.c and returns ENOSPC.
Fixes: https://code.ffmpeg.org/FFmpeg/FFmpeg/issues/25878
Signed-off-by: Jun Zhao <barryjzhao@tencent.com>
diff --git a/fftools/sync_queue.c b/fftools/sync_queue.c
index fbf288c6d1..62e9e093aa 100644
--- a/fftools/sync_queue.c
+++ b/fftools/sync_queue.c
@@ -298,8 +298,18 @@ static int overflow_heartbeat(SyncQueue *sq, int stream_idx)
/* get the chosen stream's tail timestamp */
for (size_t i = 0; tail_ts == AV_NOPTS_VALUE &&
- av_container_fifo_peek(st->fifo, (void**)&frame, i) >= 0; i++)
- tail_ts = frame_end(sq, frame, 0);
+ av_container_fifo_peek(st->fifo, (void**)&frame, i) >= 0; i++) {
+ int nb_samples = 0;
+
+ /* Use the chunk end from receive_for_stream() only when the queued
+ * frame is shorter than the encoder frame size; otherwise keep the
+ * frame's own end timestamp. */
+ if (sq->type == SYNC_QUEUE_FRAMES &&
+ frame.f->nb_samples < st->frame_samples)
+ nb_samples = st->frame_samples;
+
+ tail_ts = frame_end(sq, frame, nb_samples);
+ }
/* overflow triggers when the tail is over specified duration behind the head */
if (tail_ts == AV_NOPTS_VALUE || tail_ts >= st->head_ts ||