Commit 5b2ab843de for ffmpeg
commit 5b2ab843ded396303fbd8552204c22b6c776f8b2
Author: Romain Beauxis <romain.beauxis@gmail.com>
Date: Sun Nov 1 09:01:33 2026 -0600
avcodec/opus/dec: output held-back samples on AV_PKT_FLAG_EOS
The resampler for SILK frames holds back some output samples, which
are only output at the next mode or rate change, or when draining.
Flush them into the frame of a packet flagged AV_PKT_FLAG_EOS, so
that they end the sequence they belong to and its end trimming
applies to them.
diff --git a/libavcodec/opus/dec.c b/libavcodec/opus/dec.c
index 2cc677d667..04cb795402 100644
--- a/libavcodec/opus/dec.c
+++ b/libavcodec/opus/dec.c
@@ -474,6 +474,30 @@ finish:
return output_samples;
}
+/**
+ * Append the samples the resampler holds back to the output of the
+ * sub-packet that just decoded, leaving the stream's output state as it was.
+ */
+static int opus_drain_subpacket(OpusStreamContext *s, int decoded_samples)
+{
+ float *out[2] = { s->out[0], s->out[1] };
+ int out_size = s->out_size;
+ int ret;
+
+ for (int i = 0; i < 2; i++)
+ if (s->out[i])
+ s->out[i] += decoded_samples;
+ s->out_size -= decoded_samples * sizeof(float);
+
+ ret = opus_decode_subpacket(s, NULL);
+
+ s->out[0] = out[0];
+ s->out[1] = out[1];
+ s->out_size = out_size;
+
+ return ret < 0 ? ret : decoded_samples + ret;
+}
+
static av_cold void opus_free_streams(OpusContext *c)
{
for (int i = 0; i < c->p.nb_streams; i++) {
@@ -699,6 +723,8 @@ static int opus_decode_packet(AVCodecContext *avctx, AVFrame *frame,
}
ret = opus_decode_subpacket(&c->streams[i], buf);
+ if (ret >= 0 && buf && (avpkt->flags & AV_PKT_FLAG_EOS))
+ ret = opus_drain_subpacket(s, ret);
if (ret < 0)
return ret;
s->decoded_samples = ret;