Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: cenzhanquan1 via ffmpeg-devel <ffmpeg-devel@ffmpeg.org>
To: ffmpeg-devel@ffmpeg.org
Cc: cenzhanquan1 <code@ffmpeg.org>
Subject: [FFmpeg-devel] [PATCH] avfilter: enhance command processing with chain propagation and direction control. (PR #20731)
Date: Tue, 21 Oct 2025 09:40:20 -0000
Message-ID: <176103962100.62.8039215404646309233@bf907ddaa564> (raw)

PR #20731 opened by cenzhanquan1
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20731
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/20731.patch

The existing avfilter_process_command and avfilter_graph_send_command havelimitations in
command propagation: they only handle commands for individualfilters and lack the ability
to propagate commands through the entire filterchain, nor do they support directional
traversal of the filter graph. Thismakes it difficult to control multiple filters in a chain
(e.g., adjustingvolume for all related filters or enabling/disabling a series of filters)with
a single command.

This patch enhances the command processing logic to address these issues:
Add two new flags to control command propagation:
AVFILTER_CMD_FLAG_CHAIN: Enables command propagation through the entire
filter chain. After processing the current filter, it traverses all
associated links (inputs/outputs based on direction) and recursively
forwards the command to subsequent filters, covering the full filter
topology.
AVFILTER_CMD_FLAG_REVERSE: Works with AVFILTER_CMD_FLAG_CHAIN to control
traversal direction. Default (forward) follows data flow (source →
destination filters), while reverse traversal goes against data flow
(destination → source filters).
Refactor avfilter_process_command to integrate chain propagation logic:
Process the command for the current filter first, then check if chain
propagation is enabled.
Traverse all relevant links (inputs for reverse, outputs for forward) and
recursively forward the command to next-level filters.
Track processing status (processed) to determine if any filter in the
chain handled the command.
Respect AVFILTER_CMD_FLAG_ONE to stop propagation once a filter processes
the command, and propagate critical errors.
Improve command handling for built-in commands ("ping" and "enable") to
workseamlessly with the new propagation logic, ensuring consistent behavioracross the chain.
These changes enable flexible command control over entire filter chains,supporting use cases
like batch adjustment of filters, topology-wide statuschecks (via "ping"), and coordinated
enable/disable operations, whilemaintaining compatibility with existing filter command
implementations.

Signed-off-by: cenzhanquan1 <cenzhanquan1@xiaomi.com>


From 9dba682222bd55c952e14e71789a7084529a74f7 Mon Sep 17 00:00:00 2001
From: cenzhanquan1 <cenzhanquan1@xiaomi.com>
Date: Tue, 21 Oct 2025 17:34:22 +0800
Subject: [PATCH] avfilter: enhance command processing with chain propagation
 and direction control.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

The existing avfilter_process_command and avfilter_graph_send_command havelimitations in
command propagation: they only handle commands for individualfilters and lack the ability
to propagate commands through the entire filterchain, nor do they support directional
traversal of the filter graph. Thismakes it difficult to control multiple filters in a chain
(e.g., adjustingvolume for all related filters or enabling/disabling a series of filters)with
a single command.

This patch enhances the command processing logic to address these issues:
Add two new flags to control command propagation:
AVFILTER_CMD_FLAG_CHAIN: Enables command propagation through the entire
filter chain. After processing the current filter, it traverses all
associated links (inputs/outputs based on direction) and recursively
forwards the command to subsequent filters, covering the full filter
topology.
AVFILTER_CMD_FLAG_REVERSE: Works with AVFILTER_CMD_FLAG_CHAIN to control
traversal direction. Default (forward) follows data flow (source →
destination filters), while reverse traversal goes against data flow
(destination → source filters).
Refactor avfilter_process_command to integrate chain propagation logic:
Process the command for the current filter first, then check if chain
propagation is enabled.
Traverse all relevant links (inputs for reverse, outputs for forward) and
recursively forward the command to next-level filters.
Track processing status (processed) to determine if any filter in the
chain handled the command.
Respect AVFILTER_CMD_FLAG_ONE to stop propagation once a filter processes
the command, and propagate critical errors.
Improve command handling for built-in commands ("ping" and "enable") to
workseamlessly with the new propagation logic, ensuring consistent behavioracross the chain.
These changes enable flexible command control over entire filter chains,supporting use cases
like batch adjustment of filters, topology-wide statuschecks (via "ping"), and coordinated
enable/disable operations, whilemaintaining compatibility with existing filter command
implementations.

Signed-off-by: cenzhanquan1 <cenzhanquan1@xiaomi.com>
---
 libavfilter/avfilter.c | 75 +++++++++++++++++++++++++++++++++---------
 libavfilter/avfilter.h | 10 ++++--
 2 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index 169c2baa42..68ec9f6f6a 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -607,25 +607,68 @@ static int set_enable_expr(FFFilterContext *ctxi, const char *expr)
     return 0;
 }
 
