From: Niklas Haas via ffmpeg-devel <ffmpeg-devel@ffmpeg.org> To: ffmpeg-devel@ffmpeg.org Cc: Niklas Haas <code@ffmpeg.org> Subject: [FFmpeg-devel] [PATCH] Fix for `apad` output getting stuck issue (PR #20600) Date: Wed, 24 Sep 2025 13:44:22 -0000 Message-ID: <175872146304.25.4396440944487062385@bf249f23a2c8> (raw) PR #20600 opened by Niklas Haas (haasn) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20600 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20600.patch >From b0cc8e1e7902a7fa8a46b295a8f88ef46407dd54 Mon Sep 17 00:00:00 2001 From: Niklas Haas <git@haasn.dev> Date: Wed, 24 Sep 2025 15:14:29 +0200 Subject: [PATCH 1/3] avfilter/buffersrc: add av_buffersrc_get_status() There is currently no way for API users to know that a buffersrc is no longer accepting input, except by trying to feed it a frame and seeing what happens. Of course, this is not possible if the user does not *have* a frame to feed, but may still wish to know if the filter is still accepting input or not. Since passing `frame == NULL` to `av_buffersrc_add_frame()` is already treated as closing the input, we are left with no choice but to introduce a new function for this. We don't explicitly return the result of `ff_outlink_get_status()` to avoid leaking internal status codes, and instead tranlate them all to AVERROR(EOF). --- doc/APIchanges | 3 +++ libavfilter/buffersrc.c | 10 ++++++++++ libavfilter/buffersrc.h | 8 ++++++++ libavfilter/version.h | 2 +- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 9d629f766f..506049eb03 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2025-03-28 API changes, most recent first: +2025-09-xx - xxxxxxxxxx - lavfi 11.10.100 - buffersrc.h + Add av_buffersrc_get_status(). + 2025-09-xx - xxxxxxxxxx - lavu 60.13.100 - hwcontext_d3d12va.h Add resource_flags and heap_flags to AVD3D12VADeviceContext Add heap_flags to AVD3D12VAFramesContext diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index 30f4df83a1..b18d3f24dd 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -286,6 +286,16 @@ int av_buffersrc_close(AVFilterContext *ctx, int64_t pts, unsigned flags) return (flags & AV_BUFFERSRC_FLAG_PUSH) ? push_frame(ctx->graph) : 0; } +int av_buffersrc_get_status(AVFilterContext *ctx) +{ + BufferSourceContext *s = ctx->priv; + + if (!s->eof && ff_outlink_get_status(ctx->outputs[0])) + s->eof = 1; + + return s->eof ? AVERROR(EOF) : 0; +} + static av_cold int init_video(AVFilterContext *ctx) { BufferSourceContext *c = ctx->priv; diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h index 54de1fd1f2..c7225b6752 100644 --- a/libavfilter/buffersrc.h +++ b/libavfilter/buffersrc.h @@ -216,6 +216,14 @@ int av_buffersrc_add_frame_flags(AVFilterContext *buffer_src, */ int av_buffersrc_close(AVFilterContext *ctx, int64_t pts, unsigned flags); +/** + * Returns 0 or a negative AVERROR code. Currently, this will only ever + * return AVERROR(EOF), to indicate that the buffer source has been closed, + * either as a result of av_buffersrc_close(), or because the downstream + * filter is no longer accepting new data. + */ +int av_buffersrc_get_status(AVFilterContext *ctx); + /** * @} */ diff --git a/libavfilter/version.h b/libavfilter/version.h index 77f38cb9b4..4a69d6be98 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -31,7 +31,7 @@ #include "version_major.h" -#define LIBAVFILTER_VERSION_MINOR 9 +#define LIBAVFILTER_VERSION_MINOR 10 #define LIBAVFILTER_VERSION_MICRO 100 -- 2.49.1 >From 2db129d55e0b5fc28b7ea466f0b352b6533c26e0 Mon Sep 17 00:00:00 2001 From: Niklas Haas <git@haasn.dev> Date: Wed, 24 Sep 2025 15:23:04 +0200 Subject: [PATCH 2/3] fftools/ffmpeg_filter: close all no-longer needed inputs Currently, the thread loop of ffmpeg_filter works like this: while (1) { frame, idx = get_from_decoder(); ret = send_to_filter_graph(frame); if (ret) { close_input(idx); continue; } while (filtered_frame = get_filtered_frame()) send_to_encoder(filtered_frame); } However, this leaves the possibility of leaving a no-longer-needed input permanently open if the filter graph starts producing infinite frames after it finishes reading from an input, e.g. in a filter graph like -af atrim,apad. This patch avoids this issue by always querying the status of all filter graph inputs and explicitly closing any that were closed downstream. As a result, information about the filtergraph being closed can now propagate back upstream, where the scheduler will no longer try to send frames to that filter graph input. Fixes: https://trac.ffmpeg.org/ticket/11061 See-Also: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20457#issuecomment-6208 --- fftools/ffmpeg_filter.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 2dae6400c8..1624b3afa3 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -2452,6 +2452,16 @@ finish: fps->dropped_keyframe |= fps->last_dropped && (frame->flags & AV_FRAME_FLAG_KEY); } +static void close_input(InputFilterPriv *ifp) +{ + FilterGraphPriv *fgp = fgp_from_fg(ifp->ifilter.graph); + + if (!ifp->eof) { + sch_filter_receive_finish(fgp->sch, fgp->sch_idx, ifp->ifilter.index); + ifp->eof = 1; + } +} + static int close_output(OutputFilterPriv *ofp, FilterGraphThread *fgt) { FilterGraphPriv *fgp = fgp_from_fg(ofp->ofilter.graph); @@ -2725,6 +2735,13 @@ static int read_frames(FilterGraph *fg, FilterGraphThread *fgt, fgt->next_in = fg->nb_inputs; did_step = 1; + + // ensure all inputs no longer accepting data are closed + for (int i = 0; i < fg->nb_inputs; i++) { + InputFilterPriv *ifp = ifp_from_ifilter(fg->inputs[i]); + if (av_buffersrc_get_status(ifp->ifilter.filter)) + close_input(ifp); + } } return AVERROR_EOF; @@ -3156,7 +3173,7 @@ static int filter_thread(void *arg) if (ret == AVERROR_EOF) { av_log(fg, AV_LOG_VERBOSE, "Input %u no longer accepts new data\n", input_idx); - sch_filter_receive_finish(fgp->sch, fgp->sch_idx, input_idx); + close_input(ifp); continue; } if (ret < 0) -- 2.49.1 >From f940f769696ff5ab4134d33cbaab5163869b2b01 Mon Sep 17 00:00:00 2001 From: Niklas Haas <git@haasn.dev> Date: Wed, 24 Sep 2025 15:40:59 +0200 Subject: [PATCH 3/3] tests/fate: add apad stuck regression test Reproduces the issue solved in the previous commit. --- tests/fate/filter-audio.mak | 3 ++ tests/ref/fate/filter-apad-stuck | 76 ++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 tests/ref/fate/filter-apad-stuck diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index eee0209c59..06b9d36546 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -432,6 +432,9 @@ fate-filter-crazychannels: tests/data/filtergraphs/crazychannels fate-filter-crazychannels: CMD = framecrc -auto_conversion_filters -/filter_complex $(TARGET_PATH)/tests/data/filtergraphs/crazychannels FATE_AFILTER-$(call FILTERFRAMECRC, ARESAMPLE SINE JOIN ATRIM CHANNELMAP CHANNELSPLIT, FILE_PROTOCOL) += fate-filter-crazychannels +fate-filter-apad-stuck: CMD = framecrc -f lavfi -i "testsrc=d=2[out0];sine=d=2[out1]" -af "atrim=end=0.1,apad=pad_dur=1" +FATE_AFILTER-$(call FILTERFRAMECRC, TESTSRC SINE ATRIM APAD, PIPE_PROTOCOL) += fate-filter-apad-stuck + FATE_AFILTER-yes += fate-filter-formats fate-filter-formats: libavfilter/tests/formats$(EXESUF) fate-filter-formats: CMD = run libavfilter/tests/formats$(EXESUF) diff --git a/tests/ref/fate/filter-apad-stuck b/tests/ref/fate/filter-apad-stuck new file mode 100644 index 0000000000..86581800f6 --- /dev/null +++ b/tests/ref/fate/filter-apad-stuck @@ -0,0 +1,76 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +#tb 1: 1/44100 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 44100 +#channel_layout_name 1: mono +0, 0, 0, 1, 230400, 0x88c4d19a +1, 0, 0, 1024, 2048, 0x2096f45b +1, 1024, 1024, 1024, 2048, 0x2262f6ec +0, 1, 1, 1, 230400, 0xc4740ad1 +1, 2048, 2048, 1024, 2048, 0xaa83fe05 +1, 3072, 3072, 1024, 2048, 0x487e06b5 +0, 2, 2, 1, 230400, 0xb6dd3deb +1, 4096, 4096, 314, 628, 0x135c404b +1, 4410, 4410, 4096, 8192, 0x00000000 +0, 3, 3, 1, 230400, 0x936e6bb1 +0, 4, 4, 1, 230400, 0x59759369 +1, 8506, 8506, 4096, 8192, 0x00000000 +0, 5, 5, 1, 230400, 0x0930b896 +0, 6, 6, 1, 230400, 0xc86bd3b6 +0, 7, 7, 1, 230400, 0x4cc2e982 +1, 12602, 12602, 4096, 8192, 0x00000000 +0, 8, 8, 1, 230400, 0x7b75f95f +0, 9, 9, 1, 230400, 0x15c00454 +1, 16698, 16698, 4096, 8192, 0x00000000 +0, 10, 10, 1, 230400, 0x754f0815 +0, 11, 11, 1, 230400, 0x08d505a9 +1, 20794, 20794, 4096, 8192, 0x00000000 +0, 12, 12, 1, 230400, 0x2f24fdf9 +0, 13, 13, 1, 230400, 0x8ecfedfd +0, 14, 14, 1, 230400, 0x1678da5f +1, 24890, 24890, 4096, 8192, 0x00000000 +0, 15, 15, 1, 230400, 0x0916c018 +0, 16, 16, 1, 230400, 0x503fa09c +1, 28986, 28986, 4096, 8192, 0x00000000 +0, 17, 17, 1, 230400, 0xe6f776b6 +0, 18, 18, 1, 230400, 0xf5d34ac1 +1, 33082, 33082, 4096, 8192, 0x00000000 +0, 19, 19, 1, 230400, 0xc6a918fc +0, 20, 20, 1, 230400, 0x28d1e139 +0, 21, 21, 1, 230400, 0x6c02a0ae +1, 37178, 37178, 4096, 8192, 0x00000000 +0, 22, 22, 1, 230400, 0xe83865b5 +0, 23, 23, 1, 230400, 0x85b62adb +1, 41274, 41274, 4096, 8192, 0x00000000 +0, 24, 24, 1, 230400, 0xcc7def95 +0, 25, 25, 1, 230400, 0xddc9f26f +1, 45370, 45370, 3140, 6280, 0x00000000 +0, 26, 26, 1, 230400, 0x6894b947 +0, 27, 27, 1, 230400, 0x4311862d +0, 28, 28, 1, 230400, 0x38ba5867 +0, 29, 29, 1, 230400, 0x4b5830af +0, 30, 30, 1, 230400, 0x76700b82 +0, 31, 31, 1, 230400, 0x9ba9f053 +0, 32, 32, 1, 230400, 0x01f2da87 +0, 33, 33, 1, 230400, 0xc2f6caaa +0, 34, 34, 1, 230400, 0x1e31bfc4 +0, 35, 35, 1, 230400, 0xbad2bc03 +0, 36, 36, 1, 230400, 0x296abe6f +0, 37, 37, 1, 230400, 0x0b19c610 +0, 38, 38, 1, 230400, 0xbaa1d60c +0, 39, 39, 1, 230400, 0x475fe9aa +0, 40, 40, 1, 230400, 0x6eab0400 +0, 41, 41, 1, 230400, 0x475b237c +0, 42, 42, 1, 230400, 0xda1d4d62 +0, 43, 43, 1, 230400, 0xf7367957 +0, 44, 44, 1, 230400, 0x5891ab1c +0, 45, 45, 1, 230400, 0x2dcfe2d0 +0, 46, 46, 1, 230400, 0x2b86236a +0, 47, 47, 1, 230400, 0xea3a5e63 +0, 48, 48, 1, 230400, 0x8748993d +0, 49, 49, 1, 230400, 0x7bb8d474 -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
reply other threads:[~2025-09-24 13:44 UTC|newest] Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=175872146304.25.4396440944487062385@bf249f23a2c8 \ --to=ffmpeg-devel@ffmpeg.org \ --cc=code@ffmpeg.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror http://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ http://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git