From 931b26528ca71cf36fd1b69885ab58b6c7ad9172 Mon Sep 17 00:00:00 2001 From: Nicolas Gaullier Date: Wed, 31 Dec 2025 00:30:38 +0100 Subject: [PATCH] avfilter/src_movie: fix support multiple frames per packet Do not output more than one frame in one activate callback, though. Fixes #20827. Signed-off-by: Nicolas Gaullier --- libavfilter/src_movie.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c index adb21e019e..5d4f6e31e6 100644 --- a/libavfilter/src_movie.c +++ b/libavfilter/src_movie.c @@ -521,24 +521,26 @@ static int decode_packet(AVFilterContext *ctx, int i) AVPacket *pkt = movie->pkt; int ret = 0; - // submit the packet to the decoder - if (!movie->eof) { + // do not output more than 1 frame per iteration, + // so try to receive_frame first + ret = avcodec_receive_frame(dec, frame); + if (!movie->eof && ret == AVERROR(EAGAIN)) { ret = avcodec_send_packet(dec, pkt); + av_packet_unref(pkt); if (ret < 0) return ret; + ret = avcodec_receive_frame(dec, frame); + } + if (ret < 0) { + // those two return values are special and mean there is no output + // frame available, but there were no errors during decoding + if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) + return 0; + return ret; } - // get all the available frames from the decoder + // output a single frame if (ret >= 0) { - ret = avcodec_receive_frame(dec, frame); - if (ret < 0) { - // those two return values are special and mean there is no output - // frame available, but there were no errors during decoding - if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN)) - return 0; - return ret; - } - frame->pts = frame->best_effort_timestamp; if (frame->pts != AV_NOPTS_VALUE) { if (movie->ts_offset) @@ -568,7 +570,7 @@ static int decode_packet(AVFilterContext *ctx, int i) static int activate(AVFilterContext *ctx) { MovieContext *movie = ctx->priv; - int wanted = 0, ret; + int wanted = 0, ret = 0; for (int i = 0; i < ctx->nb_outputs; i++) { if (ff_outlink_frame_wanted(ctx->outputs[i])) @@ -579,7 +581,8 @@ static int activate(AVFilterContext *ctx) return FFERROR_NOT_READY; if (!movie->eof) { - ret = av_read_frame(movie->format_ctx, movie->pkt); + if (!movie->pkt->buf) + ret = av_read_frame(movie->format_ctx, movie->pkt); if (ret < 0) { movie->eof = 1; for (int i = 0; i < ctx->nb_outputs; i++) @@ -592,8 +595,9 @@ static int activate(AVFilterContext *ctx) if (pkt_out_id >= 0) { ret = decode_packet(ctx, pkt_out_id); + } else { + av_packet_unref(movie->pkt); } - av_packet_unref(movie->pkt); ff_filter_set_ready(ctx, 100); return (ret <= 0) ? ret : 0; }