History

avfilter/af_dynaudnorm: add curve option

Paul B Mahol committed 4 years ago

Commit 8e963191 parent a0c7c9d2 files · +88 −5Browse files

Showing the changes to libavfilter (1 of 2 files). Show all

Unified · Split

libavfilter/af_dynaudnorm.c+61−5
@@ -28,6 +28,7 @@ · 27 unmodified lines
28 28
29#include "libavutil/avassert.h"29#include "libavutil/avassert.h"
30#include "libavutil/channel_layout.h"30#include "libavutil/channel_layout.h"
31#include "libavutil/eval.h"
31#include "libavutil/opt.h"32#include "libavutil/opt.h"
32 33
33#define MIN_FILTER_SIZE 334#define MIN_FILTER_SIZE 3
@@ -41,6 +42,26 @@ · 7 unmodified lines
41#include "filters.h"42#include "filters.h"
42#include "internal.h"43#include "internal.h"
43 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
55enum var_name {
56 VAR_CH,
57 VAR_SN,
58 VAR_NB_CHANNELS,
59 VAR_T,
60 VAR_SR,
61 VAR_P,
62 VAR_VARS_NB
63};
64
44typedef struct local_gain {65typedef struct local_gain {
45 double max_gain;66 double max_gain;
46 double threshold;67 double threshold;
@@ -65,6 +86,7 @@ typedef struct DynamicAudioNormalizerContext { · 18 unmodified lines
65 int channels_coupled;86 int channels_coupled;
66 int alt_boundary_mode;87 int alt_boundary_mode;
67 double overlap;88 double overlap;
89 char *expr_str;
68 90
69 double peak_value;91 double peak_value;
70 double max_amplification;92 double max_amplification;
@@ -91,6 +113,9 @@ typedef struct DynamicAudioNormalizerContext { · 20 unmodified lines
91 cqueue *is_enabled;113 cqueue *is_enabled;
92 114
93 AVFrame *window;115 AVFrame *window;
116
117 AVExpr *expr;
118 double var_values[VAR_VARS_NB];
94} DynamicAudioNormalizerContext;119} DynamicAudioNormalizerContext;
95 120
96typedef struct ThreadData {121typedef struct ThreadData {
@@ -122,10 +147,12 @@ static const AVOption dynaudnorm_options[] = { · 25 unmodified lines
122 { "s", "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 },
123 { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },148 { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
124 { "t", "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 },
125 { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },150 { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
126 { "h", "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 },
127 { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },152 { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
128 { "o", "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 },
129 { NULL }156 { NULL }
130};157};
131 158
@@ -309,12 +336,15 @@ static av_cold void uninit(AVFilterContext *ctx) · 177 unmodified lines
309 ff_bufqueue_discard_all(&s->queue);336 ff_bufqueue_discard_all(&s->queue);
310 337
311 av_frame_free(&s->window);338 av_frame_free(&s->window);
339 av_expr_free(s->expr);
340 s->expr = NULL;
312}341}
313 342
314static int config_input(AVFilterLink *inlink)343static int config_input(AVFilterLink *inlink)
315{344{
316 AVFilterContext *ctx = inlink->dst;345 AVFilterContext *ctx = inlink->dst;
317 DynamicAudioNormalizerContext *s = ctx->priv;346 DynamicAudioNormalizerContext *s = ctx->priv;
347 int ret = 0;
318 348
319 uninit(ctx);349 uninit(ctx);
320 350
@@ -358,7 +388,13 @@ static int config_input(AVFilterLink *inlink) · 37 unmodified lines
358 return AVERROR(ENOMEM);388 return AVERROR(ENOMEM);
359 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));389 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
360 390
361 return 0;391 s->var_values[VAR_SR] = inlink->sample_rate;
392 s->var_values[VAR_NB_CHANNELS] = s->channels;
393
394 if (s->expr_str)
395 ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
396 NULL, NULL, 0, ctx);
397 return ret;
362}398}
363 399
364static inline double fade(double prev, double next, int pos, int length)400static inline double fade(double prev, double next, int pos, int length)
@@ -433,10 +469,22 @@ static local_gain get_max_local_gain(DynamicAudioNormalizerContext *s, AVFrame * · 68 unmodified lines
433 const double peak_magnitude = find_peak_magnitude(frame, channel);469 const double peak_magnitude = find_peak_magnitude(frame, channel);
434 const double maximum_gain = s->peak_value / peak_magnitude;470 const double maximum_gain = s->peak_value / peak_magnitude;
435 const double rms_gain = s->target_rms > DBL_EPSILON ? (s->target_rms / compute_frame_rms(frame, channel)) : DBL_MAX;471 const double rms_gain = s->target_rms > DBL_EPSILON ? (s->target_rms / compute_frame_rms(frame, channel)) : DBL_MAX;
472 double target_gain = DBL_MAX;
436 local_gain gain;473 local_gain gain;
437 474
475 if (s->expr_str) {
476 double var_values[VAR_VARS_NB];
477
478 memcpy(var_values, s->var_values, sizeof(var_values));
479
480 var_values[VAR_CH] = channel;
481 var_values[VAR_P] = peak_magnitude;
482
483 target_gain = av_expr_eval(s->expr, var_values, s) / peak_magnitude;
484 }
485
438 gain.threshold = peak_magnitude > s->threshold;486 gain.threshold = peak_magnitude > s->threshold;
439 gain.max_gain = bound(s->max_amplification, fmin(maximum_gain, rms_gain));487 gain.max_gain = bound(s->max_amplification, fmin(target_gain, fmin(maximum_gain, rms_gain)));
440 488
441 return gain;489 return gain;
442}490}
@@ -731,6 +779,9 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame ** · 288 unmodified lines
731 analyze_frame = *frame;779 analyze_frame = *frame;
732 }780 }
733 781
782 s->var_values[VAR_SN] = outlink->sample_count_in;
783 s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate;
784
734 if (s->channels_coupled) {785 if (s->channels_coupled) {
735 const local_gain gain = get_max_local_gain(s, analyze_frame, -1);786 const local_gain gain = get_max_local_gain(s, analyze_frame, -1);
736 for (int c = 0; c < s->channels; c++)787 for (int c = 0; c < s->channels; c++)
@@ -951,7 +1002,12 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar · 214 unmodified lines
951 1002
952 s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);1003 s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
953 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));1004 s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
954 1005 if (s->expr_str) {
1006 ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
1007 NULL, NULL, 0, ctx);
1008 if (ret < 0)
1009 return ret;
1010 }
955 return 0;1011 return 0;
956}1012}
957 1013

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t