Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
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