Showing the changes to libavfilter (1 of 2 files). Show all
Unified · Split
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | |
| 29 | 29 | #include "libavutil/avassert.h" |
| 30 | 30 | #include "libavutil/channel_layout.h" |
| 31 | +#include "libavutil/eval.h" | |
| 31 | 32 | #include "libavutil/opt.h" |
| 32 | 33 | |
| 33 | 34 | #define MIN_FILTER_SIZE 3 |
| @@ -41,6 +42,26 @@ · 7 unmodified lines | ||
| 41 | 42 | #include "filters.h" |
| 42 | 43 | #include "internal.h" |
| 43 | 44 | |
| 45 | +static 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 | + | |
| 55 | +enum 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 | + | |
| 44 | 65 | typedef struct local_gain { |
| 45 | 66 | double max_gain; |
| 46 | 67 | double threshold; |
| @@ -65,6 +86,7 @@ typedef struct DynamicAudioNormalizerContext { · 18 unmodified lines | ||
| 65 | 86 | int channels_coupled; |
| 66 | 87 | int alt_boundary_mode; |
| 67 | 88 | double overlap; |
| 89 | + char *expr_str; | |
| 68 | 90 | |
| 69 | 91 | double peak_value; |
| 70 | 92 | double max_amplification; |
| @@ -91,6 +113,9 @@ typedef struct DynamicAudioNormalizerContext { · 20 unmodified lines | ||
| 91 | 113 | cqueue *is_enabled; |
| 92 | 114 | |
| 93 | 115 | AVFrame *window; |
| 116 | + | |
| 117 | + AVExpr *expr; | |
| 118 | + double var_values[VAR_VARS_NB]; | |
| 94 | 119 | } DynamicAudioNormalizerContext; |
| 95 | 120 | |
| 96 | 121 | typedef struct ThreadData { |
| @@ -122,10 +147,12 @@ static const AVOption dynaudnorm_options[] = { · 25 unmodified lines | ||
| 122 | 147 | { "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS }, |
| 123 | 148 | { "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS }, |
| 124 | 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 }, | |
| 126 | − { "h", "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 }, | |
| 151 | + { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS }, | |
| 127 | 152 | { "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS }, |
| 128 | 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 | 156 | { NULL } |
| 130 | 157 | }; |
| 131 | 158 | |
| @@ -309,12 +336,15 @@ static av_cold void uninit(AVFilterContext *ctx) · 177 unmodified lines | ||
| 309 | 336 | ff_bufqueue_discard_all(&s->queue); |
| 310 | 337 | |
| 311 | 338 | av_frame_free(&s->window); |
| 339 | + av_expr_free(s->expr); | |
| 340 | + s->expr = NULL; | |
| 312 | 341 | } |
| 313 | 342 | |
| 314 | 343 | static int config_input(AVFilterLink *inlink) |
| 315 | 344 | { |
| 316 | 345 | AVFilterContext *ctx = inlink->dst; |
| 317 | 346 | DynamicAudioNormalizerContext *s = ctx->priv; |
| 347 | + int ret = 0; | |
| 318 | 348 | |
| 319 | 349 | uninit(ctx); |
| 320 | 350 | |
| @@ -358,7 +388,13 @@ static int config_input(AVFilterLink *inlink) · 37 unmodified lines | ||
| 358 | 388 | return AVERROR(ENOMEM); |
| 359 | 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 | |
| 364 | 400 | static 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 | 469 | const double peak_magnitude = find_peak_magnitude(frame, channel); |
| 434 | 470 | const double maximum_gain = s->peak_value / peak_magnitude; |
| 435 | 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 | 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 | 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 | 489 | return gain; |
| 442 | 490 | } |
| @@ -731,6 +779,9 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame ** · 288 unmodified lines | ||
| 731 | 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 | 785 | if (s->channels_coupled) { |
| 735 | 786 | const local_gain gain = get_max_local_gain(s, analyze_frame, -1); |
| 736 | 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 | 1003 | s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec); |
| 953 | 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 | 1011 | return 0; |
| 956 | 1012 | } |
| 957 | 1013 | |