summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/filters.texi3
-rw-r--r--libavfilter/af_dynaudnorm.c25
2 files changed, 24 insertions, 4 deletions
diff --git a/doc/filters.texi b/doc/filters.texi
index 25a11fcd10..b3ae139613 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -4389,6 +4389,9 @@ If input frame volume is above this value frame will be normalized.
Otherwise frame may not be normalized at all. The default value is set
to 0, which means all input frames will be normalized.
This option is mostly useful if digital noise is not wanted to be amplified.
+
+@item channels, h
+Specify which channels to filter, by default all available channels are filtered.
@end table
@subsection Commands
diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c
index 4935b09d08..7d779856a8 100644
--- a/libavfilter/af_dynaudnorm.c
+++ b/libavfilter/af_dynaudnorm.c
@@ -27,6 +27,7 @@
#include <float.h>
#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
#include "libavutil/opt.h"
#define MIN_FILTER_SIZE 3
@@ -76,6 +77,7 @@ typedef struct DynamicAudioNormalizerContext {
int channels;
int eof;
+ uint64_t channels_to_filter;
int64_t pts;
cqueue **gain_history_original;
@@ -110,6 +112,8 @@ 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_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS },
+ { "h", "set channels to filter", OFFSET(channels_to_filter),AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS },
{ NULL }
};
@@ -514,6 +518,11 @@ static inline double update_value(double new, double old, double aggressiveness)
return aggressiveness * new + (1.0 - aggressiveness) * old;
}
+static inline int bypass_channel(DynamicAudioNormalizerContext *s, AVFrame *frame, int ch)
+{
+ return !(av_channel_layout_extract_channel(frame->channel_layout, ch) & s->channels_to_filter);
+}
+
static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *frame)
{
const double diff = 1.0 / frame->nb_samples;
@@ -521,6 +530,7 @@ static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *fra
int c, i;
for (c = 0; c < s->channels; c++) {
+ const int bypass = bypass_channel(s, frame, c);
double *dst_ptr = (double *)frame->extended_data[c];
double current_average_value = 0.0;
double prev_value;
@@ -531,7 +541,7 @@ static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *fra
prev_value = is_first_frame ? current_average_value : s->dc_correction_value[c];
s->dc_correction_value[c] = is_first_frame ? current_average_value : update_value(current_average_value, s->dc_correction_value[c], 0.1);
- for (i = 0; i < frame->nb_samples; i++) {
+ for (i = 0; i < frame->nb_samples && !bypass; i++) {
dst_ptr[i] -= fade(prev_value, s->dc_correction_value[c], i, frame->nb_samples);
}
}
@@ -604,6 +614,11 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame
for (c = 0; c < s->channels; c++) {
double *const dst_ptr = (double *)frame->extended_data[c];
+ const int bypass = bypass_channel(s, frame, c);
+
+ if (bypass)
+ continue;
+
for (i = 0; i < frame->nb_samples; i++) {
const double localThresh = fade(prev_actual_thresh, curr_actual_thresh, i, frame->nb_samples);
dst_ptr[i] = copysign(bound(localThresh, fabs(dst_ptr[i])), dst_ptr[i]);
@@ -611,19 +626,20 @@ static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame
}
} else {
for (c = 0; c < s->channels; c++) {
+ const int bypass = bypass_channel(s, frame, c);
const double standard_deviation = compute_frame_std_dev(s, frame, c);
const double current_threshold = setup_compress_thresh(FFMIN(1.0, s->compress_factor * standard_deviation));
-
const double prev_value = is_first_frame ? current_threshold : s->compress_threshold[c];
double prev_actual_thresh, curr_actual_thresh;
double *dst_ptr;
+
s->compress_threshold[c] = is_first_frame ? current_threshold : update_value(current_threshold, s->compress_threshold[c], 1.0/3.0);
prev_actual_thresh = setup_compress_thresh(prev_value);
curr_actual_thresh = setup_compress_thresh(s->compress_threshold[c]);
dst_ptr = (double *)frame->extended_data[c];
- for (i = 0; i < frame->nb_samples; i++) {
+ for (i = 0; i < frame->nb_samples && !bypass; i++) {
const double localThresh = fade(prev_actual_thresh, curr_actual_thresh, i, frame->nb_samples);
dst_ptr[i] = copysign(bound(localThresh, fabs(dst_ptr[i])), dst_ptr[i]);
}
@@ -668,13 +684,14 @@ static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *in,
int c, i;
for (c = 0; c < s->channels; c++) {
+ const int bypass = bypass_channel(s, frame, c);
const double *src_ptr = (const double *)in->extended_data[c];
double *dst_ptr = (double *)frame->extended_data[c];
double current_amplification_factor;
cqueue_dequeue(s->gain_history_smoothed[c], &current_amplification_factor);
- for (i = 0; i < frame->nb_samples && enabled; i++) {
+ for (i = 0; i < frame->nb_samples && enabled && !bypass; i++) {
const double amplification_factor = fade(s->prev_amplification_factor[c],
current_amplification_factor, i,
frame->nb_samples);