Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FFmpeg/FFmpeg.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2022-11-08 17:17:50 +0300
committerPaul B Mahol <onemda@gmail.com>2022-11-10 21:16:05 +0300
commit8e9631967427106468cfaf1d258ecddc06db39ff (patch)
treeb9f980f7749dc740b7d7b9d4e1eaff6f686dc4da
parenta0c7c9d636c53e87a7f7265d04662c8b7e750101 (diff)
avfilter/af_dynaudnorm: add curve option
-rw-r--r--doc/filters.texi27
-rw-r--r--libavfilter/af_dynaudnorm.c66
2 files changed, 88 insertions, 5 deletions
diff --git a/doc/filters.texi b/doc/filters.texi
index 910fc1fe79..5b49687645 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -4587,6 +4587,33 @@ Using >0 and <1 values will make less conservative gain adjustments, like
when framelen option is set to smaller value, if framelen option value is
compensated for non-zero overlap then gain adjustments will be smoother across time
compared to zero overlap case.
+
+@item curve, v
+Specify the peak mapping curve expression which is going to be used when calculating
+gain applied to frames. The max output frame gain will still be limited by other
+options mentioned previously for this filter.
+
+The expression can contain the following constants:
+
+@table @option
+@item ch
+current channel number
+
+@item sn
+current sample number
+
+@item nb_channels
+number of channels
+
+@item t
+timestamp expressed in seconds
+
+@item sr
+sample rate
+
+@item p
+current frame peak value
+@end table
@end table
@subsection Commands
diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c
index 88d1b382f3..e9d8ad8ec8 100644
--- a/libavfilter/af_dynaudnorm.c
+++ b/libavfilter/af_dynaudnorm.c
@@ -28,6 +28,7 @@
#include "libavutil/avassert.h"
#include "libavutil/channel_layout.h"
+#include "libavutil/eval.h"
#include "libavutil/opt.h"
#define MIN_FILTER_SIZE 3
@@ -41,6 +42,26 @@
#include "filters.h"
#include "internal.h"
+static const char * const var_names[] = {
+ "ch", ///< the value of the current channel
+ "sn", ///< number of samples
+ "nb_channels",
+ "t", ///< timestamp expressed in seconds
+ "sr", ///< sample rate
+ "p", ///< peak value
+ NULL
+};
+
+enum var_name {
+ VAR_CH,
+ VAR_SN,
+ VAR_NB_CHANNELS,
+ VAR_T,
+ VAR_SR,
+ VAR_P,
+ VAR_VARS_NB
+};
+
typedef struct local_gain {
double max_gain;
double threshold;
@@ -65,6 +86,7 @@ typedef struct DynamicAudioNormalizerContext {
int channels_coupled;
int alt_boundary_mode;
double overlap;
+ char *expr_str;
double peak_value;
double max_amplification;
@@ -91,6 +113,9 @@ typedef struct DynamicAudioNormalizerContext {
cqueue *is_enabled;
AVFrame *window;
+
+ AVExpr *expr;
+ double var_values[VAR_VARS_NB];
} DynamicAudioNormalizerContext;
typedef struct ThreadData {
@@ -122,10 +147,12 @@ static const AVOption dynaudnorm_options[] = {
{ "s", "set the compress factor", OFFSET(compress_factor), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 30.0, FLAGS },
{ "threshold", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
{ "t", "set the threshold value", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.0}, 0.0, 1.0, FLAGS },
- { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
- { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
+ { "channels", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
+ { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_STRING, {.str="all"}, 0, 0, FLAGS },
{ "overlap", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
{ "o", "set the frame overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=.0}, 0.0, 1.0, FLAGS },
+ { "curve", "set the custom peak mapping curve",OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
+ { "v", "set the custom peak mapping curve",OFFSET(expr_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS },
{ NULL }
};
@@ -309,12 +336,15 @@ static av_cold void uninit(AVFilterContext *ctx)
ff_bufqueue_discard_all(&s->queue);
av_frame_free(&s->window);
+ av_expr_free(s->expr);
+ s->expr = NULL;
}
static int config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
DynamicAudioNormalizerContext *s = ctx->priv;
+ int ret = 0;
uninit(ctx);
@@ -358,7 +388,13 @@ static int config_input(AVFilterLink *inlink)
return AVERROR(ENOMEM);
s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
- return 0;
+ s->var_values[VAR_SR] = inlink->sample_rate;
+ s->var_values[VAR_NB_CHANNELS] = s->channels;
+
+ if (s->expr_str)
+ ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
+ NULL, NULL, 0, ctx);
+ return ret;
}
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 *
const double peak_magnitude = find_peak_magnitude(frame, channel);
const double maximum_gain = s->peak_value / peak_magnitude;
const double rms_gain = s->target_rms > DBL_EPSILON ? (s->target_rms / compute_frame_rms(frame, channel)) : DBL_MAX;
+ double target_gain = DBL_MAX;
local_gain gain;
+ if (s->expr_str) {
+ double var_values[VAR_VARS_NB];
+
+ memcpy(var_values, s->var_values, sizeof(var_values));
+
+ var_values[VAR_CH] = channel;
+ var_values[VAR_P] = peak_magnitude;
+
+ target_gain = av_expr_eval(s->expr, var_values, s) / peak_magnitude;
+ }
+
gain.threshold = peak_magnitude > s->threshold;
- gain.max_gain = bound(s->max_amplification, fmin(maximum_gain, rms_gain));
+ gain.max_gain = bound(s->max_amplification, fmin(target_gain, fmin(maximum_gain, rms_gain)));
return gain;
}
@@ -731,6 +779,9 @@ static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **
analyze_frame = *frame;
}
+ s->var_values[VAR_SN] = outlink->sample_count_in;
+ s->var_values[VAR_T] = s->var_values[VAR_SN] * (double)1/outlink->sample_rate;
+
if (s->channels_coupled) {
const local_gain gain = get_max_local_gain(s, analyze_frame, -1);
for (int c = 0; c < s->channels; c++)
@@ -951,7 +1002,12 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar
s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec);
s->sample_advance = FFMAX(1, lrint(s->frame_len * (1. - s->overlap)));
-
+ if (s->expr_str) {
+ ret = av_expr_parse(&s->expr, s->expr_str, var_names, NULL, NULL,
+ NULL, NULL, 0, ctx);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}