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 ||