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 <[email protected]>


From 9dba682222bd55c952e14e71789a7084529a74f7 Mon Sep 17 00:00:00 2001
From: cenzhanquan1 <[email protected]>
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 <[email protected]>
---
 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 -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to