-int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags)
+int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg,
+                            char *res, int res_len, int flags)
 {
-    if(!strcmp(cmd, "ping")){
-        char local_res[256] = {0};
+    int direction = flags & AVFILTER_CMD_FLAG_REVERSE;
+    int ret = AVERROR(ENOSYS);
+    int processed = 0;
 
-        if (!res) {
-            res = local_res;
-            res_len = sizeof(local_res);
-        }
-        av_strlcatf(res, res_len, "pong from:%s %s\n", filter->filter->name, filter->name);
-        if (res == local_res)
-            av_log(filter, AV_LOG_INFO, "%s", res);
-        return 0;
-    }else if(!strcmp(cmd, "enable")) {
-        return set_enable_expr(fffilterctx(filter), arg);
-    }else if (fffilter(filter->filter)->process_command) {
-        return fffilter(filter->filter)->process_command(filter, cmd, arg, res, res_len, flags);
+    int process_flags = flags & ~AVFILTER_CMD_FLAG_CHAIN;
+    if (!strcmp(cmd, "ping")) {
+        char local_res[256] = {0};
+        char *res_buf = res ? res : local_res;
+        size_t buf_len = res ? res_len : sizeof(local_res);
+        av_strlcatf(res_buf, buf_len, "pong from:%s %s\n",
+                   filter->filter->name, filter->name ? filter->name : "unknown");
+        if (!res)
+            av_log(filter, AV_LOG_INFO, "%s", res_buf);
+        ret = 0;
+    } else if (!strcmp(cmd, "enable")) {
+        ret = set_enable_expr(fffilterctx(filter), arg);
+    } else if (fffilter(filter->filter)->process_command) {
+        ret = fffilter(filter->filter)->process_command(filter, cmd, arg, res, res_len, process_flags);
+    } else {
+        ret = AVERROR(ENOSYS);
     }
-    return AVERROR(ENOSYS);
+
+    if (ret != AVERROR(ENOSYS)) {
+        processed = 1;
+        if ((flags & AVFILTER_CMD_FLAG_ONE) || ret < 0) {
+            return ret;
+        }
+    }
+
+    if (!(flags & AVFILTER_CMD_FLAG_CHAIN)) {
+        return processed ? 0 : AVERROR(ENOSYS);
+    }
+
+    av_log(filter, AV_LOG_DEBUG,
+           "cmd_chain: [%s] dir:%s -> '%s' '%s' (forwarding)\n",
+           filter->name ? filter->name : "unknown",
+           direction ? "reverse" : "forward",
+           cmd, arg ? arg : "");
+
+    unsigned nb_links = direction ? filter->nb_inputs : filter->nb_outputs;
+    for (int i = 0; i < nb_links; i++) {
+        AVFilterLink *link = direction ? filter->inputs[i] : filter->outputs[i];
+        AVFilterContext *next_filter = direction ? (link ? link->src : NULL) : (link ? link->dst : NULL);
+
+        if (!link || !next_filter) {
+            av_log(filter, AV_LOG_DEBUG, "Invalid %s link at pad %d\n",
+                   direction ? "input" : "output", i);
+            continue;
+        }
+
+        ret = avfilter_process_command(next_filter, cmd, arg, res, res_len, flags);
+        if (ret >= 0) {
+            processed = 1;
+        } else if (ret != AVERROR(ENOSYS)) {
+            return ret;
+        }
+    }
+
+    return processed ? 0 : AVERROR(ENOSYS);
 }
 
 unsigned avfilter_filter_pad_count(const AVFilter *filter, int is_output)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 02b58c42c2..fde3811dc3 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -466,8 +466,14 @@ struct AVFilterLink {
 int avfilter_link(AVFilterContext *src, unsigned srcpad,
                   AVFilterContext *dst, unsigned dstpad);
 
-#define AVFILTER_CMD_FLAG_ONE   1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically
-#define AVFILTER_CMD_FLAG_FAST  2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw)
+#define AVFILTER_CMD_FLAG_ONE     1 ///< Stop once a filter understood the command (for target=all for example), fast filters are favored automatically
+#define AVFILTER_CMD_FLAG_FAST    2 ///< Only execute command when its fast (like a video out that supports contrast adjustment in hw)
+#define AVFILTER_CMD_FLAG_CHAIN   4 ///< Propagate the command through the entire filter chain. After processing the current filter,
+                                    /// traverse all its associated links (inputs or outputs, based on direction) and recursively
+                                    /// forward the command to subsequent filters, covering the full filter topology.
+#define AVFILTER_CMD_FLAG_REVERSE 8 ///< Only effective when paired with AVFILTER_CMD_FLAG_CHAIN. Changes the command's traversal
+                                    /// direction in the chain: default (forward) follows data flow (source → destination filters),
+                                    /// while reverse traversal opposes data flow (destination → source filters).
 
 /**
  * Make the filter instance process a command.
-- 
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-10-21  9:41 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=176103962100.62.8039215404646309233@bf907ddaa564 \
    --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 https://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/ https://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