FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavfilter/af_mcompand.c
Date: 2026-09-25 23:13:28
Exec Total Coverage
Lines: 0 307 0.0%
Functions: 0 12 0.0%
Branches: 0 136 0.0%

Line Branch Exec Source
1 /*
2 * COpyright (c) 2002 Daniel Pouzzner
3 * Copyright (c) 1999 Chris Bagwell
4 * Copyright (c) 1999 Nick Bailey
5 * Copyright (c) 2007 Rob Sykes <robs@users.sourceforge.net>
6 * Copyright (c) 2013 Paul B Mahol
7 * Copyright (c) 2014 Andrew Kelley
8 *
9 * This file is part of FFmpeg.
10 *
11 * FFmpeg is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * FFmpeg is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with FFmpeg; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 */
25
26 /**
27 * @file
28 * audio multiband compand filter
29 */
30
31 #include "libavutil/avstring.h"
32 #include "libavutil/ffmath.h"
33 #include "libavutil/mem.h"
34 #include "libavutil/opt.h"
35 #include "libavutil/samplefmt.h"
36 #include "audio.h"
37 #include "avfilter.h"
38 #include "filters.h"
39
40 typedef struct CompandSegment {
41 double x, y;
42 double a, b;
43 } CompandSegment;
44
45 typedef struct CompandT {
46 CompandSegment *segments;
47 int nb_segments;
48 double in_min_lin;
49 double out_min_lin;
50 double curve_dB;
51 double gain_dB;
52 } CompandT;
53
54 #define N 4
55
56 typedef struct PrevCrossover {
57 double in;
58 double out_low;
59 double out_high;
60 } PrevCrossover[N * 2];
61
62 typedef struct Crossover {
63 PrevCrossover *previous;
64 size_t pos;
65 double coefs[3 *(N+1)];
66 } Crossover;
67
68 typedef struct CompBand {
69 CompandT transfer_fn;
70 double *attack_rate;
71 double *decay_rate;
72 double *volume;
73 double delay;
74 double topfreq;
75 Crossover filter;
76 AVFrame *delay_buf;
77 size_t delay_size;
78 ptrdiff_t delay_buf_ptr;
79 size_t delay_buf_cnt;
80 } CompBand;
81
82 typedef struct MCompandContext {
83 const AVClass *class;
84
85 char *args;
86
87 int nb_bands;
88 CompBand *bands;
89 AVFrame *band_buf1, *band_buf2, *band_buf3;
90 int band_samples;
91 size_t delay_buf_size;
92 } MCompandContext;
93
94 #define OFFSET(x) offsetof(MCompandContext, x)
95 #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
96
97 static const AVOption mcompand_options[] = {
98 { "args", "set parameters for each band", OFFSET(args), AV_OPT_TYPE_STRING, { .str = "0.005,0.1 6 -47/-40,-34/-34,-17/-33 100 | 0.003,0.05 6 -47/-40,-34/-34,-17/-33 400 | 0.000625,0.0125 6 -47/-40,-34/-34,-15/-33 1600 | 0.0001,0.025 6 -47/-40,-34/-34,-31/-31,-0/-30 6400 | 0,0.025 6 -38/-31,-28/-28,-0/-25 22000" }, 0, 0, A },
99 { NULL }
100 };
101
102 AVFILTER_DEFINE_CLASS(mcompand);
103
104 ✗ static av_cold void uninit(AVFilterContext *ctx)
105 {
106 ✗ MCompandContext *s = ctx->priv;
107 int i;
108
109 ✗ av_frame_free(&s->band_buf1);
110 ✗ av_frame_free(&s->band_buf2);
111 ✗ av_frame_free(&s->band_buf3);
112
113 ✗ if (s->bands) {
114 ✗ for (i = 0; i < s->nb_bands; i++) {
115 ✗ av_freep(&s->bands[i].attack_rate);
116 ✗ av_freep(&s->bands[i].decay_rate);
117 ✗ av_freep(&s->bands[i].volume);
118 ✗ av_freep(&s->bands[i].transfer_fn.segments);
119 ✗ av_freep(&s->bands[i].filter.previous);
120 ✗ av_frame_free(&s->bands[i].delay_buf);
121 }
122 }
123 ✗ av_freep(&s->bands);
124 ✗ }
125
126 ✗ static void count_items(char *item_str, int *nb_items, char delimiter)
127 {
128 char *p;
129
130 ✗ *nb_items = 1;
131 ✗ for (p = item_str; *p; p++) {
132 ✗ if (*p == delimiter)
133 ✗ (*nb_items)++;
134 }
135 ✗ }
136
137 ✗ static void update_volume(CompBand *cb, double in, int ch)
138 {
139 ✗ double delta = in - cb->volume[ch];
140
141 ✗ if (delta > 0.0)
142 ✗ cb->volume[ch] += delta * cb->attack_rate[ch];
143 else
144 ✗ cb->volume[ch] += delta * cb->decay_rate[ch];
145 ✗ }
146
147 ✗ static double get_volume(CompandT *s, double in_lin)
148 {
149 CompandSegment *cs;
150 double in_log, out_log;
151 int i;
152
153 ✗ if (in_lin <= s->in_min_lin)
154 ✗ return s->out_min_lin;
155
156 ✗ in_log = log(in_lin);
157
158 ✗ for (i = 1; i < s->nb_segments; i++)
159 ✗ if (in_log <= s->segments[i].x)
160 ✗ break;
161 ✗ cs = &s->segments[i - 1];
162 ✗ in_log -= cs->x;
163 ✗ out_log = cs->y + in_log * (cs->a * in_log + cs->b);
164
165 ✗ return exp(out_log);
166 }
167
168 ✗ static int parse_points(char *points, int nb_points, double radius,
169 CompandT *s, AVFilterContext *ctx)
170 {
171 int new_nb_items, num;
172 ✗ char *saveptr = NULL;
173 ✗ char *p = points;
174 int i;
175
176 #define S(x) s->segments[2 * ((x) + 1)]
177 ✗ for (i = 0, new_nb_items = 0; i < nb_points; i++) {
178 ✗ char *tstr = av_strtok(p, ",", &saveptr);
179 ✗ p = NULL;
180 ✗ if (!tstr || sscanf(tstr, "%lf/%lf", &S(i).x, &S(i).y) != 2) {
181 ✗ av_log(ctx, AV_LOG_ERROR,
182 "Invalid and/or missing input/output value.\n");
183 ✗ return AVERROR(EINVAL);
184 }
185 ✗ if (i && S(i - 1).x > S(i).x) {
186 ✗ av_log(ctx, AV_LOG_ERROR,
187 "Transfer function input values must be increasing.\n");
188 ✗ return AVERROR(EINVAL);
189 }
190 ✗ S(i).y -= S(i).x;
191 ✗ av_log(ctx, AV_LOG_DEBUG, "%d: x=%f y=%f\n", i, S(i).x, S(i).y);
192 ✗ new_nb_items++;
193 }
194 ✗ num = new_nb_items;
195
196 /* Add 0,0 if necessary */
197 ✗ if (num == 0 || S(num - 1).x)
198 ✗ num++;
199
200 #undef S
201 #define S(x) s->segments[2 * (x)]
202 /* Add a tail off segment at the start */
203 ✗ S(0).x = S(1).x - 2 * s->curve_dB;
204 ✗ S(0).y = S(1).y;
205 ✗ num++;
206
207 /* Join adjacent colinear segments */
208 ✗ for (i = 2; i < num; i++) {
209 ✗ double g1 = (S(i - 1).y - S(i - 2).y) * (S(i - 0).x - S(i - 1).x);
210 ✗ double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x);
211 int j;
212
213 ✗ if (fabs(g1 - g2))
214 ✗ continue;
215 ✗ num--;
216 ✗ for (j = --i; j < num; j++)
217 ✗ S(j) = S(j + 1);
218 }
219
220 ✗ for (i = 0; i < s->nb_segments; i += 2) {
221 ✗ s->segments[i].y += s->gain_dB;
222 ✗ s->segments[i].x *= M_LN10 / 20;
223 ✗ s->segments[i].y *= M_LN10 / 20;
224 }
225
226 #define L(x) s->segments[i - (x)]
227 ✗ for (i = 4; i < s->nb_segments; i += 2) {
228 double x, y, cx, cy, in1, in2, out1, out2, theta, len, r;
229
230 ✗ L(4).a = 0;
231 ✗ L(4).b = (L(2).y - L(4).y) / (L(2).x - L(4).x);
232
233 ✗ L(2).a = 0;
234 ✗ L(2).b = (L(0).y - L(2).y) / (L(0).x - L(2).x);
235
236 ✗ theta = atan2(L(2).y - L(4).y, L(2).x - L(4).x);
237 ✗ len = hypot(L(2).x - L(4).x, L(2).y - L(4).y);
238 ✗ r = FFMIN(radius, len);
239 ✗ L(3).x = L(2).x - r * cos(theta);
240 ✗ L(3).y = L(2).y - r * sin(theta);
241
242 ✗ theta = atan2(L(0).y - L(2).y, L(0).x - L(2).x);
243 ✗ len = hypot(L(0).x - L(2).x, L(0).y - L(2).y);
244 ✗ r = FFMIN(radius, len / 2);
245 ✗ x = L(2).x + r * cos(theta);
246 ✗ y = L(2).y + r * sin(theta);
247
248 ✗ cx = (L(3).x + L(2).x + x) / 3;
249 ✗ cy = (L(3).y + L(2).y + y) / 3;
250
251 ✗ L(2).x = x;
252 ✗ L(2).y = y;
253
254 ✗ in1 = cx - L(3).x;
255 ✗ out1 = cy - L(3).y;
256 ✗ in2 = L(2).x - L(3).x;
257 ✗ out2 = L(2).y - L(3).y;
258 ✗ L(3).a = (out2 / in2 - out1 / in1) / (in2 - in1);
259 ✗ L(3).b = out1 / in1 - L(3).a * in1;
260 }
261 ✗ L(3).x = 0;
262 ✗ L(3).y = L(2).y;
263
264 ✗ s->in_min_lin = exp(s->segments[1].x);
265 ✗ s->out_min_lin = exp(s->segments[1].y);
266
267 ✗ return 0;
268 }
269
270 ✗ static void square_quadratic(double const *x, double *y)
271 {
272 ✗ y[0] = x[0] * x[0];
273 ✗ y[1] = 2 * x[0] * x[1];
274 ✗ y[2] = 2 * x[0] * x[2] + x[1] * x[1];
275 ✗ y[3] = 2 * x[1] * x[2];
276 ✗ y[4] = x[2] * x[2];
277 ✗ }
278
279 ✗ static int crossover_setup(AVFilterLink *outlink, Crossover *p, double frequency)
280 {
281 ✗ double w0 = 2 * M_PI * frequency / outlink->sample_rate;
282 ✗ double Q = sqrt(.5), alpha = sin(w0) / (2*Q);
283 double x[9], norm;
284 int i;
285
286 ✗ if (w0 > M_PI)
287 ✗ return AVERROR(EINVAL);
288
289 ✗ x[0] = (1 - cos(w0))/2; /* Cf. filter_LPF in biquads.c */
290 ✗ x[1] = 1 - cos(w0);
291 ✗ x[2] = (1 - cos(w0))/2;
292 ✗ x[3] = (1 + cos(w0))/2; /* Cf. filter_HPF in biquads.c */
293 ✗ x[4] = -(1 + cos(w0));
294 ✗ x[5] = (1 + cos(w0))/2;
295 ✗ x[6] = 1 + alpha;
296 ✗ x[7] = -2*cos(w0);
297 ✗ x[8] = 1 - alpha;
298
299 ✗ for (norm = x[6], i = 0; i < 9; ++i)
300 ✗ x[i] /= norm;
301
302 ✗ square_quadratic(x , p->coefs);
303 ✗ square_quadratic(x + 3, p->coefs + 5);
304 ✗ square_quadratic(x + 6, p->coefs + 10);
305
306 ✗ p->previous = av_calloc(outlink->ch_layout.nb_channels, sizeof(*p->previous));
307 ✗ if (!p->previous)
308 ✗ return AVERROR(ENOMEM);
309
310 ✗ return 0;
311 }
312
313 ✗ static int config_output(AVFilterLink *outlink)
314 {
315 ✗ AVFilterContext *ctx = outlink->src;
316 ✗ MCompandContext *s = ctx->priv;
317 int ret, ch, i, k, new_nb_items, nb_bands;
318 ✗ char *p = s->args, *saveptr = NULL;
319 ✗ int max_delay_size = 0;
320
321 ✗ count_items(s->args, &nb_bands, '|');
322 ✗ s->nb_bands = FFMAX(1, nb_bands);
323
324 ✗ s->bands = av_calloc(nb_bands, sizeof(*s->bands));
325 ✗ if (!s->bands)
326 ✗ return AVERROR(ENOMEM);
327
328 ✗ for (i = 0, new_nb_items = 0; i < nb_bands; i++) {
329 ✗ int nb_points, nb_attacks, nb_items = 0;
330 ✗ char *tstr2, *tstr = av_strtok(p, "|", &saveptr);
331 ✗ char *p2, *p3, *saveptr2 = NULL, *saveptr3 = NULL;
332 double radius;
333
334 ✗ if (!tstr)
335 ✗ return AVERROR(EINVAL);
336 ✗ p = NULL;
337
338 ✗ p2 = tstr;
339 ✗ count_items(tstr, &nb_items, ' ');
340 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
341 ✗ if (!tstr2) {
342 ✗ av_log(ctx, AV_LOG_ERROR, "at least one attacks/decays rate is mandatory\n");
343 ✗ return AVERROR(EINVAL);
344 }
345 ✗ p2 = NULL;
346 ✗ p3 = tstr2;
347
348 ✗ count_items(tstr2, &nb_attacks, ',');
349 ✗ if (!nb_attacks || nb_attacks & 1) {
350 ✗ av_log(ctx, AV_LOG_ERROR, "number of attacks rate plus decays rate must be even\n");
351 ✗ return AVERROR(EINVAL);
352 }
353
354 ✗ s->bands[i].attack_rate = av_calloc(outlink->ch_layout.nb_channels, sizeof(double));
355 ✗ s->bands[i].decay_rate = av_calloc(outlink->ch_layout.nb_channels, sizeof(double));
356 ✗ s->bands[i].volume = av_calloc(outlink->ch_layout.nb_channels, sizeof(double));
357 ✗ if (!s->bands[i].attack_rate || !s->bands[i].decay_rate || !s->bands[i].volume)
358 ✗ return AVERROR(ENOMEM);
359
360 ✗ for (k = 0; k < FFMIN(nb_attacks / 2, outlink->ch_layout.nb_channels); k++) {
361 ✗ char *tstr3 = av_strtok(p3, ",", &saveptr3);
362
363 ✗ p3 = NULL;
364 ✗ sscanf(tstr3, "%lf", &s->bands[i].attack_rate[k]);
365 ✗ tstr3 = av_strtok(p3, ",", &saveptr3);
366 ✗ sscanf(tstr3, "%lf", &s->bands[i].decay_rate[k]);
367
368 ✗ if (s->bands[i].attack_rate[k] > 1.0 / outlink->sample_rate) {
369 ✗ s->bands[i].attack_rate[k] = 1.0 - exp(-1.0 / (outlink->sample_rate * s->bands[i].attack_rate[k]));
370 } else {
371 ✗ s->bands[i].attack_rate[k] = 1.0;
372 }
373
374 ✗ if (s->bands[i].decay_rate[k] > 1.0 / outlink->sample_rate) {
375 ✗ s->bands[i].decay_rate[k] = 1.0 - exp(-1.0 / (outlink->sample_rate * s->bands[i].decay_rate[k]));
376 } else {
377 ✗ s->bands[i].decay_rate[k] = 1.0;
378 }
379 }
380
381 ✗ for (ch = k; ch < outlink->ch_layout.nb_channels; ch++) {
382 ✗ s->bands[i].attack_rate[ch] = s->bands[i].attack_rate[k - 1];
383 ✗ s->bands[i].decay_rate[ch] = s->bands[i].decay_rate[k - 1];
384 }
385
386 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
387 ✗ if (!tstr2) {
388 ✗ av_log(ctx, AV_LOG_ERROR, "transfer function curve in dB must be set\n");
389 ✗ return AVERROR(EINVAL);
390 }
391 ✗ sscanf(tstr2, "%lf", &s->bands[i].transfer_fn.curve_dB);
392
393 ✗ radius = s->bands[i].transfer_fn.curve_dB * M_LN10 / 20.0;
394
395 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
396 ✗ if (!tstr2) {
397 ✗ av_log(ctx, AV_LOG_ERROR, "transfer points missing\n");
398 ✗ return AVERROR(EINVAL);
399 }
400
401 ✗ count_items(tstr2, &nb_points, ',');
402 ✗ s->bands[i].transfer_fn.nb_segments = (nb_points + 4) * 2;
403 ✗ s->bands[i].transfer_fn.segments = av_calloc(s->bands[i].transfer_fn.nb_segments,
404 sizeof(CompandSegment));
405 ✗ if (!s->bands[i].transfer_fn.segments)
406 ✗ return AVERROR(ENOMEM);
407
408 ✗ ret = parse_points(tstr2, nb_points, radius, &s->bands[i].transfer_fn, ctx);
409 ✗ if (ret < 0) {
410 ✗ av_log(ctx, AV_LOG_ERROR, "transfer points parsing failed\n");
411 ✗ return ret;
412 }
413
414 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
415 ✗ if (!tstr2) {
416 ✗ av_log(ctx, AV_LOG_ERROR, "crossover_frequency is missing\n");
417 ✗ return AVERROR(EINVAL);
418 }
419
420 ✗ new_nb_items += sscanf(tstr2, "%lf", &s->bands[i].topfreq) == 1;
421 ✗ if (s->bands[i].topfreq < 0 || s->bands[i].topfreq >= outlink->sample_rate / 2.0) {
422 ✗ av_log(ctx, AV_LOG_ERROR, "crossover_frequency: %f, should be >=0 and lower than half of sample rate: %f.\n", s->bands[i].topfreq, outlink->sample_rate / 2.0);
423 ✗ return AVERROR(EINVAL);
424 }
425
426 ✗ if (s->bands[i].topfreq != 0) {
427 ✗ ret = crossover_setup(outlink, &s->bands[i].filter, s->bands[i].topfreq);
428 ✗ if (ret < 0)
429 ✗ return ret;
430 }
431
432 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
433 ✗ if (tstr2) {
434 ✗ sscanf(tstr2, "%lf", &s->bands[i].delay);
435 ✗ max_delay_size = FFMAX(max_delay_size, s->bands[i].delay * outlink->sample_rate);
436
437 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
438 ✗ if (tstr2) {
439 double initial_volume;
440
441 ✗ sscanf(tstr2, "%lf", &initial_volume);
442 ✗ initial_volume = pow(10.0, initial_volume / 20);
443
444 ✗ for (k = 0; k < outlink->ch_layout.nb_channels; k++) {
445 ✗ s->bands[i].volume[k] = initial_volume;
446 }
447
448 ✗ tstr2 = av_strtok(p2, " ", &saveptr2);
449 ✗ if (tstr2) {
450 ✗ sscanf(tstr2, "%lf", &s->bands[i].transfer_fn.gain_dB);
451 }
452 }
453 }
454 }
455 ✗ s->nb_bands = new_nb_items;
456
457 ✗ for (i = 0; max_delay_size > 0 && i < s->nb_bands; i++) {
458 ✗ s->bands[i].delay_buf = ff_get_audio_buffer(outlink, max_delay_size);
459 ✗ if (!s->bands[i].delay_buf)
460 ✗ return AVERROR(ENOMEM);
461 }
462 ✗ s->delay_buf_size = max_delay_size;
463
464 ✗ return 0;
465 }
466
467 #define CONVOLVE _ _ _ _
468
469 ✗ static void crossover(int ch, Crossover *p,
470 double *ibuf, double *obuf_low,
471 double *obuf_high, size_t len)
472 {
473 double out_low, out_high;
474
475 ✗ while (len--) {
476 ✗ p->pos = p->pos ? p->pos - 1 : N - 1;
477 #define _ out_low += p->coefs[j] * p->previous[ch][p->pos + j].in \
478 - p->coefs[2*N+2 + j] * p->previous[ch][p->pos + j].out_low, j++;
479 {
480 ✗ int j = 1;
481 ✗ out_low = p->coefs[0] * *ibuf;
482 ✗ CONVOLVE
483 ✗ *obuf_low++ = out_low;
484 }
485 #undef _
486 #define _ out_high += p->coefs[j+N+1] * p->previous[ch][p->pos + j].in \
487 - p->coefs[2*N+2 + j] * p->previous[ch][p->pos + j].out_high, j++;
488 {
489 ✗ int j = 1;
490 ✗ out_high = p->coefs[N+1] * *ibuf;
491 ✗ CONVOLVE
492 ✗ *obuf_high++ = out_high;
493 }
494 ✗ p->previous[ch][p->pos + N].in = p->previous[ch][p->pos].in = *ibuf++;
495 ✗ p->previous[ch][p->pos + N].out_low = p->previous[ch][p->pos].out_low = out_low;
496 ✗ p->previous[ch][p->pos + N].out_high = p->previous[ch][p->pos].out_high = out_high;
497 }
498 ✗ }
499
500 ✗ static int mcompand_channel(MCompandContext *c, CompBand *l, double *ibuf, double *obuf, int len, int ch)
501 {
502 int i;
503
504 ✗ for (i = 0; i < len; i++) {
505 double level_in_lin, level_out_lin, checkbuf;
506 /* Maintain the volume fields by simulating a leaky pump circuit */
507 ✗ update_volume(l, fabs(ibuf[i]), ch);
508
509 /* Volume memory is updated: perform compand */
510 ✗ level_in_lin = l->volume[ch];
511 ✗ level_out_lin = get_volume(&l->transfer_fn, level_in_lin);
512
513 ✗ if (c->delay_buf_size <= 0) {
514 ✗ checkbuf = ibuf[i] * level_out_lin;
515 ✗ obuf[i] = checkbuf;
516 } else {
517 ✗ double *delay_buf = (double *)l->delay_buf->extended_data[ch];
518
519 /* FIXME: note that this lookahead algorithm is really lame:
520 the response to a peak is released before the peak
521 arrives. */
522
523 /* because volume application delays differ band to band, but
524 total delay doesn't, the volume is applied in an iteration
525 preceding that in which the sample goes to obuf, except in
526 the band(s) with the longest vol app delay.
527
528 the offset between delay_buf_ptr and the sample to apply
529 vol to, is a constant equal to the difference between this
530 band's delay and the longest delay of all the bands. */
531
532 ✗ if (l->delay_buf_cnt >= l->delay_size) {
533 ✗ checkbuf =
534 ✗ delay_buf[(l->delay_buf_ptr +
535 ✗ c->delay_buf_size -
536 ✗ l->delay_size) % c->delay_buf_size] * level_out_lin;
537 ✗ delay_buf[(l->delay_buf_ptr + c->delay_buf_size -
538 ✗ l->delay_size) % c->delay_buf_size] = checkbuf;
539 }
540 ✗ if (l->delay_buf_cnt >= c->delay_buf_size) {
541 ✗ obuf[i] = delay_buf[l->delay_buf_ptr];
542 } else {
543 ✗ l->delay_buf_cnt++;
544 }
545 ✗ delay_buf[l->delay_buf_ptr++] = ibuf[i];
546 ✗ l->delay_buf_ptr %= c->delay_buf_size;
547 }
548 }
549
550 ✗ return 0;
551 }
552
553 ✗ static int filter_frame(AVFilterLink *inlink, AVFrame *in)
554 {
555 ✗ AVFilterContext *ctx = inlink->dst;
556 ✗ AVFilterLink *outlink = ctx->outputs[0];
557 ✗ MCompandContext *s = ctx->priv;
558 AVFrame *out, *abuf, *bbuf, *cbuf;
559 int ch, band, i;
560
561 ✗ out = ff_get_audio_buffer(outlink, in->nb_samples);
562 ✗ if (!out) {
563 ✗ av_frame_free(&in);
564 ✗ return AVERROR(ENOMEM);
565 }
566
567 ✗ if (s->band_samples < in->nb_samples) {
568 ✗ av_frame_free(&s->band_buf1);
569 ✗ av_frame_free(&s->band_buf2);
570 ✗ av_frame_free(&s->band_buf3);
571
572 ✗ s->band_buf1 = ff_get_audio_buffer(outlink, in->nb_samples);
573 ✗ s->band_buf2 = ff_get_audio_buffer(outlink, in->nb_samples);
574 ✗ s->band_buf3 = ff_get_audio_buffer(outlink, in->nb_samples);
575 ✗ s->band_samples = in->nb_samples;
576 }
577
578 ✗ for (ch = 0; ch < outlink->ch_layout.nb_channels; ch++) {
579 ✗ double *a, *dst = (double *)out->extended_data[ch];
580
581 ✗ for (band = 0, abuf = in, bbuf = s->band_buf2, cbuf = s->band_buf1; band < s->nb_bands; band++) {
582 ✗ CompBand *b = &s->bands[band];
583
584 ✗ if (b->topfreq) {
585 ✗ crossover(ch, &b->filter, (double *)abuf->extended_data[ch],
586 ✗ (double *)bbuf->extended_data[ch], (double *)cbuf->extended_data[ch], in->nb_samples);
587 } else {
588 ✗ bbuf = abuf;
589 ✗ abuf = cbuf;
590 }
591
592 ✗ if (abuf == in)
593 ✗ abuf = s->band_buf3;
594 ✗ mcompand_channel(s, b, (double *)bbuf->extended_data[ch], (double *)abuf->extended_data[ch], out->nb_samples, ch);
595 ✗ a = (double *)abuf->extended_data[ch];
596 ✗ for (i = 0; i < out->nb_samples; i++) {
597 ✗ dst[i] += a[i];
598 }
599
600 ✗ FFSWAP(AVFrame *, abuf, cbuf);
601 }
602 }
603
604 ✗ out->pts = in->pts;
605 ✗ av_frame_free(&in);
606 ✗ return ff_filter_frame(outlink, out);
607 }
608
609 ✗ static int request_frame(AVFilterLink *outlink)
610 {
611 ✗ AVFilterContext *ctx = outlink->src;
612 int ret;
613
614 ✗ ret = ff_request_frame(ctx->inputs[0]);
615
616 ✗ return ret;
617 }
618
619 static const AVFilterPad mcompand_inputs[] = {
620 {
621 .name = "default",
622 .type = AVMEDIA_TYPE_AUDIO,
623 .filter_frame = filter_frame,
624 },
625 };
626
627 static const AVFilterPad mcompand_outputs[] = {
628 {
629 .name = "default",
630 .type = AVMEDIA_TYPE_AUDIO,
631 .request_frame = request_frame,
632 .config_props = config_output,
633 },
634 };
635
636
637 const FFFilter ff_af_mcompand = {
638 .p.name = "mcompand",
639 .p.description = NULL_IF_CONFIG_SMALL(
640 "Multiband Compress or expand audio dynamic range."),
641 .p.priv_class = &mcompand_class,
642 .priv_size = sizeof(MCompandContext),
643 .uninit = uninit,
644 FILTER_INPUTS(mcompand_inputs),
645 FILTER_OUTPUTS(mcompand_outputs),
646 FILTER_SINGLE_SAMPLEFMT(AV_SAMPLE_FMT_DBLP),
647 };
648