[FFmpeg-cvslog] avfilter/af_amix: add weights option

Paul B Mahol git at videolan.org
Sun Apr 1 21:37:59 EEST 2018


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Thu Mar 29 13:54:51 2018 +0200| [8dff6c2844965473ec37a32c136887efe5e622b9] | committer: Paul B Mahol

avfilter/af_amix: add weights option

Signed-off-by: Paul B Mahol <onemda at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=8dff6c2844965473ec37a32c136887efe5e622b9
---

 doc/filters.texi      |  3 +++
 libavfilter/af_amix.c | 55 ++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index bf2b94e240..7538ab3273 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1350,6 +1350,9 @@ The duration of the first input.
 The transition time, in seconds, for volume renormalization when an input
 stream ends. The default value is 2 seconds.
 
+ at item weights
+Specify weight of each input audio stream as sequence.
+Each weight is separated by space. By default all inputs have same weight.
 @end table
 
 @section anequalizer
diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c
index ec764375c0..46f1bf63d7 100644
--- a/libavfilter/af_amix.c
+++ b/libavfilter/af_amix.c
@@ -162,6 +162,7 @@ typedef struct MixContext {
     int active_inputs;          /**< number of input currently active */
     int duration_mode;          /**< mode for determining duration */
     float dropout_transition;   /**< transition time when an input drops out */
+    char *weights_str;          /**< string for custom weights for every input */
 
     int nb_channels;            /**< number of channels */
     int sample_rate;            /**< sample rate */
@@ -169,7 +170,9 @@ typedef struct MixContext {
     AVAudioFifo **fifos;        /**< audio fifo for each input */
     uint8_t *input_state;       /**< current state of each input */
     float *input_scale;         /**< mixing scale factor for each input */
-    float scale_norm;           /**< normalization factor for all inputs */
+    float *weights;             /**< custom weights for every input */
+    float weight_sum;           /**< sum of custom weights for every input */
+    float *scale_norm;          /**< normalization factor for every input */
     int64_t next_pts;           /**< calculated pts for next output frame */
     FrameList *frame_list;      /**< list of frame info for the first input */
 } MixContext;
@@ -188,6 +191,8 @@ static const AVOption amix_options[] = {
     { "dropout_transition", "Transition time, in seconds, for volume "
                             "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 },
     { NULL }
 };
 
@@ -202,16 +207,26 @@ AVFILTER_DEFINE_CLASS(amix);
  */
 static void calculate_scales(MixContext *s, int nb_samples)
 {
+    float weight_sum = 0.f;
     int i;
 
-    if (s->scale_norm > s->active_inputs) {
-        s->scale_norm -= nb_samples / (s->dropout_transition * s->sample_rate);
-        s->scale_norm = FFMAX(s->scale_norm, s->active_inputs);
+    for (i = 0; i < s->nb_inputs; i++)
+        if (s->input_state[i] & INPUT_ON)
+            weight_sum += s->weights[i];
+
+    for (i = 0; i < s->nb_inputs; i++) {
+        if (s->input_state[i] & INPUT_ON) {
+            if (s->scale_norm[i] > weight_sum / s->weights[i]) {
+                s->scale_norm[i] -= ((s->weight_sum / s->weights[i]) / s->nb_inputs) *
+                                    nb_samples / (s->dropout_transition * s->sample_rate);
+                s->scale_norm[i] = FFMAX(s->scale_norm[i], weight_sum / s->weights[i]);
+            }
+        }
     }
 
     for (i = 0; i < s->nb_inputs; i++) {
         if (s->input_state[i] & INPUT_ON)
-            s->input_scale[i] = 1.0f / s->scale_norm;
+            s->input_scale[i] = 1.0f / s->scale_norm[i];
         else
             s->input_scale[i] = 0.0f;
     }
@@ -251,9 +266,11 @@ static int config_output(AVFilterLink *outlink)
     s->active_inputs = s->nb_inputs;
 
     s->input_scale = av_mallocz_array(s->nb_inputs, sizeof(*s->input_scale));
-    if (!s->input_scale)
+    s->scale_norm  = av_mallocz_array(s->nb_inputs, sizeof(*s->scale_norm));
+    if (!s->input_scale || !s->scale_norm)
         return AVERROR(ENOMEM);
-    s->scale_norm = s->active_inputs;
+    for (i = 0; i < s->nb_inputs; i++)
+        s->scale_norm[i] = s->weight_sum / s->weights[i];
     calculate_scales(s, 0);
 
     av_get_channel_layout_string(buf, sizeof(buf), -1, outlink->channel_layout);
@@ -487,6 +504,8 @@ static int activate(AVFilterContext *ctx)
 static av_cold int init(AVFilterContext *ctx)
 {
     MixContext *s = ctx->priv;
+    char *p, *arg, *saveptr = NULL;
+    float last_weight = 1.f;
     int i, ret;
 
     for (i = 0; i < s->nb_inputs; i++) {
@@ -507,6 +526,26 @@ static av_cold int init(AVFilterContext *ctx)
     if (!s->fdsp)
         return AVERROR(ENOMEM);
 
+    s->weights = av_mallocz_array(s->nb_inputs, sizeof(*s->weights));
+    if (!s->weights)
+        return AVERROR(ENOMEM);
+
+    p = s->weights_str;
+    for (i = 0; i < s->nb_inputs; i++) {
+        if (!(arg = av_strtok(p, " ", &saveptr)))
+            break;
+
+        p = NULL;
+        sscanf(arg, "%f", &last_weight);
+        s->weights[i] = last_weight;
+        s->weight_sum += last_weight;
+    }
+
+    for (; i < s->nb_inputs; i++) {
+        s->weights[i] = last_weight;
+        s->weight_sum += last_weight;
+    }
+
     return 0;
 }
 
@@ -524,6 +563,8 @@ static av_cold void uninit(AVFilterContext *ctx)
     av_freep(&s->frame_list);
     av_freep(&s->input_state);
     av_freep(&s->input_scale);
+    av_freep(&s->scale_norm);
+    av_freep(&s->weights);
     av_freep(&s->fdsp);
 
     for (i = 0; i < ctx->nb_inputs; i++)



More information about the ffmpeg-cvslog mailing list