FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/af_arls.c
Date: 2024-04-18 20:30:25
Exec Total Coverage
Lines: 0 105 0.0%
Functions: 0 5 0.0%
Branches: 0 93 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2023 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/common.h"
22 #include "libavutil/float_dsp.h"
23 #include "libavutil/mem.h"
24 #include "libavutil/opt.h"
25
26 #include "audio.h"
27 #include "avfilter.h"
28 #include "formats.h"
29 #include "filters.h"
30 #include "internal.h"
31
32 enum OutModes {
33 IN_MODE,
34 DESIRED_MODE,
35 OUT_MODE,
36 NOISE_MODE,
37 ERROR_MODE,
38 NB_OMODES
39 };
40
41 typedef struct AudioRLSContext {
42 const AVClass *class;
43
44 int order;
45 float lambda;
46 float delta;
47 int output_mode;
48 int precision;
49
50 int kernel_size;
51 AVFrame *offset;
52 AVFrame *delay;
53 AVFrame *coeffs;
54 AVFrame *p, *dp;
55 AVFrame *gains;
56 AVFrame *u, *tmp;
57
58 AVFrame *frame[2];
59
60 int (*filter_channels)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs);
61
62 AVFloatDSPContext *fdsp;
63 } AudioRLSContext;
64
65 #define OFFSET(x) offsetof(AudioRLSContext, x)
66 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
67 #define AT AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
68
69 static const AVOption arls_options[] = {
70 { "order", "set the filter order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=16}, 1, INT16_MAX, A },
71 { "lambda", "set the filter lambda", OFFSET(lambda), AV_OPT_TYPE_FLOAT, {.dbl=1.f}, 0, 1, AT },
72 { "delta", "set the filter delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=2.f}, 0, INT16_MAX, A },
73 { "out_mode", "set output mode", OFFSET(output_mode), AV_OPT_TYPE_INT, {.i64=OUT_MODE}, 0, NB_OMODES-1, AT, .unit = "mode" },
74 { "i", "input", 0, AV_OPT_TYPE_CONST, {.i64=IN_MODE}, 0, 0, AT, .unit = "mode" },
75 { "d", "desired", 0, AV_OPT_TYPE_CONST, {.i64=DESIRED_MODE}, 0, 0, AT, .unit = "mode" },
76 { "o", "output", 0, AV_OPT_TYPE_CONST, {.i64=OUT_MODE}, 0, 0, AT, .unit = "mode" },
77 { "n", "noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_MODE}, 0, 0, AT, .unit = "mode" },
78 { "e", "error", 0, AV_OPT_TYPE_CONST, {.i64=ERROR_MODE}, 0, 0, AT, .unit = "mode" },
79 { "precision", "set processing precision", OFFSET(precision), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, A, .unit = "precision" },
80 { "auto", "set auto processing precision", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, .unit = "precision" },
81 { "float", "set single-floating point processing precision", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, .unit = "precision" },
82 { "double","set double-floating point processing precision", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, A, .unit = "precision" },
83 { NULL }
84 };
85
86 AVFILTER_DEFINE_CLASS(arls);
87
88 static int query_formats(AVFilterContext *ctx)
89 {
90 AudioRLSContext *s = ctx->priv;
91 static const enum AVSampleFormat sample_fmts[3][3] = {
92 { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE },
93 { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE },
94 { AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE },
95 };
96 int ret;
97
98 if ((ret = ff_set_common_all_channel_counts(ctx)) < 0)
99 return ret;
100
101 if ((ret = ff_set_common_formats_from_list(ctx, sample_fmts[s->precision])) < 0)
102 return ret;
103
104 return ff_set_common_all_samplerates(ctx);
105 }
106
107 static int activate(AVFilterContext *ctx)
108 {
109 AudioRLSContext *s = ctx->priv;
110 int i, ret, status;
111 int nb_samples;
112 int64_t pts;
113
114 FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx);
115
116 nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[0]),
117 ff_inlink_queued_samples(ctx->inputs[1]));
118 for (i = 0; i < ctx->nb_inputs && nb_samples > 0; i++) {
119 if (s->frame[i])
120 continue;
121
122 if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) {
123 ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->frame[i]);
124 if (ret < 0)
125 return ret;
126 }
127 }
128
129 if (s->frame[0] && s->frame[1]) {
130 AVFrame *out;
131
132 out = ff_get_audio_buffer(ctx->outputs[0], s->frame[0]->nb_samples);
133 if (!out) {
134 av_frame_free(&s->frame[0]);
135 av_frame_free(&s->frame[1]);
136 return AVERROR(ENOMEM);
137 }
138
139 ff_filter_execute(ctx, s->filter_channels, out, NULL,
140 FFMIN(ctx->outputs[0]->ch_layout.nb_channels, ff_filter_get_nb_threads(ctx)));
141
142 out->pts = s->frame[0]->pts;
143 out->duration = s->frame[0]->duration;
144
145 av_frame_free(&s->frame[0]);
146 av_frame_free(&s->frame[1]);
147
148 ret = ff_filter_frame(ctx->outputs[0], out);
149 if (ret < 0)
150 return ret;
151 }
152
153 if (!nb_samples) {
154 for (i = 0; i < 2; i++) {
155 if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) {
156 ff_outlink_set_status(ctx->outputs[0], status, pts);
157 return 0;
158 }
159 }
160 }
161
162 if (ff_outlink_frame_wanted(ctx->outputs[0])) {
163 for (i = 0; i < 2; i++) {
164 if (s->frame[i] || ff_inlink_queued_samples(ctx->inputs[i]) > 0)
165 continue;
166 ff_inlink_request_frame(ctx->inputs[i]);
167 return 0;
168 }
169 }
170 return 0;
171 }
172
173 #define DEPTH 32
174 #include "arls_template.c"
175
176 #undef DEPTH
177 #define DEPTH 64
178 #include "arls_template.c"
179
180 static int config_output(AVFilterLink *outlink)
181 {
182 AVFilterContext *ctx = outlink->src;
183 AudioRLSContext *s = ctx->priv;
184
185 s->kernel_size = FFALIGN(s->order, 16);
186
187 if (!s->offset)
188 s->offset = ff_get_audio_buffer(outlink, 1);
189 if (!s->delay)
190 s->delay = ff_get_audio_buffer(outlink, 2 * s->kernel_size);
191 if (!s->coeffs)
192 s->coeffs = ff_get_audio_buffer(outlink, 2 * s->kernel_size);
193 if (!s->gains)
194 s->gains = ff_get_audio_buffer(outlink, s->kernel_size);
195 if (!s->p)
196 s->p = ff_get_audio_buffer(outlink, s->kernel_size * s->kernel_size);
197 if (!s->dp)
198 s->dp = ff_get_audio_buffer(outlink, s->kernel_size * s->kernel_size);
199 if (!s->u)
200 s->u = ff_get_audio_buffer(outlink, s->kernel_size);
201 if (!s->tmp)
202 s->tmp = ff_get_audio_buffer(outlink, s->kernel_size);
203
204 if (!s->delay || !s->coeffs || !s->p || !s->dp || !s->gains || !s->offset || !s->u || !s->tmp)
205 return AVERROR(ENOMEM);
206
207 for (int ch = 0; ch < s->offset->ch_layout.nb_channels; ch++) {
208 int *dst = (int *)s->offset->extended_data[ch];
209
210 for (int i = 0; i < s->kernel_size; i++)
211 dst[0] = s->kernel_size - 1;
212 }
213
214 switch (outlink->format) {
215 case AV_SAMPLE_FMT_DBLP:
216 for (int ch = 0; ch < s->p->ch_layout.nb_channels; ch++) {
217 double *dst = (double *)s->p->extended_data[ch];
218
219 for (int i = 0; i < s->kernel_size; i++)
220 dst[i * s->kernel_size + i] = s->delta;
221 }
222
223 s->filter_channels = filter_channels_double;
224 break;
225 case AV_SAMPLE_FMT_FLTP:
226 for (int ch = 0; ch < s->p->ch_layout.nb_channels; ch++) {
227 float *dst = (float *)s->p->extended_data[ch];
228
229 for (int i = 0; i < s->kernel_size; i++)
230 dst[i * s->kernel_size + i] = s->delta;
231 }
232
233 s->filter_channels = filter_channels_float;
234 break;
235 }
236
237 return 0;
238 }
239
240 static av_cold int init(AVFilterContext *ctx)
241 {
242 AudioRLSContext *s = ctx->priv;
243
244 s->fdsp = avpriv_float_dsp_alloc(0);
245 if (!s->fdsp)
246 return AVERROR(ENOMEM);
247
248 return 0;
249 }
250
251 static av_cold void uninit(AVFilterContext *ctx)
252 {
253 AudioRLSContext *s = ctx->priv;
254
255 av_freep(&s->fdsp);
256 av_frame_free(&s->delay);
257 av_frame_free(&s->coeffs);
258 av_frame_free(&s->gains);
259 av_frame_free(&s->offset);
260 av_frame_free(&s->p);
261 av_frame_free(&s->dp);
262 av_frame_free(&s->u);
263 av_frame_free(&s->tmp);
264 }
265
266 static const AVFilterPad inputs[] = {
267 {
268 .name = "input",
269 .type = AVMEDIA_TYPE_AUDIO,
270 },
271 {
272 .name = "desired",
273 .type = AVMEDIA_TYPE_AUDIO,
274 },
275 };
276
277 static const AVFilterPad outputs[] = {
278 {
279 .name = "default",
280 .type = AVMEDIA_TYPE_AUDIO,
281 .config_props = config_output,
282 },
283 };
284
285 const AVFilter ff_af_arls = {
286 .name = "arls",
287 .description = NULL_IF_CONFIG_SMALL("Apply Recursive Least Squares algorithm to first audio stream."),
288 .priv_size = sizeof(AudioRLSContext),
289 .priv_class = &arls_class,
290 .init = init,
291 .uninit = uninit,
292 .activate = activate,
293 FILTER_INPUTS(inputs),
294 FILTER_OUTPUTS(outputs),
295 FILTER_QUERY_FUNC(query_formats),
296 .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL |
297 AVFILTER_FLAG_SLICE_THREADS,
298 .process_command = ff_filter_process_command,
299 };
300