PR #21156 opened by cenzhanquan1 URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21156 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/21156.patch
Add FATE tests for the new 'forward' and 'backward' command propagation modes in asendcmd/sendcmd, which allow directional traversal of the filter graph to control multiple filters with a single command. - fate-filter-sendcmd-graph: tests mode=graph (existing behavior) - fate-filter-sendcmd-forward: tests mode=forward (propagate downstream) - fate-filter-sendcmd-backward: tests mode=backward (propagate upstream) These tests verify that volume adjustments are correctly applied across the filter chain according to the specified propagation direction, using sine wave inputs and amix for deterministic output. The tests depend on ASENDCMD, VOLUME, ANULL, ADELAY, and AMIX filters, and use framecrc for reproducible verification. Signed-off-by: cenzhanquan1 <[email protected]> >From ca1bb9407ecfc8e52cd895ba2ae2a30ed8e0ff93 Mon Sep 17 00:00:00 2001 From: cenzhanquan1 <[email protected]> Date: Wed, 10 Dec 2025 23:08:00 +0800 Subject: [PATCH] fate: add tests for asendcmd/sendcmd propagation modes. Add FATE tests for the new 'forward' and 'backward' command propagation modes in asendcmd/sendcmd, which allow directional traversal of the filter graph to control multiple filters with a single command. - fate-filter-sendcmd-graph: tests mode=graph (existing behavior) - fate-filter-sendcmd-forward: tests mode=forward (propagate downstream) - fate-filter-sendcmd-backward: tests mode=backward (propagate upstream) These tests verify that volume adjustments are correctly applied across the filter chain according to the specified propagation direction, using sine wave inputs and amix for deterministic output. The tests depend on ASENDCMD, VOLUME, ANULL, ADELAY, and AMIX filters, and use framecrc for reproducible verification. Signed-off-by: cenzhanquan1 <[email protected]> --- libavfilter/f_sendcmd.c | 69 ++++++++++++++++++++++++++++++++----- tests/fate/filter-audio.mak | 42 ++++++++++++++++++++++ 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/libavfilter/f_sendcmd.c b/libavfilter/f_sendcmd.c index 304658ae3d..7d841d0e87 100644 --- a/libavfilter/f_sendcmd.c +++ b/libavfilter/f_sendcmd.c @@ -98,6 +98,12 @@ typedef struct Interval { int enabled; ///< current time detected inside this interval } Interval; +typedef enum { + CMD_MODE_GRAPH = 0, + CMD_MODE_FORWARD, + CMD_MODE_BACKWARD +} SendCmdMode; + typedef struct SendCmdContext { const AVClass *class; Interval *intervals; @@ -105,6 +111,8 @@ typedef struct SendCmdContext { char *commands_filename; char *commands_str; + + int mode; } SendCmdContext; #define OFFSET(x) offsetof(SendCmdContext, x) @@ -114,6 +122,10 @@ static const AVOption options[] = { { "c", "set commands", OFFSET(commands_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, { "filename", "set commands file", OFFSET(commands_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, { "f", "set commands file", OFFSET(commands_filename), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, + { "mode", "set command propagation mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=CMD_MODE_GRAPH}, CMD_MODE_GRAPH, CMD_MODE_BACKWARD, FLAGS, "mode" }, + { "graph", "graph send command mode", 0, AV_OPT_TYPE_CONST, {.i64=CMD_MODE_GRAPH}, 0, 0, FLAGS, "mode" }, + { "forward", "forward traversal mode", 0, AV_OPT_TYPE_CONST, {.i64=CMD_MODE_FORWARD}, 0, 0, FLAGS, "mode" }, + { "backward", "backward traversal mode", 0, AV_OPT_TYPE_CONST, {.i64=CMD_MODE_BACKWARD}, 0, 0, FLAGS, "mode" }, { NULL } }; @@ -530,6 +542,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref) for (j = 0; flags && j < interval->nb_commands; j++) { Command *cmd = &interval->commands[j]; char *cmd_arg = cmd->arg; + int send_flags = 0; char buf[1024]; if (cmd->flags & flags) { @@ -561,16 +574,56 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *ref) return AVERROR(ENOMEM); } } + + if (s->mode == CMD_MODE_GRAPH) + send_flags = AVFILTER_CMD_FLAG_ONE; + else if (s->mode == CMD_MODE_FORWARD) + send_flags = AVFILTER_CMD_FLAG_FORWARD; + else if (s->mode == CMD_MODE_BACKWARD) + send_flags = AVFILTER_CMD_FLAG_BACKWARD; + av_log(ctx, AV_LOG_VERBOSE, - "Processing command #%d target:%s command:%s arg:%s\n", - cmd->index, cmd->target, cmd->command, cmd_arg); - ret = avfilter_graph_send_command(inl->graph, - cmd->target, cmd->command, cmd_arg, - buf, sizeof(buf), - AVFILTER_CMD_FLAG_ONE); + "Processing command #%d target:%s command:%s arg:%s\n", + cmd->index, cmd->target, cmd->command, cmd_arg); + + if (s->mode == CMD_MODE_GRAPH) { + ret = avfilter_graph_send_command(inl->graph, + cmd->target, cmd->command, cmd_arg, + buf, sizeof(buf), + send_flags); + } else { + AVFilterContext *start_filter = NULL; + + if (cmd->target && cmd->target[0]) { + for (int k = 0; k < inl->graph->nb_filters; k++) { + AVFilterContext *filter = inl->graph->filters[k]; + + if (filter->name && strcmp(filter->name, cmd->target) == 0) { + start_filter = filter; + break; + } + } + } + + if (!start_filter) { + av_log(ctx, AV_LOG_ERROR, + "Cannot find target filter instance '%s' for command #%d in non-GRAPH mode\n", + cmd->target ? cmd->target : "(null)", j); + + if (cmd->flags & COMMAND_FLAG_EXPR) + av_freep(&cmd_arg); + + continue; + } + + ret = avfilter_process_command(start_filter, cmd->command, + cmd_arg, buf, sizeof(buf), send_flags); + } + av_log(ctx, AV_LOG_VERBOSE, - "Command reply for command #%d: ret:%s res:%s\n", - cmd->index, av_err2str(ret), buf); + "Command reply for command #%d: ret:%s res:%s\n", + cmd->index, av_err2str(ret), buf); + if (cmd->flags & COMMAND_FLAG_EXPR) av_freep(&cmd_arg); } diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index 526645a634..4db1594bab 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -451,3 +451,45 @@ FATE_AFILTER-yes := $(if $(call FRAMECRC), $(FATE_AFILTER-yes)) FATE_SAMPLES_AVCONV += $(FATE_AFILTER_SAMPLES-yes) FATE_FFMPEG += $(FATE_AFILTER-yes) fate-afilter: $(FATE_AFILTER-yes) $(FATE_AFILTER_SAMPLES-yes) + +# FATE tests for sendcmd/asendcmd with new propagation modes + +# Test 'graph' mode: commands affect multiple filters in a graph, +# demonstrating cross-filter parameter propagation. +FATE_AFILTER-$(call FILTERDEMDECENCMUX, ASENDCMD VOLUME ANULL AMIX, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-sendcmd-graph +fate-filter-sendcmd-graph: tests/data/filtergraphs/sendcmd-graph +fate-filter-sendcmd-graph: CMD = ffmpeg \ + -f lavfi -i "sine=frequency=440:sample_rate=44100:duration=5" \ + -f lavfi -i "sine=frequency=880:sample_rate=44100:duration=5" \ + -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/sendcmd-graph \ + -map "[mixout]" -t 5 -f framecrc - + +tests/data/filtergraphs/sendcmd-graph: TAG = GEN +tests/data/filtergraphs/sendcmd-graph: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data/filtergraphs + $(M)echo '[0:a]asendcmd=mode=graph:commands=0.0 volume volume 0.5,anull,volume=precision=fixed:volume=1.0[a1];[1:a]asendcmd=mode=graph:commands=0.0 volume volume 0.3,anull,volume=precision=fixed:volume=1.0[a2];[a1][a2]amix=inputs=2[mixout]' > $(TARGET_PATH)/tests/data/filtergraphs/sendcmd-graph + +# Test 'forward' mode: command propagates forward to filters downstream. +FATE_AFILTER-$(call FILTERDEMDECENCMUX, ASENDCMD VOLUME ADELAY AMIX, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-sendcmd-forward +fate-filter-sendcmd-forward: tests/data/filtergraphs/sendcmd-forward +fate-filter-sendcmd-forward: CMD = ffmpeg \ + -f lavfi -i "sine=frequency=440:sample_rate=44100:duration=5" \ + -f lavfi -i "sine=frequency=880:sample_rate=44100:duration=5" \ + -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/sendcmd-forward \ + -map "[mixout]" -t 5 -f framecrc - + +tests/data/filtergraphs/sendcmd-forward: TAG = GEN +tests/data/filtergraphs/sendcmd-forward: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data/filtergraphs + $(M)echo '[0:a]asendcmd=mode=forward:commands=0.0 volume volume 0.5,volume=precision=fixed:volume=1.0,aformat=sample_fmts=fltp,adelay=1000,volume=precision=fixed:volume=1.0[a1];[1:a]volume=precision=fixed:volume=1.0,aformat=sample_fmts=fltp,adelay=2000,volume=precision=fixed:volume=1.0[a2];[a1][a2]amix=inputs=2[mixout]' > $(TARGET_PATH)/tests/data/filtergraphs/sendcmd-forward + +# Test 'backward' mode: command propagates backward to upstream filters. +FATE_AFILTER-$(call FILTERDEMDECENCMUX, ASENDCMD VOLUME ADELAY AMIX, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-sendcmd-backward +fate-filter-sendcmd-backward: tests/data/filtergraphs/sendcmd-backward +fate-filter-sendcmd-backward: CMD = ffmpeg \ + -f lavfi -i "sine=frequency=440:sample_rate=44100:duration=5" \ + -f lavfi -i "sine=frequency=880:sample_rate=44100:duration=5" \ + -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/sendcmd-backward \ + -map "[mixout]" -t 5 -f framecrc - + +tests/data/filtergraphs/sendcmd-backward: TAG = GEN +tests/data/filtergraphs/sendcmd-backward: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data/filtergraphs + $(M)echo '[0:a]volume=precision=fixed:volume=1.0,aformat=sample_fmts=fltp,adelay=1000,volume=precision=fixed:volume=1.0[a1];[1:a]volume=precision=fixed:volume=1.0,aformat=sample_fmts=fltp,adelay=2000,volume=precision=fixed:volume=1.0[a2];[a1][a2]amix=inputs=2,asendcmd=mode=backward:commands=0.0 volume volume 0.3[mixout]' > $(TARGET_PATH)/tests/data/filtergraphs/sendcmd-backward \ No newline at end of file -- 2.49.1 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
