diff --git a/doc/filters.texi b/doc/filters.texi index ce200aa314..3be83533bb 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -1703,6 +1703,14 @@ Specify weight of each input audio stream as sequence. Each weight is separated by space. By default all inputs have same weight. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item weights +Syntax is same as option with same name. +@end table + @section amultiply Multiply first audio stream with second audio stream and store result diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index c09f8b034b..0826fc118c 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -181,6 +181,7 @@ typedef struct MixContext { #define OFFSET(x) offsetof(MixContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM #define F AV_OPT_FLAG_FILTERING_PARAM +#define T AV_OPT_FLAG_RUNTIME_PARAM static const AVOption amix_options[] = { { "inputs", "Number of inputs.", OFFSET(nb_inputs), AV_OPT_TYPE_INT, { .i64 = 2 }, 1, INT16_MAX, A|F }, @@ -193,7 +194,7 @@ static const AVOption amix_options[] = { "renormalization when an input stream ends.", OFFSET(dropout_transition), AV_OPT_TYPE_FLOAT, { .dbl = 2.0 }, 0, INT_MAX, A|F }, { "weights", "Set weight for each input.", - OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, A|F }, + OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, A|F|T }, { NULL } }; @@ -504,12 +505,37 @@ static int activate(AVFilterContext *ctx) return 0; } -static av_cold int init(AVFilterContext *ctx) +static void parse_weights(AVFilterContext *ctx) { MixContext *s = ctx->priv; float last_weight = 1.f; - int i, ret; char *p; + int i; + + s->weight_sum = 0.f; + p = s->weights_str; + for (i = 0; i < s->nb_inputs; i++) { + last_weight = av_strtod(p, &p); + s->weights[i] = last_weight; + s->weight_sum += FFABS(last_weight); + if (p && *p) { + p++; + } else { + i++; + break; + } + } + + for (; i < s->nb_inputs; i++) { + s->weights[i] = last_weight; + s->weight_sum += FFABS(last_weight); + } +} + +static av_cold int init(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + int i, ret; for (i = 0; i < s->nb_inputs; i++) { AVFilterPad pad = { 0 }; @@ -533,23 +559,7 @@ static av_cold int init(AVFilterContext *ctx) if (!s->weights) return AVERROR(ENOMEM); - p = s->weights_str; - for (i = 0; i < s->nb_inputs; i++) { - last_weight = av_strtod(p, &p); - s->weights[i] = last_weight; - s->weight_sum += FFABS(last_weight); - if (p && *p) { - p++; - } else { - i++; - break; - } - } - - for (; i < s->nb_inputs; i++) { - s->weights[i] = last_weight; - s->weight_sum += FFABS(last_weight); - } + parse_weights(ctx); return 0; } @@ -604,6 +614,24 @@ fail: return ret; } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + MixContext *s = ctx->priv; + int ret; + + ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags); + if (ret < 0) + return ret; + + parse_weights(ctx); + for (int i = 0; i < s->nb_inputs; i++) + s->scale_norm[i] = s->weight_sum / FFABS(s->weights[i]); + calculate_scales(s, 0); + + return 0; +} + static const AVFilterPad avfilter_af_amix_outputs[] = { { .name = "default", @@ -624,5 +652,6 @@ AVFilter ff_af_amix = { .query_formats = query_formats, .inputs = NULL, .outputs = avfilter_af_amix_outputs, + .process_command = process_command, .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, };