Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / libavfilter / af_anlms.c
1 /*
2  * Copyright (c) 2019 Paul B Mahol
3  *
4  * This file is part of FFmpeg.
5  *
6  * FFmpeg is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * FFmpeg is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with FFmpeg; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "libavutil/channel_layout.h"
22 #include "libavutil/common.h"
23 #include "libavutil/float_dsp.h"
24 #include "libavutil/opt.h"
25
26 #include "audio.h"
27 #include "avfilter.h"
28 #include "filters.h"
29 #include "internal.h"
30
31 enum OutModes {
32     IN_MODE,
33     DESIRED_MODE,
34     OUT_MODE,
35     NOISE_MODE,
36     ERROR_MODE,
37     NB_OMODES
38 };
39
40 typedef struct AudioNLMSContext {
41     const AVClass *class;
42
43     int order;
44     float mu;
45     float eps;
46     float leakage;
47     int output_mode;
48
49     int kernel_size;
50     AVFrame *offset;
51     AVFrame *delay;
52     AVFrame *coeffs;
53     AVFrame *tmp;
54
55     AVFrame *frame[2];
56
57     int anlmf;
58
59     AVFloatDSPContext *fdsp;
60 } AudioNLMSContext;
61
62 #define OFFSET(x) offsetof(AudioNLMSContext, x)
63 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
64 #define AT AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
65
66 static const AVOption anlms_options[] = {
67     { "order",   "set the filter order",   OFFSET(order),   AV_OPT_TYPE_INT,   {.i64=256},  1, INT16_MAX, A },
68     { "mu",      "set the filter mu",      OFFSET(mu),      AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 2, AT },
69     { "eps",     "set the filter eps",     OFFSET(eps),     AV_OPT_TYPE_FLOAT, {.dbl=1},    0, 1, AT },
70     { "leakage", "set the filter leakage", OFFSET(leakage), AV_OPT_TYPE_FLOAT, {.dbl=0},    0, 1, AT },
71     { "out_mode", "set output mode",       OFFSET(output_mode), AV_OPT_TYPE_INT, {.i64=OUT_MODE}, 0, NB_OMODES-1, AT, "mode" },
72     {  "i", "input",                 0,          AV_OPT_TYPE_CONST,    {.i64=IN_MODE},      0, 0, AT, "mode" },
73     {  "d", "desired",               0,          AV_OPT_TYPE_CONST,    {.i64=DESIRED_MODE}, 0, 0, AT, "mode" },
74     {  "o", "output",                0,          AV_OPT_TYPE_CONST,    {.i64=OUT_MODE},     0, 0, AT, "mode" },
75     {  "n", "noise",                 0,          AV_OPT_TYPE_CONST,    {.i64=NOISE_MODE},   0, 0, AT, "mode" },
76     {  "e", "error",                 0,          AV_OPT_TYPE_CONST,    {.i64=ERROR_MODE},   0, 0, AT, "mode" },
77     { NULL }
78 };
79
80 AVFILTER_DEFINE_CLASS_EXT(anlms, "anlm(f|s)", anlms_options);
81
82 static float fir_sample(AudioNLMSContext *s, float sample, float *delay,
83                         float *coeffs, float *tmp, int *offset)
84 {
85     const int order = s->order;
86     float output;
87
88     delay[*offset] = sample;
89
90     memcpy(tmp, coeffs + order - *offset, order * sizeof(float));
91
92     output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size);
93
94     if (--(*offset) < 0)
95         *offset = order - 1;
96
97     return output;
98 }
99
100 static float process_sample(AudioNLMSContext *s, float input, float desired,
101                             float *delay, float *coeffs, float *tmp, int *offsetp)
102 {
103     const int order = s->order;
104     const float leakage = s->leakage;
105     const float mu = s->mu;
106     const float a = 1.f - leakage;
107     float sum, output, e, norm, b;
108     int offset = *offsetp;
109
110     delay[offset + order] = input;
111
112     output = fir_sample(s, input, delay, coeffs, tmp, offsetp);
113     e = desired - output;
114
115     sum = s->fdsp->scalarproduct_float(delay, delay, s->kernel_size);
116
117     norm = s->eps + sum;
118     b = mu * e / norm;
119     if (s->anlmf)
120         b *= e * e;
121
122     memcpy(tmp, delay + offset, order * sizeof(float));
123
124     s->fdsp->vector_fmul_scalar(coeffs, coeffs, a, s->kernel_size);
125
126     s->fdsp->vector_fmac_scalar(coeffs, tmp, b, s->kernel_size);
127
128     memcpy(coeffs + order, coeffs, order * sizeof(float));
129
130     switch (s->output_mode) {
131     case IN_MODE:       output = input;         break;
132     case DESIRED_MODE:  output = desired;       break;
133     case OUT_MODE:   output = desired - output; break;
134     case NOISE_MODE: output = input - output;   break;
135     case ERROR_MODE:                            break;
136     }
137     return output;
138 }
139
140 static int process_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
141 {
142     AudioNLMSContext *s = ctx->priv;
143     AVFrame *out = arg;
144     const int start = (out->ch_layout.nb_channels * jobnr) / nb_jobs;
145     const int end = (out->ch_layout.nb_channels * (jobnr+1)) / nb_jobs;
146
147     for (int c = start; c < end; c++) {
148         const float *input = (const float *)s->frame[0]->extended_data[c];
149         const float *desired = (const float *)s->frame[1]->extended_data[c];
150         float *delay = (float *)s->delay->extended_data[c];
151         float *coeffs = (float *)s->coeffs->extended_data[c];
152         float *tmp = (float *)s->tmp->extended_data[c];
153         int *offset = (int *)s->offset->extended_data[c];
154         float *output = (float *)out->extended_data[c];
155
156         for (int n = 0; n < out->nb_samples; n++) {
157             output[n] = process_sample(s, input[n], desired[n], delay, coeffs, tmp, offset);
158             if (ctx->is_disabled)
159                 output[n] = input[n];
160         }
161     }
162
163     return 0;
164 }
165
166 static int activate(AVFilterContext *ctx)
167 {
168     AudioNLMSContext *s = ctx->priv;
169     int i, ret, status;
170     int nb_samples;
171     int64_t pts;
172
173     FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
174
175     nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[0]),
176                        ff_inlink_queued_samples(ctx->inputs[1]));
177     for (i = 0; i < ctx->nb_inputs && nb_samples > 0; i++) {
178         if (s->frame[i])
179             continue;
180
181         if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) {
182             ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->frame[i]);
183             if (ret < 0)
184                 return ret;
185         }
186     }
187
188     if (s->frame[0] && s->frame[1]) {
189         AVFrame *out;
190
191         out = ff_get_audio_buffer(ctx->outputs[0], s->frame[0]->nb_samples);
192         if (!out) {
193             av_frame_free(&s->frame[0]);
194             av_frame_free(&s->frame[1]);
195             return AVERROR(ENOMEM);
196         }
197
198         ff_filter_execute(ctx, process_channels, out, NULL,
199                           FFMIN(ctx->outputs[0]->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
200
201         out->pts = s->frame[0]->pts;
202
203         av_frame_free(&s->frame[0]);
204         av_frame_free(&s->frame[1]);
205
206         ret = ff_filter_frame(ctx->outputs[0], out);
207         if (ret < 0)
208             return ret;
209     }
210
211     if (!nb_samples) {
212         for (i = 0; i < 2; i++) {
213             if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
214                 ff_outlink_set_status(ctx->outputs[0], status, pts);
215                 return 0;
216             }
217         }
218     }
219
220     if (ff_outlink_frame_wanted(ctx->outputs[0])) {
221         for (i = 0; i < 2; i++) {
222             if (ff_inlink_queued_samples(ctx->inputs[i]) > 0)
223                 continue;
224             ff_inlink_request_frame(ctx->inputs[i]);
225             return 0;
226         }
227     }
228     return 0;
229 }
230
231 static int config_output(AVFilterLink *outlink)
232 {
233     AVFilterContext *ctx = outlink->src;
234     AudioNLMSContext *s = ctx->priv;
235
236     s->anlmf = !strcmp(ctx->filter->name, "anlmf");
237     s->kernel_size = FFALIGN(s->order, 16);
238
239     if (!s->offset)
240         s->offset = ff_get_audio_buffer(outlink, 1);
241     if (!s->delay)
242         s->delay = ff_get_audio_buffer(outlink, 2 * s->kernel_size);
243     if (!s->coeffs)
244         s->coeffs = ff_get_audio_buffer(outlink, 2 * s->kernel_size);
245     if (!s->tmp)
246         s->tmp = ff_get_audio_buffer(outlink, s->kernel_size);
247     if (!s->delay || !s->coeffs || !s->offset || !s->tmp)
248         return AVERROR(ENOMEM);
249
250     return 0;
251 }
252
253 static av_cold int init(AVFilterContext *ctx)
254 {
255     AudioNLMSContext *s = ctx->priv;
256
257     s->fdsp = avpriv_float_dsp_alloc(0);
258     if (!s->fdsp)
259         return AVERROR(ENOMEM);
260
261     return 0;
262 }
263
264 static av_cold void uninit(AVFilterContext *ctx)
265 {
266     AudioNLMSContext *s = ctx->priv;
267
268     av_freep(&s->fdsp);
269     av_frame_free(&s->delay);
270     av_frame_free(&s->coeffs);
271     av_frame_free(&s->offset);
272     av_frame_free(&s->tmp);
273 }
274
275 static const AVFilterPad inputs[] = {
276     {
277         .name = "input",
278         .type = AVMEDIA_TYPE_AUDIO,
279     },
280     {
281         .name = "desired",
282         .type = AVMEDIA_TYPE_AUDIO,
283     },
284 };
285
286 static const AVFilterPad outputs[] = {
287     {
288         .name         = "default",
289         .type         = AVMEDIA_TYPE_AUDIO,
290         .config_props = config_output,
291     },
292 };
293
294 const AVFilter ff_af_anlms = {
295     .name           = "anlms",
296     .description    = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Squares algorithm to first audio stream."),
297     .priv_size      = sizeof(AudioNLMSContext),
298     .priv_class     = &anlms_class,
299     .init           = init,
300     .uninit         = uninit,
301     .activate       = activate,
302     FILTER_INPUTS(inputs),
303     FILTER_OUTPUTS(outputs),
304     FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP),
305     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
306                       AVFILTER_FLAG_SLICE_THREADS,
307     .process_command = ff_filter_process_command,
308 };
309
310 const AVFilter ff_af_anlmf = {
311     .name           = "anlmf",
312     .description    = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Fourth algorithm to first audio stream."),
313     .priv_size      = sizeof(AudioNLMSContext),
314     .priv_class     = &anlms_class,
315     .init           = init,
316     .uninit         = uninit,
317     .activate       = activate,
318     FILTER_INPUTS(inputs),
319     FILTER_OUTPUTS(outputs),
320     FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_FLTP),
321     .flags          = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
322                       AVFILTER_FLAG_SLICE_THREADS,
323     .process_command = ff_filter_process_command,
324 };