FFmpeg
Loading...
Searching...
No Matches
af_dynaudnorm.c
Go to the documentation of this file.
1/*
2 * Dynamic Audio Normalizer
3 * Copyright (c) 2015 LoRd_MuldeR <mulder2@gmx.de>. Some rights reserved.
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
23 * @file
24 * Dynamic Audio Normalizer
25 */
26
27#include <float.h>
28
29#include "libavutil/avassert.h"
31#include "libavutil/eval.h"
32#include "libavutil/mem.h"
33#include "libavutil/opt.h"
34
35#define MIN_FILTER_SIZE 3
36#define MAX_FILTER_SIZE 301
37
38#define FF_BUFQUEUE_SIZE (MAX_FILTER_SIZE + 1)
40
41#include "audio.h"
42#include "avfilter.h"
43#include "filters.h"
44
45static const char * const var_names[] = {
46 "ch", ///< the value of the current channel
47 "sn", ///< number of samples
48 "nb_channels",
49 "t", ///< timestamp expressed in seconds
50 "sr", ///< sample rate
51 "p", ///< peak value
52 NULL
53};
54
64
65typedef struct local_gain {
66 double max_gain;
67 double threshold;
69
70typedef struct cqueue {
71 double *elements;
72 int size;
75} cqueue;
76
120
121typedef struct ThreadData {
122 AVFrame *in, *out;
124} ThreadData;
125
126#define OFFSET(x) offsetof(DynamicAudioNormalizerContext, x)
127#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
128
129static const AVOption dynaudnorm_options[] = {
130 { "framelen", "set the frame length in msec", OFFSET(frame_len_msec), AV_OPT_TYPE_INT, {.i64 = 500}, 10, 8000, FLAGS },
131 { "f", "set the frame length in msec", OFFSET(frame_len_msec), AV_OPT_TYPE_INT, {.i64 = 500}, 10, 8000, FLAGS },
132 { "gausssize", "set the filter size", OFFSET(filter_size), AV_OPT_TYPE_INT, {.i64 = 31}, 3, 301, FLAGS },
133 { "g", "set the filter size", OFFSET(filter_size), AV_OPT_TYPE_INT, {.i64 = 31}, 3, 301, FLAGS },
134 { "peak", "set the peak value", OFFSET(peak_value), AV_OPT_TYPE_DOUBLE, {.dbl = 0.95}, 0.0, 1.0, FLAGS },
135 { "p", "set the peak value", OFFSET(peak_value), AV_OPT_TYPE_DOUBLE, {.dbl = 0.95}, 0.0, 1.0, FLAGS },
136 { "maxgain", "set the max amplification", OFFSET(max_amplification), AV_OPT_TYPE_DOUBLE, {.dbl = 10.0}, 1.0, 100.0, FLAGS },
137 { "m", "set the max amplification", OFFSET(max_amplification), AV_OPT_TYPE_DOUBLE, {.dbl = 10.0}, 1.0, 100.0, FLAGS },
138 { "targetrms", "set the target RMS", OFFSET(target_rms), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
139 { "r", "set the target RMS", OFFSET(target_rms), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
140 { "coupling", "set channel coupling", OFFSET(channels_coupled), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
141 { "n", "set channel coupling", OFFSET(channels_coupled), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS },
142 { "correctdc", "set DC correction", OFFSET(dc_correction), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
143 { "c", "set DC correction", OFFSET(dc_correction), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
144 { "altboundary", "set alternative boundary mode", OFFSET(alt_boundary_mode), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
145 { "b", "set alternative boundary mode", OFFSET(alt_boundary_mode), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS },
146 { "compress", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS },
147 { "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS },
148 { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
149 { "t", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
150 { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
151 { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
152 { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
153 { "o", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
154 { "curve", "set the custom peak mapping curve",OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
155 { "v", "set the custom peak mapping curve",OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
156 { NULL }
157};
158
160
162{
164
165 if (!(s->filter_size & 1)) {
166 av_log(ctx, AV_LOG_WARNING, "filter size %d is invalid. Changing to an odd value.\n", s->filter_size);
167 s->filter_size |= 1;
168 }
169
170 return 0;
171}
172
173static inline int frame_size(int sample_rate, int frame_len_msec)
174{
175 const int64_t frame_size = llrint((double)sample_rate * (frame_len_msec / 1000.0));
176 if (frame_size >= INT_MAX / 2)
177 return AVERROR(EINVAL);
178 return frame_size + (frame_size % 2);
179}
180
181static cqueue *cqueue_create(int size, int max_size)
182{
183 cqueue *q;
184
185 if (max_size < size)
186 return NULL;
187
188 q = av_malloc(sizeof(cqueue));
189 if (!q)
190 return NULL;
191
192 q->max_size = max_size;
193 q->size = size;
194 q->nb_elements = 0;
195
196 q->elements = av_malloc_array(max_size, sizeof(double));
197 if (!q->elements) {
198 av_free(q);
199 return NULL;
200 }
201
202 return q;
203}
204
205static void cqueue_free(cqueue *q)
206{
207 if (q)
208 av_free(q->elements);
209 av_free(q);
210}
211
212static int cqueue_size(cqueue *q)
213{
214 return q->nb_elements;
215}
216
217static int cqueue_empty(cqueue *q)
218{
219 return q->nb_elements <= 0;
220}
221
222static int cqueue_enqueue(cqueue *q, double element)
223{
225
226 q->elements[q->nb_elements] = element;
227 q->nb_elements++;
228
229 return 0;
230}
231
232static double cqueue_peek(cqueue *q, int index)
233{
234 av_assert2(index < q->nb_elements);
235 return q->elements[index];
236}
237
238static int cqueue_dequeue(cqueue *q, double *element)
239{
241
242 *element = q->elements[0];
243 memmove(&q->elements[0], &q->elements[1], (q->nb_elements - 1) * sizeof(double));
244 q->nb_elements--;
245
246 return 0;
247}
248
249static int cqueue_pop(cqueue *q)
250{
252
253 memmove(&q->elements[0], &q->elements[1], (q->nb_elements - 1) * sizeof(double));
254 q->nb_elements--;
255
256 return 0;
257}
258
259static void cqueue_resize(cqueue *q, int new_size)
260{
261 av_assert2(q->max_size >= new_size);
262 av_assert2(MIN_FILTER_SIZE <= new_size);
263
264 if (new_size > q->nb_elements) {
265 const int side = (new_size - q->nb_elements) / 2;
266
267 memmove(q->elements + side, q->elements, sizeof(double) * q->nb_elements);
268 for (int i = 0; i < side; i++)
269 q->elements[i] = q->elements[side];
270 q->nb_elements = new_size - 1 - side;
271 } else {
272 int count = (q->size - new_size + 1) / 2;
273
274 while (count-- > 0)
275 cqueue_pop(q);
276 }
277
278 q->size = new_size;
279}
280
282{
283 double total_weight = 0.0;
284 const double sigma = (((s->filter_size / 2.0) - 1.0) / 3.0) + (1.0 / 3.0);
285 double adjust;
286
287 // Pre-compute constants
288 const int offset = s->filter_size / 2;
289 const double c1 = 1.0 / (sigma * sqrt(2.0 * M_PI));
290 const double c2 = 2.0 * sigma * sigma;
291
292 // Compute weights
293 for (int i = 0; i < s->filter_size; i++) {
294 const int x = i - offset;
295
296 s->weights[i] = c1 * exp(-x * x / c2);
297 total_weight += s->weights[i];
298 }
299
300 // Adjust weights
301 adjust = 1.0 / total_weight;
302 for (int i = 0; i < s->filter_size; i++) {
303 s->weights[i] *= adjust;
304 }
305}
306
308{
310
311 av_freep(&s->prev_amplification_factor);
312 av_freep(&s->dc_correction_value);
313 av_freep(&s->compress_threshold);
314
315 for (int c = 0; c < s->channels; c++) {
316 if (s->gain_history_original)
317 cqueue_free(s->gain_history_original[c]);
318 if (s->gain_history_minimum)
319 cqueue_free(s->gain_history_minimum[c]);
320 if (s->gain_history_smoothed)
321 cqueue_free(s->gain_history_smoothed[c]);
322 if (s->threshold_history)
323 cqueue_free(s->threshold_history[c]);
324 }
325
326 av_freep(&s->gain_history_original);
327 av_freep(&s->gain_history_minimum);
328 av_freep(&s->gain_history_smoothed);
329 av_freep(&s->threshold_history);
330
331 cqueue_free(s->is_enabled);
332 s->is_enabled = NULL;
333
334 av_freep(&s->weights);
335
336 av_channel_layout_uninit(&s->ch_layout);
337
338 ff_bufqueue_discard_all(&s->queue);
339
340 av_frame_free(&s->window);
341 av_expr_free(s->expr);
342 s->expr = NULL;
343}
344
345static int config_input(AVFilterLink *inlink)
346{
347 AVFilterContext *ctx = inlink->dst;
349 int ret = 0;
350
351 uninit(ctx);
352
353 s->channels = inlink->ch_layout.nb_channels;
354 s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
355 if (s->frame_len < 0)
356 return s->frame_len;
357 av_log(ctx, AV_LOG_DEBUG, "frame len %d\n", s->frame_len);
358
359 s->prev_amplification_factor = av_malloc_array(inlink->ch_layout.nb_channels, sizeof(*s->prev_amplification_factor));
360 s->dc_correction_value = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->dc_correction_value));
361 s->compress_threshold = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->compress_threshold));
362 s->gain_history_original = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->gain_history_original));
363 s->gain_history_minimum = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->gain_history_minimum));
364 s->gain_history_smoothed = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->gain_history_smoothed));
365 s->threshold_history = av_calloc(inlink->ch_layout.nb_channels, sizeof(*s->threshold_history));
366 s->weights = av_malloc_array(MAX_FILTER_SIZE, sizeof(*s->weights));
367 s->is_enabled = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
368 if (!s->prev_amplification_factor || !s->dc_correction_value ||
369 !s->compress_threshold ||
370 !s->gain_history_original || !s->gain_history_minimum ||
371 !s->gain_history_smoothed || !s->threshold_history ||
372 !s->is_enabled || !s->weights)
373 return AVERROR(ENOMEM);
374
375 for (int c = 0; c < inlink->ch_layout.nb_channels; c++) {
376 s->prev_amplification_factor[c] = 1.0;
377
378 s->gain_history_original[c] = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
379 s->gain_history_minimum[c] = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
380 s->gain_history_smoothed[c] = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
381 s->threshold_history[c] = cqueue_create(s->filter_size, MAX_FILTER_SIZE);
382
383 if (!s->gain_history_original[c] || !s->gain_history_minimum[c] ||
384 !s->gain_history_smoothed[c] || !s->threshold_history[c])
385 return AVERROR(ENOMEM);
386 }
387
389
390 s->window = ff_get_audio_buffer(ctx->outputs[0], s->frame_len * 2);
391 if (!s->window)
392 return AVERROR(ENOMEM);
393 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
394
395 s->var_values[VAR_SR] = inlink->sample_rate;
396 s->var_values[VAR_NB_CHANNELS] = s->channels;
397
398 if (s->expr_str)
399 ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
400 NULL, NULL, 0, ctx);
401 return ret;
402}
403
404static inline double fade(double prev, double next, int pos, int length)
405{
406 const double step_size = 1.0 / length;
407 const double f0 = 1.0 - (step_size * (pos + 1.0));
408 const double f1 = 1.0 - f0;
409 return f0 * prev + f1 * next;
410}
411
412static inline double pow_2(const double value)
413{
414 return value * value;
415}
416
417static inline double bound(const double threshold, const double val)
418{
419 const double CONST = 0.8862269254527580136490837416705725913987747280611935; //sqrt(PI) / 2.0
420 return erf(CONST * (val / threshold)) * threshold;
421}
422
424{
425 double max = DBL_EPSILON;
426
427 if (channel == -1) {
428 for (int c = 0; c < frame->ch_layout.nb_channels; c++) {
429 double *data_ptr = (double *)frame->extended_data[c];
430
431 for (int i = 0; i < frame->nb_samples; i++)
432 max = fmax(max, fabs(data_ptr[i]));
433 }
434 } else {
435 double *data_ptr = (double *)frame->extended_data[channel];
436
437 for (int i = 0; i < frame->nb_samples; i++)
438 max = fmax(max, fabs(data_ptr[i]));
439 }
440
441 return max;
442}
443
445{
446 double rms_value = 0.0;
447
448 if (channel == -1) {
449 for (int c = 0; c < frame->ch_layout.nb_channels; c++) {
450 const double *data_ptr = (double *)frame->extended_data[c];
451
452 for (int i = 0; i < frame->nb_samples; i++) {
453 rms_value += pow_2(data_ptr[i]);
454 }
455 }
456
457 rms_value /= frame->nb_samples * frame->ch_layout.nb_channels;
458 } else {
459 const double *data_ptr = (double *)frame->extended_data[channel];
460 for (int i = 0; i < frame->nb_samples; i++) {
461 rms_value += pow_2(data_ptr[i]);
462 }
463
464 rms_value /= frame->nb_samples;
465 }
466
467 return fmax(sqrt(rms_value), DBL_EPSILON);
468}
469
471 int channel)
472{
473 const double peak_magnitude = find_peak_magnitude(frame, channel);
474 const double maximum_gain = s->peak_value / peak_magnitude;
475 const double rms_gain = s->target_rms > DBL_EPSILON ? (s->target_rms / compute_frame_rms(frame, channel)) : DBL_MAX;
476 double target_gain = DBL_MAX;
477 local_gain gain;
478
479 if (s->expr_str) {
480 double var_values[VAR_VARS_NB];
481
482 memcpy(var_values, s->var_values, sizeof(var_values));
483
484 var_values[VAR_CH] = channel;
485 var_values[VAR_P] = peak_magnitude;
486
487 target_gain = av_expr_eval(s->expr, var_values, s) / peak_magnitude;
488 }
489
490 gain.threshold = peak_magnitude > s->threshold;
491 gain.max_gain = bound(s->max_amplification, fmin(target_gain, fmin(maximum_gain, rms_gain)));
492
493 return gain;
494}
495
496static double minimum_filter(cqueue *q)
497{
498 double min = DBL_MAX;
499
500 for (int i = 0; i < cqueue_size(q); i++) {
501 min = fmin(min, cqueue_peek(q, i));
502 }
503
504 return min;
505}
506
508{
509 const double *weights = s->weights;
510 double result = 0.0, tsum = 0.0;
511
512 for (int i = 0; i < cqueue_size(q); i++) {
513 double tq_item = cqueue_peek(tq, i);
514 double q_item = cqueue_peek(q, i);
515
516 tsum += tq_item * weights[i];
517 result += tq_item * weights[i] * q_item;
518 }
519
520 if (tsum == 0.0)
521 result = 1.0;
522
523 return result;
524}
525
527 local_gain gain)
528{
529 if (cqueue_empty(s->gain_history_original[channel])) {
530 const int pre_fill_size = s->filter_size / 2;
531 const double initial_value = s->alt_boundary_mode ? gain.max_gain : fmin(1.0, gain.max_gain);
532
533 s->prev_amplification_factor[channel] = initial_value;
534
535 while (cqueue_size(s->gain_history_original[channel]) < pre_fill_size) {
536 cqueue_enqueue(s->gain_history_original[channel], initial_value);
537 cqueue_enqueue(s->threshold_history[channel], gain.threshold);
538 }
539 }
540
541 cqueue_enqueue(s->gain_history_original[channel], gain.max_gain);
542
543 while (cqueue_size(s->gain_history_original[channel]) >= s->filter_size) {
544 double minimum;
545
546 if (cqueue_empty(s->gain_history_minimum[channel])) {
547 const int pre_fill_size = s->filter_size / 2;
548 double initial_value = s->alt_boundary_mode ? cqueue_peek(s->gain_history_original[channel], 0) : 1.0;
549 int input = pre_fill_size;
550
551 while (cqueue_size(s->gain_history_minimum[channel]) < pre_fill_size) {
552 input++;
553 initial_value = fmin(initial_value, cqueue_peek(s->gain_history_original[channel], input));
554 cqueue_enqueue(s->gain_history_minimum[channel], initial_value);
555 }
556 }
557
558 minimum = minimum_filter(s->gain_history_original[channel]);
559
560 cqueue_enqueue(s->gain_history_minimum[channel], minimum);
561
562 cqueue_enqueue(s->threshold_history[channel], gain.threshold);
563
564 cqueue_pop(s->gain_history_original[channel]);
565 }
566
567 while (cqueue_size(s->gain_history_minimum[channel]) >= s->filter_size) {
568 double smoothed, limit;
569
570 smoothed = gaussian_filter(s, s->gain_history_minimum[channel], s->threshold_history[channel]);
571 limit = cqueue_peek(s->gain_history_original[channel], 0);
572 smoothed = fmin(smoothed, limit);
573
574 cqueue_enqueue(s->gain_history_smoothed[channel], smoothed);
575
576 cqueue_pop(s->gain_history_minimum[channel]);
577 cqueue_pop(s->threshold_history[channel]);
578 }
579}
580
581static int update_gain_histories(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
582{
585 const int channels = s->channels;
586 const int start = ff_slice_pos(channels, jobnr, nb_jobs);
587 const int end = ff_slice_pos(channels, jobnr + 1, nb_jobs);
588
589 for (int c = start; c < end; c++)
591
592 return 0;
593}
594
595static inline double update_value(double new, double old, double aggressiveness)
596{
597 av_assert0((aggressiveness >= 0.0) && (aggressiveness <= 1.0));
598 return aggressiveness * new + (1.0 - aggressiveness) * old;
599}
600
602{
604
605 return av_channel_layout_index_from_channel(&s->ch_layout, channel) < 0;
606}
607
609{
610 const double diff = 1.0 / frame->nb_samples;
611 int is_first_frame = cqueue_empty(s->gain_history_original[0]);
612
613 for (int c = 0; c < s->channels; c++) {
614 const int bypass = bypass_channel(s, frame, c);
615 double *dst_ptr = (double *)frame->extended_data[c];
616 double current_average_value = 0.0;
617 double prev_value;
618
619 for (int i = 0; i < frame->nb_samples; i++)
620 current_average_value += dst_ptr[i] * diff;
621
622 prev_value = is_first_frame ? current_average_value : s->dc_correction_value[c];
623 s->dc_correction_value[c] = is_first_frame ? current_average_value : update_value(current_average_value, s->dc_correction_value[c], 0.1);
624
625 for (int i = 0; i < frame->nb_samples && !bypass; i++) {
626 dst_ptr[i] -= fade(prev_value, s->dc_correction_value[c], i, frame->nb_samples);
627 }
628 }
629}
630
631static double setup_compress_thresh(double threshold)
632{
633 if ((threshold > DBL_EPSILON) && (threshold < (1.0 - DBL_EPSILON))) {
634 double current_threshold = threshold;
635 double step_size = 1.0;
636
637 while (step_size > DBL_EPSILON) {
638 while ((llrint((current_threshold + step_size) * (UINT64_C(1) << 63)) >
639 llrint(current_threshold * (UINT64_C(1) << 63))) &&
640 (bound(current_threshold + step_size, 1.0) <= threshold)) {
641 current_threshold += step_size;
642 }
643
644 step_size /= 2.0;
645 }
646
647 return current_threshold;
648 } else {
649 return threshold;
650 }
651}
652
654 AVFrame *frame, int channel)
655{
656 double variance = 0.0;
657
658 if (channel == -1) {
659 for (int c = 0; c < s->channels; c++) {
660 const double *data_ptr = (double *)frame->extended_data[c];
661
662 for (int i = 0; i < frame->nb_samples; i++) {
663 variance += pow_2(data_ptr[i]); // Assume that MEAN is *zero*
664 }
665 }
666 variance /= (s->channels * frame->nb_samples) - 1;
667 } else {
668 const double *data_ptr = (double *)frame->extended_data[channel];
669
670 for (int i = 0; i < frame->nb_samples; i++) {
671 variance += pow_2(data_ptr[i]); // Assume that MEAN is *zero*
672 }
673 variance /= frame->nb_samples - 1;
674 }
675
676 return fmax(sqrt(variance), DBL_EPSILON);
677}
678
680{
681 int is_first_frame = cqueue_empty(s->gain_history_original[0]);
682
683 if (s->channels_coupled) {
684 const double standard_deviation = compute_frame_std_dev(s, frame, -1);
685 const double current_threshold = fmin(1.0, s->compress_factor * standard_deviation);
686
687 const double prev_value = is_first_frame ? current_threshold : s->compress_threshold[0];
688 double prev_actual_thresh, curr_actual_thresh;
689 s->compress_threshold[0] = is_first_frame ? current_threshold : update_value(current_threshold, s->compress_threshold[0], (1.0/3.0));
690
691 prev_actual_thresh = setup_compress_thresh(prev_value);
692 curr_actual_thresh = setup_compress_thresh(s->compress_threshold[0]);
693
694 for (int c = 0; c < s->channels; c++) {
695 double *const dst_ptr = (double *)frame->extended_data[c];
696 const int bypass = bypass_channel(s, frame, c);
697
698 if (bypass)
699 continue;
700
701 for (int i = 0; i < frame->nb_samples; i++) {
702 const double localThresh = fade(prev_actual_thresh, curr_actual_thresh, i, frame->nb_samples);
703 dst_ptr[i] = copysign(bound(localThresh, fabs(dst_ptr[i])), dst_ptr[i]);
704 }
705 }
706 } else {
707 for (int c = 0; c < s->channels; c++) {
708 const int bypass = bypass_channel(s, frame, c);
709 const double standard_deviation = compute_frame_std_dev(s, frame, c);
710 const double current_threshold = setup_compress_thresh(fmin(1.0, s->compress_factor * standard_deviation));
711 const double prev_value = is_first_frame ? current_threshold : s->compress_threshold[c];
712 double prev_actual_thresh, curr_actual_thresh;
713 double *dst_ptr;
714
715 s->compress_threshold[c] = is_first_frame ? current_threshold : update_value(current_threshold, s->compress_threshold[c], 1.0/3.0);
716
717 prev_actual_thresh = setup_compress_thresh(prev_value);
718 curr_actual_thresh = setup_compress_thresh(s->compress_threshold[c]);
719
720 dst_ptr = (double *)frame->extended_data[c];
721 for (int i = 0; i < frame->nb_samples && !bypass; i++) {
722 const double localThresh = fade(prev_actual_thresh, curr_actual_thresh, i, frame->nb_samples);
723 dst_ptr[i] = copysign(bound(localThresh, fabs(dst_ptr[i])), dst_ptr[i]);
724 }
725 }
726 }
727}
728
730{
731 FilterLink *outl = ff_filter_link(outlink);
734
735 if (s->dc_correction || s->compress_factor > DBL_EPSILON) {
736 int ret;
737
739 AVFrame *out = ff_get_audio_buffer(outlink, (*frame)->nb_samples);
740
741 if (!out) {
743 return AVERROR(ENOMEM);
744 }
746 if (ret < 0) {
749 return ret;
750 }
751 ret = av_frame_copy(out, *frame);
752 if (ret < 0) {
755 return ret;
756 }
757
759 *frame = out;
760 }
761 }
762
763 if (s->dc_correction)
765
766 if (s->compress_factor > DBL_EPSILON)
768
769 if (s->frame_len != s->sample_advance) {
770 const int offset = s->frame_len - s->sample_advance;
771
772 for (int c = 0; c < s->channels; c++) {
773 double *src = (double *)s->window->extended_data[c];
774
775 memmove(src, &src[s->sample_advance], offset * sizeof(double));
776 memcpy(&src[offset], (*frame)->extended_data[c], (*frame)->nb_samples * sizeof(double));
777 memset(&src[offset + (*frame)->nb_samples], 0, (s->sample_advance - (*frame)->nb_samples) * sizeof(double));
778 }
779
780 analyze_frame = s->window;
781 } else {
782 av_samples_copy(s->window->extended_data, (*frame)->extended_data, 0, 0,
783 FFMIN(s->frame_len, (*frame)->nb_samples), (*frame)->ch_layout.nb_channels, (*frame)->format);
785 }
786
787 s->var_values[VAR_SN] = outl->sample_count_in;
788 s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate;
789
790 if (s->channels_coupled) {
791 const local_gain gain = get_max_local_gain(s, analyze_frame, -1);
792 for (int c = 0; c < s->channels; c++)
793 update_gain_history(s, c, gain);
794 } else {
796 FFMIN(s->channels, ff_filter_get_nb_threads(ctx)));
797 }
798
799 return 0;
800}
801
803 AVFrame *frame, int enabled, int c)
804{
805 const int bypass = bypass_channel(s, frame, c);
806 const double *src_ptr = (const double *)in->extended_data[c];
807 double *dst_ptr = (double *)frame->extended_data[c];
808 double current_amplification_factor;
809
810 cqueue_dequeue(s->gain_history_smoothed[c], &current_amplification_factor);
811
812 for (int i = 0; i < frame->nb_samples && enabled && !bypass; i++) {
813 const double amplification_factor = fade(s->prev_amplification_factor[c],
814 current_amplification_factor, i,
815 frame->nb_samples);
816
817 dst_ptr[i] = src_ptr[i] * amplification_factor;
818 }
819
820 s->prev_amplification_factor[c] = current_amplification_factor;
821}
822
823static int amplify_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
824{
826 ThreadData *td = arg;
827 AVFrame *out = td->out;
828 AVFrame *in = td->in;
829 const int enabled = td->enabled;
830 const int channels = s->channels;
831 const int start = ff_slice_pos(channels, jobnr, nb_jobs);
832 const int end = ff_slice_pos(channels, jobnr + 1, nb_jobs);
833
834 for (int ch = start; ch < end; ch++)
835 amplify_channel(s, in, out, enabled, ch);
836
837 return 0;
838}
839
840static int filter_frame(AVFilterLink *inlink, AVFrame *in)
841{
842 AVFilterContext *ctx = inlink->dst;
844 AVFilterLink *outlink = ctx->outputs[0];
845 ThreadData td;
846 int ret;
847
848 while (((s->queue.available >= s->filter_size) ||
849 (s->eof && s->queue.available)) &&
850 !cqueue_empty(s->gain_history_smoothed[0])) {
851 AVFrame *in = ff_bufqueue_get(&s->queue);
852 AVFrame *out;
853 double is_enabled;
854
855 cqueue_dequeue(s->is_enabled, &is_enabled);
856
857 if (av_frame_is_writable(in)) {
858 out = in;
859 } else {
860 out = ff_get_audio_buffer(outlink, in->nb_samples);
861 if (!out) {
862 av_frame_free(&in);
863 return AVERROR(ENOMEM);
864 }
866 }
867
868 td.in = in;
869 td.out = out;
870 td.enabled = is_enabled > 0.;
872 FFMIN(s->channels, ff_filter_get_nb_threads(ctx)));
873
874 s->pts = out->pts + av_rescale_q(out->nb_samples, av_make_q(1, outlink->sample_rate),
875 outlink->time_base);
876 if (out != in)
877 av_frame_free(&in);
878 ret = ff_filter_frame(outlink, out);
879 if (ret < 0)
880 return ret;
881 }
882
883 ret = analyze_frame(ctx, outlink, &in);
884 if (ret < 0)
885 return ret;
886 if (!s->eof) {
887 ff_bufqueue_add(ctx, &s->queue, in);
888 cqueue_enqueue(s->is_enabled, !ctx->is_disabled);
889 } else {
890 av_frame_free(&in);
891 }
892
893 return 1;
894}
895
897 AVFilterLink *outlink)
898{
899 AVFrame *out = ff_get_audio_buffer(outlink, s->sample_advance);
900
901 if (!out)
902 return AVERROR(ENOMEM);
903
904 for (int c = 0; c < s->channels; c++) {
905 double *dst_ptr = (double *)out->extended_data[c];
906
907 for (int i = 0; i < out->nb_samples; i++) {
908 dst_ptr[i] = s->alt_boundary_mode ? DBL_EPSILON : ((s->target_rms > DBL_EPSILON) ? fmin(s->peak_value, s->target_rms) : s->peak_value);
909 if (s->dc_correction) {
910 dst_ptr[i] *= ((i % 2) == 1) ? -1 : 1;
911 dst_ptr[i] += s->dc_correction_value[c];
912 }
913 }
914 }
915
916 return filter_frame(inlink, out);
917}
918
919static int flush(AVFilterLink *outlink)
920{
921 AVFilterContext *ctx = outlink->src;
922 AVFilterLink *inlink = ctx->inputs[0];
924
925 while (s->eof && cqueue_empty(s->gain_history_smoothed[0])) {
926 for (int c = 0; c < s->channels; c++)
927 update_gain_history(s, c, (local_gain){ cqueue_peek(s->gain_history_original[c], 0), 1.0});
928 }
929
930 return flush_buffer(s, inlink, outlink);
931}
932
934{
935 AVFilterLink *inlink = ctx->inputs[0];
936 AVFilterLink *outlink = ctx->outputs[0];
938 AVFrame *in = NULL;
939 int ret = 0, status;
940 int64_t pts;
941
942 ret = av_channel_layout_copy(&s->ch_layout, &inlink->ch_layout);
943 if (ret < 0)
944 return ret;
945 if (strcmp(s->channels_to_filter, "all"))
946 av_channel_layout_from_string(&s->ch_layout, s->channels_to_filter);
947
948 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
949
950 if (!s->eof) {
951 ret = ff_inlink_consume_samples(inlink, s->sample_advance, s->sample_advance, &in);
952 if (ret < 0)
953 return ret;
954 if (ret > 0) {
955 ret = filter_frame(inlink, in);
956 if (ret <= 0)
957 return ret;
958 }
959
960 if (ff_inlink_check_available_samples(inlink, s->sample_advance) > 0) {
962 return 0;
963 }
964 }
965
966 if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
967 if (status == AVERROR_EOF)
968 s->eof = 1;
969 }
970
971 if (s->eof && s->queue.available)
972 return flush(outlink);
973
974 if (s->eof && !s->queue.available) {
975 ff_outlink_set_status(outlink, AVERROR_EOF, s->pts);
976 return 0;
977 }
978
979 if (!s->eof)
980 FF_FILTER_FORWARD_WANTED(outlink, inlink);
981
982 return FFERROR_NOT_READY;
983}
984
985static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
986 char *res, int res_len, int flags)
987{
989 AVFilterLink *inlink = ctx->inputs[0];
990 int prev_filter_size = s->filter_size;
991 int frame_len, ret;
992
993 ret = ff_filter_process_command(ctx, cmd, args, res, res_len, flags);
994 if (ret < 0)
995 return ret;
996
997 s->filter_size |= 1;
998 if (prev_filter_size != s->filter_size) {
1000
1001 for (int c = 0; c < s->channels; c++) {
1002 cqueue_resize(s->gain_history_original[c], s->filter_size);
1003 cqueue_resize(s->gain_history_minimum[c], s->filter_size);
1004 cqueue_resize(s->threshold_history[c], s->filter_size);
1005 }
1006 }
1007
1008 frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
1009 if (frame_len < 0)
1010 return frame_len;
1011 if (frame_len != s->frame_len) {
1012 AVFrame *window = ff_get_audio_buffer(ctx->outputs[0], frame_len * 2);
1013 if (!window)
1014 return AVERROR(ENOMEM);
1015 av_frame_free(&s->window);
1016 s->window = window;
1017 s->frame_len = frame_len;
1018 }
1019 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
1020 if (s->expr_str) {
1021 ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
1022 NULL, NULL, 0, ctx);
1023 if (ret < 0)
1024 return ret;
1025 }
1026 return 0;
1027}
1028
1030 {
1031 .name = "default",
1032 .type = AVMEDIA_TYPE_AUDIO,
1033 .config_props = config_input,
1034 },
1035};
1036
1038 .p.name = "dynaudnorm",
1039 .p.description = NULL_IF_CONFIG_SMALL("Dynamic Audio Normalizer."),
1040 .p.priv_class = &dynaudnorm_class,
1043 .priv_size = sizeof(DynamicAudioNormalizerContext),
1044 .init = init,
1045 .uninit = uninit,
1046 .activate = activate,
1050 .process_command = process_command,
1051};
@ VAR_CH
Definition aeval.c:49
@ VAR_T
Definition aeval.c:53
static double val(void *priv, double ch)
Definition aeval.c:77
static int config_input(AVFilterLink *inlink)
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
@ VAR_SN
Definition af_adrc.c:45
@ VAR_NB_CHANNELS
Definition af_adrc.c:46
@ VAR_P
Definition af_adrc.c:49
static int cqueue_pop(cqueue *q)
static void cqueue_resize(cqueue *q, int new_size)
@ VAR_VARS_NB
static void amplify_channel(DynamicAudioNormalizerContext *s, AVFrame *in, AVFrame *frame, int enabled, int c)
static double bound(const double threshold, const double val)
static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame)
static int cqueue_empty(cqueue *q)
const FFFilter ff_af_dynaudnorm
static double update_value(double new, double old, double aggressiveness)
static double compute_frame_rms(AVFrame *frame, int channel)
static int flush_buffer(DynamicAudioNormalizerContext *s, AVFilterLink *inlink, AVFilterLink *outlink)
static cqueue * cqueue_create(int size, int max_size)
static int cqueue_enqueue(cqueue *q, double element)
static const AVOption dynaudnorm_options[]
static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *frame)
static int update_gain_histories(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static double setup_compress_thresh(double threshold)
static local_gain get_max_local_gain(DynamicAudioNormalizerContext *s, AVFrame *frame, int channel)
static double compute_frame_std_dev(DynamicAudioNormalizerContext *s, AVFrame *frame, int channel)
static int cqueue_size(cqueue *q)
static double minimum_filter(cqueue *q)
static double cqueue_peek(cqueue *q, int index)
static void update_gain_history(DynamicAudioNormalizerContext *s, int channel, local_gain gain)
static void cqueue_free(cqueue *q)
static double find_peak_magnitude(AVFrame *frame, int channel)
static int config_input(AVFilterLink *inlink)
static double pow_2(const double value)
static int bypass_channel(DynamicAudioNormalizerContext *s, AVFrame *frame, int ch)
static void init_gaussian_filter(DynamicAudioNormalizerContext *s)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
#define MIN_FILTER_SIZE
static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **frame)
static int cqueue_dequeue(cqueue *q, double *element)
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
static int activate(AVFilterContext *ctx)
static av_cold void uninit(AVFilterContext *ctx)
static double fade(double prev, double next, int pos, int length)
static double gaussian_filter(DynamicAudioNormalizerContext *s, cqueue *q, cqueue *tq)
#define MAX_FILTER_SIZE
static int amplify_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
#define OFFSET(x)
static const AVFilterPad avfilter_af_dynaudnorm_inputs[]
static FILE * out
static AVFormatContext * ctx
channels
Definition aptx.h:31
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
Definition audio.c:34
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition audio.c:74
simple assert() macros that are a bit more flexible than ISO C assert().
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
Definition avassert.h:68
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition avassert.h:42
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:1472
int ff_inlink_check_available_samples(AVFilterLink *link, unsigned min)
Test if enough samples are available on the link.
Definition avfilter.c:1506
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1073
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:911
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition avfilter.c:1701
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:1545
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition avfilter.c:851
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.
Definition avfilter.c:229
Main libavfilter public API header.
static void ff_bufqueue_add(void *log, struct FFBufQueue *queue, AVFrame *buf)
Add a buffer to the queue.
Definition bufferqueue.h:71
static void ff_bufqueue_discard_all(struct FFBufQueue *queue)
Unref and remove all buffers from the queue.
static AVFrame * ff_bufqueue_get(struct FFBufQueue *queue)
Get the first buffer from the queue and remove it.
Definition bufferqueue.h:98
#define flags(name, subs,...)
Definition cbs_h264.c:74
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
Public libavutil channel layout APIs header.
#define FLAGS
Definition cmdutils.c:596
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static __device__ float fabs(float a)
#define min(a, b)
#define max(a, b)
static AVFrame * frame
double fmin(double, double)
double fmax(double, double)
void(* flush)(AVBSFContext *ctx)
Definition dts2pts.c:610
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
channel
Use these values when setting the channel map with ebur128_set_channel().
Definition ebur128.h:39
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition eval.c:368
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition eval.c:824
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition eval.c:735
double value
Definition eval.c:102
int8_t exp
Definition eval.c:76
simple arithmetic expression evaluator
static SDL_Window * window
Definition ffplay.c:442
static const uint8_t frame_size[4]
Definition g723_1.h:222
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_DOUBLE
Underlying C type is double.
Definition opt.h:266
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition avfilter.h:172
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
Definition avfilter.h:210
int av_channel_layout_from_string(AVChannelLayout *channel_layout, const char *str)
Initialize a channel layout from a given string description.
int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, enum AVChannel channel)
Get the index of a given channel in a channel layout.
enum AVChannel av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx)
Get the channel with the given index in a channel layout.
void av_channel_layout_uninit(AVChannelLayout *channel_layout)
Free any allocated data in the channel layout and reset the channel count to 0.
AVChannel
int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
Make a copy of a channel layout.
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition frame.c:535
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
Definition frame.c:711
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition log.h:216
static AVRational av_make_q(int num, int den)
Create an AVRational.
Definition rational.h:71
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AV_SAMPLE_FMT_DBLP
double, planar
Definition samplefmt.h:67
int av_samples_copy(uint8_t *const *dst, uint8_t *const *src, int dst_offset, int src_offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Copy samples from src to dst.
Definition samplefmt.c:223
int index
Definition gxfenc.c:90
static const int weights[]
Definition hevc_pel.c:32
static av_cold void uninit(AVBitStreamFilterContext *ctx)
static int activate(AVBitStreamFilterContext *ctx)
unsigned offset
Definition libaomenc.c:763
const char * arg
Definition jacosubdec.c:65
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition filters.h:763
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
Definition filters.h:694
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:629
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
Definition filters.h:34
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition filters.h:639
static FilterLink * ff_filter_link(AVFilterLink *link)
Definition filters.h:199
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
Definition filters.h:257
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define CONST(name, help, val, u)
Definition vf_bwdif.c:189
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:97
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
#define M_PI
Definition mathematics.h:67
void * av_calloc(size_t nmemb, size_t size)
Definition mem.c:370
Memory handling functions.
static int adjust(int x, int size)
Definition mobiclip.c:514
static const uint64_t c2
Definition murmur3.c:53
static const uint64_t c1
Definition murmur3.c:52
var_name
Definition noise.c:46
@ VAR_VARS_NB
Definition noise.c:59
static const char *const var_names[]
Definition noise.c:30
#define av_malloc(s)
Definition ops_static.c:52
AVOptions.
@ VAR_SR
Definition setts.c:77
unsigned int pos
Definition spdifenc.c:431
An AVChannelLayout holds information about the channel layout of audio data.
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
Definition eval.c:171
An instance of a filter.
Definition avfilter.h:279
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:479
int nb_samples
number of audio samples (per channel) described by this frame
Definition frame.h:559
uint8_t ** extended_data
pointers to the data planes/channels.
Definition frame.h:540
AVOption.
Definition opt.h:428
double var_values[VAR_VARS_NB]
Structure holding the queue.
Definition bufferqueue.h:49
Used for passing data between threads.
Definition v210dec.c:35
AVFrame * out
double * elements
int max_size
int nb_elements
double threshold
double max_gain
#define lrint
Definition tablegen.h:53
#define llrint
Definition tablegen.h:47
#define av_free(p)
#define av_malloc_array(a, b)
#define av_freep(p)
#define av_log(a,...)
#define src
Definition vp8dsp.c:248
static int64_t pts
int size
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
static double limit(double x)
static double c[64]