FFmpeg  4.4.6
af_anlms.c
Go to the documentation of this file.
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/avassert.h"
23 #include "libavutil/common.h"
24 #include "libavutil/float_dsp.h"
25 #include "libavutil/opt.h"
26 
27 #include "audio.h"
28 #include "avfilter.h"
29 #include "formats.h"
30 #include "filters.h"
31 #include "internal.h"
32 
33 enum OutModes {
38  NB_OMODES
39 };
40 
41 typedef struct AudioNLMSContext {
42  const AVClass *class;
43 
44  int order;
45  float mu;
46  float eps;
47  float leakage;
49 
55 
57 
60 
61 #define OFFSET(x) offsetof(AudioNLMSContext, x)
62 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
63 #define AT AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
64 
65 static const AVOption anlms_options[] = {
66  { "order", "set the filter order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=256}, 1, INT16_MAX, A },
67  { "mu", "set the filter mu", OFFSET(mu), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 2, AT },
68  { "eps", "set the filter eps", OFFSET(eps), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AT },
69  { "leakage", "set the filter leakage", OFFSET(leakage), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, AT },
70  { "out_mode", "set output mode", OFFSET(output_mode), AV_OPT_TYPE_INT, {.i64=OUT_MODE}, 0, NB_OMODES-1, AT, "mode" },
71  { "i", "input", 0, AV_OPT_TYPE_CONST, {.i64=IN_MODE}, 0, 0, AT, "mode" },
72  { "d", "desired", 0, AV_OPT_TYPE_CONST, {.i64=DESIRED_MODE}, 0, 0, AT, "mode" },
73  { "o", "output", 0, AV_OPT_TYPE_CONST, {.i64=OUT_MODE}, 0, 0, AT, "mode" },
74  { "n", "noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_MODE}, 0, 0, AT, "mode" },
75  { NULL }
76 };
77 
79 
81 {
84  static const enum AVSampleFormat sample_fmts[] = {
87  };
88  int ret;
89 
91  if (!layouts)
92  return AVERROR(ENOMEM);
94  if (ret < 0)
95  return ret;
96 
98  if (!formats)
99  return AVERROR(ENOMEM);
101  if (ret < 0)
102  return ret;
103 
105  if (!formats)
106  return AVERROR(ENOMEM);
108 }
109 
110 static float fir_sample(AudioNLMSContext *s, float sample, float *delay,
111  float *coeffs, float *tmp, int *offset)
112 {
113  const int order = s->order;
114  float output;
115 
116  delay[*offset] = sample;
117 
118  memcpy(tmp, coeffs + order - *offset, order * sizeof(float));
119 
120  output = s->fdsp->scalarproduct_float(delay, tmp, s->kernel_size);
121 
122  if (--(*offset) < 0)
123  *offset = order - 1;
124 
125  return output;
126 }
127 
128 static float process_sample(AudioNLMSContext *s, float input, float desired,
129  float *delay, float *coeffs, float *tmp, int *offsetp)
130 {
131  const int order = s->order;
132  const float leakage = s->leakage;
133  const float mu = s->mu;
134  const float a = 1.f - leakage * mu;
135  float sum, output, e, norm, b;
136  int offset = *offsetp;
137 
138  delay[offset + order] = input;
139 
140  output = fir_sample(s, input, delay, coeffs, tmp, offsetp);
141  e = desired - output;
142 
143  sum = s->fdsp->scalarproduct_float(delay, delay, s->kernel_size);
144 
145  norm = s->eps + sum;
146  b = mu * e / norm;
147 
148  memcpy(tmp, delay + offset, order * sizeof(float));
149 
150  s->fdsp->vector_fmul_scalar(coeffs, coeffs, a, s->kernel_size);
151 
152  s->fdsp->vector_fmac_scalar(coeffs, tmp, b, s->kernel_size);
153 
154  memcpy(coeffs + order, coeffs, order * sizeof(float));
155 
156  switch (s->output_mode) {
157  case IN_MODE: output = input; break;
158  case DESIRED_MODE: output = desired; break;
159  case OUT_MODE: /*output = output;*/ break;
160  case NOISE_MODE: output = desired - output; break;
161  }
162  return output;
163 }
164 
165 static int process_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
166 {
167  AudioNLMSContext *s = ctx->priv;
168  AVFrame *out = arg;
169  const int start = (out->channels * jobnr) / nb_jobs;
170  const int end = (out->channels * (jobnr+1)) / nb_jobs;
171 
172  for (int c = start; c < end; c++) {
173  const float *input = (const float *)s->frame[0]->extended_data[c];
174  const float *desired = (const float *)s->frame[1]->extended_data[c];
175  float *delay = (float *)s->delay->extended_data[c];
176  float *coeffs = (float *)s->coeffs->extended_data[c];
177  float *tmp = (float *)s->tmp->extended_data[c];
178  int *offset = (int *)s->offset->extended_data[c];
179  float *output = (float *)out->extended_data[c];
180 
181  for (int n = 0; n < out->nb_samples; n++)
182  output[n] = process_sample(s, input[n], desired[n], delay, coeffs, tmp, offset);
183  }
184 
185  return 0;
186 }
187 
189 {
190  AudioNLMSContext *s = ctx->priv;
191  int i, ret, status;
192  int nb_samples;
193  int64_t pts;
194 
196 
197  nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[0]),
198  ff_inlink_queued_samples(ctx->inputs[1]));
199  for (i = 0; i < ctx->nb_inputs && nb_samples > 0; i++) {
200  if (s->frame[i])
201  continue;
202 
203  if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) {
204  ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->frame[i]);
205  if (ret < 0)
206  return ret;
207  }
208  }
209 
210  if (s->frame[0] && s->frame[1]) {
211  AVFrame *out;
212 
213  out = ff_get_audio_buffer(ctx->outputs[0], s->frame[0]->nb_samples);
214  if (!out) {
215  av_frame_free(&s->frame[0]);
216  av_frame_free(&s->frame[1]);
217  return AVERROR(ENOMEM);
218  }
219 
220  ctx->internal->execute(ctx, process_channels, out, NULL, FFMIN(ctx->outputs[0]->channels,
222 
223  out->pts = s->frame[0]->pts;
224 
225  av_frame_free(&s->frame[0]);
226  av_frame_free(&s->frame[1]);
227 
228  ret = ff_filter_frame(ctx->outputs[0], out);
229  if (ret < 0)
230  return ret;
231  }
232 
233  if (!nb_samples) {
234  for (i = 0; i < 2; i++) {
235  if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
236  ff_outlink_set_status(ctx->outputs[0], status, pts);
237  return 0;
238  }
239  }
240  }
241 
242  if (ff_outlink_frame_wanted(ctx->outputs[0])) {
243  for (i = 0; i < 2; i++) {
244  if (ff_inlink_queued_samples(ctx->inputs[i]) > 0)
245  continue;
246  ff_inlink_request_frame(ctx->inputs[i]);
247  return 0;
248  }
249  }
250  return 0;
251 }
252 
253 static int config_output(AVFilterLink *outlink)
254 {
255  AVFilterContext *ctx = outlink->src;
256  AudioNLMSContext *s = ctx->priv;
257 
258  s->kernel_size = FFALIGN(s->order, 16);
259 
260  if (!s->offset)
261  s->offset = ff_get_audio_buffer(outlink, 1);
262  if (!s->delay)
263  s->delay = ff_get_audio_buffer(outlink, 2 * s->kernel_size);
264  if (!s->coeffs)
265  s->coeffs = ff_get_audio_buffer(outlink, 2 * s->kernel_size);
266  if (!s->tmp)
267  s->tmp = ff_get_audio_buffer(outlink, s->kernel_size);
268  if (!s->delay || !s->coeffs || !s->offset || !s->tmp)
269  return AVERROR(ENOMEM);
270 
271  return 0;
272 }
273 
275 {
276  AudioNLMSContext *s = ctx->priv;
277 
278  s->fdsp = avpriv_float_dsp_alloc(0);
279  if (!s->fdsp)
280  return AVERROR(ENOMEM);
281 
282  return 0;
283 }
284 
286 {
287  AudioNLMSContext *s = ctx->priv;
288 
289  av_freep(&s->fdsp);
290  av_frame_free(&s->delay);
291  av_frame_free(&s->coeffs);
292  av_frame_free(&s->offset);
293  av_frame_free(&s->tmp);
294 }
295 
296 static const AVFilterPad inputs[] = {
297  {
298  .name = "input",
299  .type = AVMEDIA_TYPE_AUDIO,
300  },
301  {
302  .name = "desired",
303  .type = AVMEDIA_TYPE_AUDIO,
304  },
305  { NULL }
306 };
307 
308 static const AVFilterPad outputs[] = {
309  {
310  .name = "default",
311  .type = AVMEDIA_TYPE_AUDIO,
312  .config_props = config_output,
313  },
314  { NULL }
315 };
316 
318  .name = "anlms",
319  .description = NULL_IF_CONFIG_SMALL("Apply Normalized Least-Mean-Squares algorithm to first audio stream."),
320  .priv_size = sizeof(AudioNLMSContext),
321  .priv_class = &anlms_class,
322  .init = init,
323  .uninit = uninit,
324  .activate = activate,
326  .inputs = inputs,
327  .outputs = outputs,
330 };
static enum AVSampleFormat sample_fmts[]
Definition: adpcmenc.c:925
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: af_acrusher.c:336
OutModes
Definition: af_afftdn.c:37
static const AVOption anlms_options[]
Definition: af_anlms.c:65
static float fir_sample(AudioNLMSContext *s, float sample, float *delay, float *coeffs, float *tmp, int *offset)
Definition: af_anlms.c:110
AVFilter ff_af_anlms
Definition: af_anlms.c:317
AVFILTER_DEFINE_CLASS(anlms)
static int process_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition: af_anlms.c:165
@ NOISE_MODE
Definition: af_anlms.c:37
@ IN_MODE
Definition: af_anlms.c:34
@ DESIRED_MODE
Definition: af_anlms.c:35
@ NB_OMODES
Definition: af_anlms.c:38
@ OUT_MODE
Definition: af_anlms.c:36
static int query_formats(AVFilterContext *ctx)
Definition: af_anlms.c:80
static const AVFilterPad inputs[]
Definition: af_anlms.c:296
static const AVFilterPad outputs[]
Definition: af_anlms.c:308
#define A
Definition: af_anlms.c:62
static float process_sample(AudioNLMSContext *s, float input, float desired, float *delay, float *coeffs, float *tmp, int *offsetp)
Definition: af_anlms.c:128
static int activate(AVFilterContext *ctx)
Definition: af_anlms.c:188
static av_cold int init(AVFilterContext *ctx)
Definition: af_anlms.c:274
static av_cold void uninit(AVFilterContext *ctx)
Definition: af_anlms.c:285
#define OFFSET(x)
Definition: af_anlms.c:61
static int config_output(AVFilterLink *outlink)
Definition: af_anlms.c:253
#define AT
Definition: af_anlms.c:63
#define av_cold
Definition: attributes.h:88
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:86
simple assert() macros that are a bit more flexible than ISO C assert().
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition: avfilter.c:1449
int ff_inlink_check_available_samples(AVFilterLink *link, unsigned min)
Test if enough samples are available on the link.
Definition: avfilter.c:1479
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1096
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition: avfilter.c:882
int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe)
Take samples from the link's FIFO and update the link's stats.
Definition: avfilter.c:1513
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition: avfilter.c:802
int ff_inlink_queued_samples(AVFilterLink *link)
Definition: avfilter.c:1474
void ff_inlink_request_frame(AVFilterLink *link)
Mark that a frame is wanted on the link.
Definition: avfilter.c:1620
Main libavfilter public API header.
#define flags(name, subs,...)
Definition: cbs_av1.c:572
#define s(width, name)
Definition: cbs_vp9.c:257
audio channel layout utility functions
common internal and external API header
#define FFMIN(a, b)
Definition: common.h:105
#define NULL
Definition: coverity.c:32
long long int64_t
Definition: coverity.c:34
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition: filters.h:189
#define FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, filter)
Forward the status on an output link to all input links.
Definition: filters.h:212
static int ff_outlink_frame_wanted(AVFilterLink *link)
Test if a frame is wanted on an output link.
Definition: filters.h:172
#define sample
AVFilterChannelLayouts * ff_all_channel_counts(void)
Construct an AVFilterChannelLayouts coding for any channel layout, with known or unknown disposition.
Definition: formats.c:436
int ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:587
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:286
int ff_set_common_samplerates(AVFilterContext *ctx, AVFilterFormats *samplerates)
Definition: formats.c:575
int ff_set_common_channel_layouts(AVFilterContext *ctx, AVFilterChannelLayouts *channel_layouts)
A helper for query_formats() which sets all links to the same list of channel layouts/sample rates.
Definition: formats.c:568
AVFilterFormats * ff_all_samplerates(void)
Definition: formats.c:421
@ AV_OPT_TYPE_CONST
Definition: opt.h:234
@ AV_OPT_TYPE_INT
Definition: opt.h:225
@ AV_OPT_TYPE_FLOAT
Definition: opt.h:228
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition: avfilter.h:117
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVSampleFormat
Audio sample formats.
Definition: samplefmt.h:58
@ AV_SAMPLE_FMT_FLTP
float, planar
Definition: samplefmt.h:69
@ AV_SAMPLE_FMT_NONE
Definition: samplefmt.h:59
for(j=16;j >0;--j)
int i
Definition: input.c:407
const char * arg
Definition: jacosubdec.c:66
av_cold AVFloatDSPContext * avpriv_float_dsp_alloc(int bit_exact)
Allocate a float DSP context.
Definition: float_dsp.c:135
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
#define FFALIGN(x, a)
Definition: macros.h:48
enum MovChannelLayoutTag * layouts
Definition: mov_chan.c:434
AVOptions.
formats
Definition: signature.h:48
Describe the class of an AVClass context structure.
Definition: log.h:67
A list of supported channel layouts.
Definition: formats.h:86
An instance of a filter.
Definition: avfilter.h:341
A list of supported formats for one end of a filter link.
Definition: formats.h:65
A filter pad used for either input or output.
Definition: internal.h:54
const char * name
Pad name.
Definition: internal.h:60
Filter definition.
Definition: avfilter.h:145
const char * name
Filter name.
Definition: avfilter.h:149
AVFormatInternal * internal
An opaque field for libavformat internal usage.
Definition: avformat.h:1699
This structure describes decoded (raw) audio or video data.
Definition: frame.h:318
AVOption.
Definition: opt.h:248
AVFloatDSPContext * fdsp
Definition: af_anlms.c:58
AVFrame * delay
Definition: af_anlms.c:52
AVFrame * frame[2]
Definition: af_anlms.c:56
AVFrame * offset
Definition: af_anlms.c:51
AVFrame * tmp
Definition: af_anlms.c:54
AVFrame * coeffs
Definition: af_anlms.c:53
#define av_freep(p)
static uint8_t tmp[11]
Definition: aes_ctr.c:27
FILE * out
Definition: movenc.c:54
AVFormatContext * ctx
Definition: movenc.c:48
static int64_t pts
const char * b
Definition: vf_curves.c:118
static const uint8_t offset[127][2]
Definition: vf_spp.c:107
static double c[64]