[FFmpeg-cvslog] avfilter/af_afir: add irnorm and irlink options

Paul B Mahol git at videolan.org
Sat Nov 18 18:10:10 EET 2023


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Sat Nov 18 00:36:18 2023 +0100| [5452cbdc150f0fcff736cd3897a2c41fec77fb79] | committer: Paul B Mahol

avfilter/af_afir: add irnorm and irlink options

Deprecate gtype option.

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

 doc/filters.texi            |  37 ++++++---------
 libavfilter/af_afir.c       |  57 ++++++++++++++++++----
 libavfilter/af_afir.h       |   3 ++
 libavfilter/afir_template.c | 113 +++++++++++---------------------------------
 4 files changed, 91 insertions(+), 119 deletions(-)

diff --git a/doc/filters.texi b/doc/filters.texi
index d83a3fb91e..ffe9a424a8 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -1794,33 +1794,24 @@ Set wet gain. This sets final output gain.
 Set Impulse Response filter length. Default is 1, which means whole IR is processed.
 
 @item gtype
-Enable applying gain measured from power of IR.
+This option is deprecated, and does nothing.
 
-Set which approach to use for auto gain measurement.
+ at item irnorm
+Set norm to be applied to IR coefficients before filtering.
+Allowed range is from @var{-1} to @var{2}.
+IR coefficients are normalized with calculated vector norm set by this option.
+For negative values, no norm is calculated, and IR coefficients are not modified at all.
+Default is @var{1}.
 
- at table @option
- at item none
-Do not apply any gain.
-
- at item peak
-select peak gain, very conservative approach. This is default value.
-
- at item dc
-select DC gain, limited application.
-
- at item gn
-select gain to noise approach, this is most popular one.
-
- at item ac
-select AC gain.
-
- at item rms
-select RMS gain.
- at end table
+ at item irlink
+For multichannel IR if this option is set to @var{true}. All IR channels will be
+normalized with maximal measured gain of all IR channels coefficients as set by @code{irnorm} option.
+When disabled, all IR coefficients in each IR channel will be normalized independently.
+Default is @var{true}.
 
 @item irgain
 Set gain to be applied to IR coefficients before filtering.
-Allowed range is 0 to 1. This gain is applied after any gain applied with @var{gtype} option.
+Allowed range is 0 to 1. This gain is applied after any gain applied with @var{irnorm} option.
 
 @item irfmt
 Set format of IR stream. Can be @code{mono} or @code{input}.
@@ -1899,7 +1890,7 @@ ffmpeg -i input.wav -i middle_tunnel_1way_mono.wav -lavfi afir output.wav
 Apply true stereo processing given input stereo stream, and two stereo impulse responses for left and right channel,
 the impulse response files are files with names l_ir.wav and r_ir.wav:
 @example
-"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:gtype=gn:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
+"pan=4C|c0=FL|c1=FL|c2=FR|c3=FR[a];amovie=l_ir.wav[LIR];amovie=r_ir.wav[RIR];[LIR][RIR]amerge[ir];[a][ir]afir=irfmt=input:irgain=-5dB,pan=stereo|FL<c0+c2|FR<c1+c3"
 @end example
 @end itemize
 
diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c
index 5d3f4070a7..ca4b585afd 100644
--- a/libavfilter/af_afir.c
+++ b/libavfilter/af_afir.c
@@ -393,6 +393,22 @@ skip:
 
     switch (s->format) {
     case AV_SAMPLE_FMT_FLTP:
+        for (int ch = 0; ch < s->nb_channels; ch++) {
+            const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
+
+            s->ch_gain[ch] = ir_gain_float(ctx, s, nb_taps, tsrc);
+        }
+
+        if (s->ir_link) {
+            float gain = +INFINITY;
+
+            for (int ch = 0; ch < s->nb_channels; ch++)
+                gain = fminf(gain, s->ch_gain[ch]);
+
+            for (int ch = 0; ch < s->nb_channels; ch++)
+                s->ch_gain[ch] = gain;
+        }
+
         for (int ch = 0; ch < s->nb_channels; ch++) {
             const float *tsrc = (const float *)s->ir[selir]->extended_data[!s->one2many * ch];
             float *time = (float *)s->norm_ir[selir]->extended_data[ch];
@@ -401,7 +417,7 @@ skip:
             for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
                 time[i] = 0;
 
-            get_power_float(ctx, s, nb_taps, ch, time);
+            ir_scale_float(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
 
             for (int n = 0; n < s->nb_segments[selir]; n++) {
                 AudioFIRSegment *seg = &s->seg[selir][n];
@@ -417,6 +433,22 @@ skip:
         }
         break;
     case AV_SAMPLE_FMT_DBLP:
+        for (int ch = 0; ch < s->nb_channels; ch++) {
+            const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
+
+            s->ch_gain[ch] = ir_gain_double(ctx, s, nb_taps, tsrc);
+        }
+
+        if (s->ir_link) {
+            double gain = +INFINITY;
+
+            for (int ch = 0; ch < s->nb_channels; ch++)
+                gain = fmin(gain, s->ch_gain[ch]);
+
+            for (int ch = 0; ch < s->nb_channels; ch++)
+                s->ch_gain[ch] = gain;
+        }
+
         for (int ch = 0; ch < s->nb_channels; ch++) {
             const double *tsrc = (const double *)s->ir[selir]->extended_data[!s->one2many * ch];
             double *time = (double *)s->norm_ir[selir]->extended_data[ch];
@@ -425,7 +457,8 @@ skip:
             for (int i = FFMAX(1, s->length * nb_taps); i < nb_taps; i++)
                 time[i] = 0;
 
-            get_power_double(ctx, s, nb_taps, ch, time);
+            ir_scale_double(ctx, s, nb_taps, ch, time, s->ch_gain[ch]);
+
             for (int n = 0; n < s->nb_segments[selir]; n++) {
                 AudioFIRSegment *seg = &s->seg[selir][n];
 
@@ -627,8 +660,9 @@ FF_ENABLE_DEPRECATION_WARNINGS
 
     s->format = outlink->format;
     s->nb_channels = outlink->ch_layout.nb_channels;
+    s->ch_gain = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->ch_gain));
     s->loading = av_calloc(ctx->inputs[0]->ch_layout.nb_channels, sizeof(*s->loading));
-    if (!s->loading)
+    if (!s->loading || !s->ch_gain)
         return AVERROR(ENOMEM);
 
     s->fadein[0] = ff_get_audio_buffer(outlink, s->min_part_size);
@@ -674,6 +708,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     AudioFIRContext *s = ctx->priv;
 
     av_freep(&s->fdsp);
+    av_freep(&s->ch_gain);
     av_freep(&s->loading);
 
     for (int i = 0; i < s->nb_irs; i++) {
@@ -812,13 +847,15 @@ static const AVOption afir_options[] = {
     { "dry",    "set dry gain",      OFFSET(dry_gain),   AV_OPT_TYPE_FLOAT, {.dbl=1},    0, 10, AFR },
     { "wet",    "set wet gain",      OFFSET(wet_gain),   AV_OPT_TYPE_FLOAT, {.dbl=1},    0, 10, AFR },
     { "length", "set IR length",     OFFSET(length),     AV_OPT_TYPE_FLOAT, {.dbl=1},    0,  1, AF },
-    { "gtype",  "set IR auto gain type",OFFSET(gtype),   AV_OPT_TYPE_INT,   {.i64=0},   -1,  4, AF, "gtype" },
-    {  "none",  "without auto gain", 0,                  AV_OPT_TYPE_CONST, {.i64=-1},   0,  0, AF, "gtype" },
-    {  "peak",  "peak gain",         0,                  AV_OPT_TYPE_CONST, {.i64=0},    0,  0, AF, "gtype" },
-    {  "dc",    "DC gain",           0,                  AV_OPT_TYPE_CONST, {.i64=1},    0,  0, AF, "gtype" },
-    {  "gn",    "gain to noise",     0,                  AV_OPT_TYPE_CONST, {.i64=2},    0,  0, AF, "gtype" },
-    {  "ac",    "AC gain",           0,                  AV_OPT_TYPE_CONST, {.i64=3},    0,  0, AF, "gtype" },
-    {  "rms",   "RMS gain",          0,                  AV_OPT_TYPE_CONST, {.i64=4},    0,  0, AF, "gtype" },
+    { "gtype",  "set IR auto gain type",OFFSET(gtype),   AV_OPT_TYPE_INT,   {.i64=0},   -1,  4, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    {  "none",  "without auto gain", 0,                  AV_OPT_TYPE_CONST, {.i64=-1},   0,  0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    {  "peak",  "peak gain",         0,                  AV_OPT_TYPE_CONST, {.i64=0},    0,  0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    {  "dc",    "DC gain",           0,                  AV_OPT_TYPE_CONST, {.i64=1},    0,  0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    {  "gn",    "gain to noise",     0,                  AV_OPT_TYPE_CONST, {.i64=2},    0,  0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    {  "ac",    "AC gain",           0,                  AV_OPT_TYPE_CONST, {.i64=3},    0,  0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    {  "rms",   "RMS gain",          0,                  AV_OPT_TYPE_CONST, {.i64=4},    0,  0, AF|AV_OPT_FLAG_DEPRECATED, "gtype" },
+    { "irnorm", "set IR norm",       OFFSET(ir_norm),    AV_OPT_TYPE_FLOAT, {.dbl=1},   -1,  2, AF },
+    { "irlink", "set IR link",       OFFSET(ir_link),    AV_OPT_TYPE_BOOL,  {.i64=1},    0,  1, AF },
     { "irgain", "set IR gain",       OFFSET(ir_gain),    AV_OPT_TYPE_FLOAT, {.dbl=1},    0,  1, AF },
     { "irfmt",  "set IR format",     OFFSET(ir_format),  AV_OPT_TYPE_INT,   {.i64=1},    0,  1, AF, "irfmt" },
     {  "mono",  "single channel",    0,                  AV_OPT_TYPE_CONST, {.i64=0},    0,  0, AF, "irfmt" },
diff --git a/libavfilter/af_afir.h b/libavfilter/af_afir.h
index 7c9a3b3e31..5c39aa10b9 100644
--- a/libavfilter/af_afir.h
+++ b/libavfilter/af_afir.h
@@ -63,6 +63,8 @@ typedef struct AudioFIRContext {
     float dry_gain;
     float length;
     int gtype;
+    float ir_norm;
+    float ir_link;
     float ir_gain;
     int ir_format;
     int ir_load;
@@ -87,6 +89,7 @@ typedef struct AudioFIRContext {
     int nb_channels;
     int one2many;
     int *loading;
+    double *ch_gain;
 
     AudioFIRSegment seg[MAX_IR_STREAMS][1024];
 
diff --git a/libavfilter/afir_template.c b/libavfilter/afir_template.c
index 9a11ec2fa6..676cec6dde 100644
--- a/libavfilter/afir_template.c
+++ b/libavfilter/afir_template.c
@@ -29,6 +29,8 @@
 #undef HYPOT
 #undef SAMPLE_FORMAT
 #undef TX_TYPE
+#undef FABS
+#undef POW
 #if DEPTH == 32
 #define SAMPLE_FORMAT float
 #define SQRT sqrtf
@@ -36,6 +38,8 @@
 #define ctype AVComplexFloat
 #define ftype float
 #define TX_TYPE AV_TX_FLOAT_RDFT
+#define FABS fabsf
+#define POW powf
 #else
 #define SAMPLE_FORMAT double
 #define SQRT sqrt
@@ -43,6 +47,8 @@
 #define ctype AVComplexDouble
 #define ftype double
 #define TX_TYPE AV_TX_DOUBLE_RDFT
+#define FABS fabs
+#define POW pow
 #endif
 
 #define fn3(a,b)   a##_##b
@@ -139,95 +145,32 @@ end:
     av_free(mag);
 }
 
-static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,
-                         int cur_nb_taps, int ch,
-                         ftype *time)
+static ftype fn(ir_gain)(AVFilterContext *ctx, AudioFIRContext *s,
+                         int cur_nb_taps, const ftype *time)
 {
-    ftype ch_gain = 1;
+    ftype ch_gain, sum = 0;
 
-    switch (s->gtype) {
-    case -1:
+    if (s->ir_norm < 0.f) {
         ch_gain = 1;
-        break;
-    case 0:
-        {
-            ftype sum = 0;
-
-            for (int i = 0; i < cur_nb_taps; i++)
-                sum += FFABS(time[i]);
-            ch_gain = 1. / sum;
-        }
-        break;
-    case 1:
-        {
-            ftype sum = 0;
-
-            for (int i = 0; i < cur_nb_taps; i++)
-                sum += time[i];
-            ch_gain = 1. / sum;
-        }
-        break;
-    case 2:
-        {
-            ftype sum = 0;
-
-            for (int i = 0; i < cur_nb_taps; i++)
-                sum += time[i] * time[i];
-            ch_gain = 1. / SQRT(sum);
-        }
-        break;
-    case 3:
-    case 4:
-        {
-            ftype *inc, *outc, scale, power;
-            AVTXContext *tx;
-            av_tx_fn tx_fn;
-            int ret, size;
-
-            size = 1 << av_ceil_log2_c(cur_nb_taps);
-            inc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
-            outc = av_calloc(size + 2, sizeof(SAMPLE_FORMAT));
-            if (!inc || !outc) {
-                av_free(outc);
-                av_free(inc);
-                break;
-            }
-
-            scale = 1.;
-            ret = av_tx_init(&tx, &tx_fn, TX_TYPE, 0, size, &scale, 0);
-            if (ret < 0) {
-                av_free(outc);
-                av_free(inc);
-                break;
-            }
-
-            {
-                memcpy(inc, time, cur_nb_taps * sizeof(SAMPLE_FORMAT));
-                tx_fn(tx, outc, inc, sizeof(SAMPLE_FORMAT));
-
-                power = 0;
-                if (s->gtype == 3) {
-                    for (int i = 0; i < size / 2 + 1; i++)
-                        power = FFMAX(power, HYPOT(outc[i * 2], outc[i * 2 + 1]));
-                } else {
-                    ftype sum = 0;
-                    for (int i = 0; i < size / 2 + 1; i++)
-                        sum += HYPOT(outc[i * 2], outc[i * 2 + 1]);
-                    power = SQRT(sum / (size / 2 + 1));
-                }
-
-                ch_gain = 1. / power;
-            }
-
-            av_tx_uninit(&tx);
-            av_free(outc);
-            av_free(inc);
-        }
-        break;
-    default:
-        return AVERROR_BUG;
+    } else if (s->ir_norm == 0.f) {
+        for (int i = 0; i < cur_nb_taps; i++)
+            sum += time[i];
+        ch_gain = 1. / sum;
+    } else {
+        ftype ir_norm = s->ir_norm;
+
+        for (int i = 0; i < cur_nb_taps; i++)
+            sum += POW(FABS(time[i]), ir_norm);
+        ch_gain = 1. / POW(sum, 1. / ir_norm);
     }
 
+    return ch_gain;
+}
+
+static void fn(ir_scale)(AVFilterContext *ctx, AudioFIRContext *s,
+                         int cur_nb_taps, int ch,
+                         ftype *time, ftype ch_gain)
+{
     if (ch_gain != 1. || s->ir_gain != 1.) {
         ftype gain = ch_gain * s->ir_gain;
 
@@ -238,8 +181,6 @@ static int fn(get_power)(AVFilterContext *ctx, AudioFIRContext *s,
         s->fdsp->vector_dmul_scalar(time, time, gain, FFALIGN(cur_nb_taps, 8));
 #endif
     }
-
-    return 0;
 }
 
 static void fn(convert_channel)(AVFilterContext *ctx, AudioFIRContext *s, int ch,



More information about the ffmpeg-cvslog mailing list