Go to the documentation of this file.
34 #define MIN_FILTER_SIZE 3
35 #define MAX_FILTER_SIZE 301
37 #define FF_BUFQUEUE_SIZE (MAX_FILTER_SIZE + 1)
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
165 if (!(
s->filter_size & 1)) {
266 for (
int i = 0;
i < side;
i++)
270 int count = (q->
size - new_size + 1) / 2;
281 double total_weight = 0.0;
282 const double sigma = (((
s->filter_size / 2.0) - 1.0) / 3.0) + (1.0 / 3.0);
286 const int offset =
s->filter_size / 2;
287 const double c1 = 1.0 / (sigma * sqrt(2.0 *
M_PI));
288 const double c2 = 2.0 * sigma * sigma;
291 for (
int i = 0;
i <
s->filter_size;
i++) {
295 total_weight +=
s->weights[
i];
299 adjust = 1.0 / total_weight;
300 for (
int i = 0;
i <
s->filter_size;
i++) {
313 for (
int c = 0;
c <
s->channels;
c++) {
314 if (
s->gain_history_original)
316 if (
s->gain_history_minimum)
318 if (
s->gain_history_smoothed)
320 if (
s->threshold_history)
330 s->is_enabled =
NULL;
351 s->channels =
inlink->ch_layout.nb_channels;
355 s->prev_amplification_factor =
av_malloc_array(
inlink->ch_layout.nb_channels,
sizeof(*
s->prev_amplification_factor));
356 s->dc_correction_value =
av_calloc(
inlink->ch_layout.nb_channels,
sizeof(*
s->dc_correction_value));
357 s->compress_threshold =
av_calloc(
inlink->ch_layout.nb_channels,
sizeof(*
s->compress_threshold));
358 s->gain_history_original =
av_calloc(
inlink->ch_layout.nb_channels,
sizeof(*
s->gain_history_original));
359 s->gain_history_minimum =
av_calloc(
inlink->ch_layout.nb_channels,
sizeof(*
s->gain_history_minimum));
360 s->gain_history_smoothed =
av_calloc(
inlink->ch_layout.nb_channels,
sizeof(*
s->gain_history_smoothed));
361 s->threshold_history =
av_calloc(
inlink->ch_layout.nb_channels,
sizeof(*
s->threshold_history));
364 if (!
s->prev_amplification_factor || !
s->dc_correction_value ||
365 !
s->compress_threshold ||
366 !
s->gain_history_original || !
s->gain_history_minimum ||
367 !
s->gain_history_smoothed || !
s->threshold_history ||
368 !
s->is_enabled || !
s->weights)
371 for (
int c = 0;
c <
inlink->ch_layout.nb_channels;
c++) {
372 s->prev_amplification_factor[
c] = 1.0;
379 if (!
s->gain_history_original[
c] || !
s->gain_history_minimum[
c] ||
380 !
s->gain_history_smoothed[
c] || !
s->threshold_history[
c])
389 s->sample_advance =
FFMAX(1,
lrint(
s->frame_len * (1. -
s->overlap)));
400 static inline double fade(
double prev,
double next,
int pos,
int length)
402 const double step_size = 1.0 / length;
403 const double f0 = 1.0 - (step_size * (
pos + 1.0));
404 const double f1 = 1.0 - f0;
405 return f0 * prev + f1 * next;
413 static inline double bound(
const double threshold,
const double val)
415 const double CONST = 0.8862269254527580136490837416705725913987747280611935;
421 double max = DBL_EPSILON;
442 double rms_value = 0.0;
449 rms_value +=
pow_2(data_ptr[
i]);
457 rms_value +=
pow_2(data_ptr[
i]);
463 return fmax(sqrt(rms_value), DBL_EPSILON);
470 const double maximum_gain =
s->peak_value / peak_magnitude;
472 double target_gain = DBL_MAX;
478 memcpy(var_values,
s->var_values,
sizeof(var_values));
481 var_values[
VAR_P] = peak_magnitude;
483 target_gain =
av_expr_eval(
s->expr, var_values,
s) / peak_magnitude;
486 gain.
threshold = peak_magnitude >
s->threshold;
494 double min = DBL_MAX;
506 double result = 0.0, tsum = 0.0;
526 const int pre_fill_size =
s->filter_size / 2;
529 s->prev_amplification_factor[
channel] = initial_value;
543 const int pre_fill_size =
s->filter_size / 2;
544 double initial_value =
s->alt_boundary_mode ?
cqueue_peek(
s->gain_history_original[
channel], 0) : 1.0;
545 int input = pre_fill_size;
564 double smoothed,
limit;
582 const int start = (
channels * jobnr) / nb_jobs;
583 const int end = (
channels * (jobnr+1)) / nb_jobs;
585 for (
int c = start;
c < end;
c++)
591 static inline double update_value(
double new,
double old,
double aggressiveness)
593 av_assert0((aggressiveness >= 0.0) && (aggressiveness <= 1.0));
594 return aggressiveness *
new + (1.0 - aggressiveness) * old;
607 int is_first_frame =
cqueue_empty(
s->gain_history_original[0]);
609 for (
int c = 0;
c <
s->channels;
c++) {
612 double current_average_value = 0.0;
616 current_average_value += dst_ptr[
i] *
diff;
618 prev_value = is_first_frame ? current_average_value :
s->dc_correction_value[
c];
619 s->dc_correction_value[
c] = is_first_frame ? current_average_value :
update_value(current_average_value,
s->dc_correction_value[
c], 0.1);
629 if ((threshold > DBL_EPSILON) && (threshold < (1.0 - DBL_EPSILON))) {
630 double current_threshold = threshold;
631 double step_size = 1.0;
633 while (step_size > DBL_EPSILON) {
634 while ((
llrint((current_threshold + step_size) * (UINT64_C(1) << 63)) >
635 llrint(current_threshold * (UINT64_C(1) << 63))) &&
636 (
bound(current_threshold + step_size, 1.0) <= threshold)) {
637 current_threshold += step_size;
643 return current_threshold;
652 double variance = 0.0;
655 for (
int c = 0;
c <
s->channels;
c++) {
659 variance +=
pow_2(data_ptr[
i]);
667 variance +=
pow_2(data_ptr[
i]);
672 return fmax(sqrt(variance), DBL_EPSILON);
677 int is_first_frame =
cqueue_empty(
s->gain_history_original[0]);
679 if (
s->channels_coupled) {
681 const double current_threshold =
fmin(1.0,
s->compress_factor * standard_deviation);
683 const double prev_value = is_first_frame ? current_threshold :
s->compress_threshold[0];
684 double prev_actual_thresh, curr_actual_thresh;
685 s->compress_threshold[0] = is_first_frame ? current_threshold :
update_value(current_threshold,
s->compress_threshold[0], (1.0/3.0));
690 for (
int c = 0;
c <
s->channels;
c++) {
703 for (
int c = 0;
c <
s->channels;
c++) {
707 const double prev_value = is_first_frame ? current_threshold :
s->compress_threshold[
c];
708 double prev_actual_thresh, curr_actual_thresh;
711 s->compress_threshold[
c] = is_first_frame ? current_threshold :
update_value(current_threshold,
s->compress_threshold[
c], 1.0/3.0);
730 if (
s->dc_correction ||
s->compress_factor > DBL_EPSILON) {
758 if (
s->dc_correction)
761 if (
s->compress_factor > DBL_EPSILON)
764 if (
s->frame_len !=
s->sample_advance) {
765 const int offset =
s->frame_len -
s->sample_advance;
767 for (
int c = 0;
c <
s->channels;
c++) {
768 double *
src = (
double *)
s->window->extended_data[
c];
770 memmove(
src, &
src[
s->sample_advance],
offset *
sizeof(
double));
771 memcpy(&
src[
offset], (*frame)->extended_data[
c], (*frame)->nb_samples *
sizeof(
double));
772 memset(&
src[
offset + (*frame)->nb_samples], 0, (
s->sample_advance - (*frame)->nb_samples) *
sizeof(
double));
778 FFMIN(
s->frame_len, (*frame)->nb_samples), (*frame)->ch_layout.nb_channels, (*frame)->format);
785 if (
s->channels_coupled) {
787 for (
int c = 0;
c <
s->channels;
c++)
803 double current_amplification_factor;
808 const double amplification_factor =
fade(
s->prev_amplification_factor[
c],
809 current_amplification_factor,
i,
812 dst_ptr[
i] = src_ptr[
i] * amplification_factor;
815 s->prev_amplification_factor[
c] = current_amplification_factor;
824 const int enabled =
td->enabled;
826 const int start = (
channels * jobnr) / nb_jobs;
827 const int end = (
channels * (jobnr+1)) / nb_jobs;
829 for (
int ch = start; ch < end; ch++)
843 while (((
s->queue.available >=
s->filter_size) ||
844 (
s->eof &&
s->queue.available)) &&
865 td.enabled = is_enabled > 0.;
899 for (
int c = 0;
c <
s->channels;
c++) {
900 double *dst_ptr = (
double *)
out->extended_data[
c];
902 for (
int i = 0;
i <
out->nb_samples;
i++) {
903 dst_ptr[
i] =
s->alt_boundary_mode ? DBL_EPSILON : ((
s->target_rms > DBL_EPSILON) ?
fmin(
s->peak_value,
s->target_rms) :
s->peak_value);
904 if (
s->dc_correction) {
905 dst_ptr[
i] *= ((
i % 2) == 1) ? -1 : 1;
906 dst_ptr[
i] +=
s->dc_correction_value[
c];
921 for (
int c = 0;
c <
s->channels;
c++)
940 if (strcmp(
s->channels_to_filter,
"all"))
966 if (
s->eof &&
s->queue.available)
967 return flush(outlink);
969 if (
s->eof && !
s->queue.available) {
981 char *res,
int res_len,
int flags)
985 int prev_filter_size =
s->filter_size;
993 if (prev_filter_size !=
s->filter_size) {
996 for (
int c = 0;
c <
s->channels;
c++) {
1004 s->sample_advance =
FFMAX(1,
lrint(
s->frame_len * (1. -
s->overlap)));
1023 .
name =
"dynaudnorm",
1032 .priv_class = &dynaudnorm_class,
static int config_input(AVFilterLink *inlink)
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.
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
#define AV_LOG_WARNING
Something somehow does not look correct.
static int flush_buffer(DynamicAudioNormalizerContext *s, AVFilterLink *inlink, AVFilterLink *outlink)
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
#define CONST(name, help, val, u)
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
#define AVERROR_EOF
End of file.
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
AVFILTER_DEFINE_CLASS(dynaudnorm)
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is inlink
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
This structure describes decoded (raw) audio or video data.
static av_cold int init(AVFilterContext *ctx)
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.
double * dc_correction_value
static void cqueue_resize(cqueue *q, int new_size)
const char * name
Filter name.
int nb_channels
Number of channels in this layout.
A link between two filters.
static const AVFilterPad avfilter_af_dynaudnorm_inputs[]
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
static int amplify_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static double find_peak_magnitude(AVFrame *frame, int channel)
static AVFrame * ff_bufqueue_get(struct FFBufQueue *queue)
Get the first buffer from the queue and remove it.
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.
static double val(void *priv, double ch)
AVChannelLayout ch_layout
Channel layout of the audio data.
char * channels_to_filter
static cqueue * cqueue_create(int size, int max_size)
static int activate(AVFilterContext *ctx)
static int update_gain_histories(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static double update_value(double new, double old, double aggressiveness)
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
A filter pad used for either input or output.
int ff_inlink_check_available_samples(AVFilterLink *link, unsigned min)
Test if enough samples are available on the link.
static int frame_size(int sample_rate, int frame_len_msec)
static double minimum_filter(cqueue *q)
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
AVChannelLayout ch_layout
static int cqueue_empty(cqueue *q)
static int adjust(int x, int size)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
static av_always_inline double copysign(double x, double y)
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
static int cqueue_size(cqueue *q)
static av_cold void uninit(AVFilterContext *ctx)
#define FILTER_INPUTS(array)
Describe the class of an AVClass context structure.
and forward the result(frame or status change) to the corresponding input. If nothing is possible
static __device__ float fabs(float a)
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.
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
static local_gain get_max_local_gain(DynamicAudioNormalizerContext *s, AVFrame *frame, int channel)
static double pow_2(const double value)
static void perform_dc_correction(DynamicAudioNormalizerContext *s, AVFrame *frame)
static void ff_bufqueue_discard_all(struct FFBufQueue *queue)
Unref and remove all buffers from the queue.
static int flush(AVFilterLink *outlink)
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
cqueue ** threshold_history
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
static int analyze_frame(AVFilterContext *ctx, AVFilterLink *outlink, AVFrame **frame)
static int cqueue_enqueue(cqueue *q, double element)
static double compute_frame_std_dev(DynamicAudioNormalizerContext *s, AVFrame *frame, int channel)
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
An AVChannelLayout holds information about the channel layout of audio data.
int av_frame_copy(AVFrame *dst, const AVFrame *src)
Copy the frame data from src to dst.
double * prev_amplification_factor
double var_values[VAR_VARS_NB]
double fmin(double, double)
static AVRational av_make_q(int num, int den)
Create an AVRational.
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
int64_t sample_count_in
Number of past samples sent through the link.
static int cqueue_pop(cqueue *q)
AVFilterContext * src
source filter
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.
static av_always_inline int diff(const struct color_info *a, const struct color_info *b, const int trans_thresh)
static void cqueue_free(cqueue *q)
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
const AVFilter ff_af_dynaudnorm
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf offset
FF_FILTER_FORWARD_WANTED(outlink, inlink)
static void ff_bufqueue_add(void *log, struct FFBufQueue *queue, AVFrame *buf)
Add a buffer to the queue.
and forward the test the status of outputs and forward it to the corresponding return FFERROR_NOT_READY If the filters stores internally one or a few frame for some input
static const char *const var_names[]
double * compress_threshold
static void update_gain_history(DynamicAudioNormalizerContext *s, int channel, local_gain gain)
int sample_rate
samples per second
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
int av_channel_layout_from_string(AVChannelLayout *channel_layout, const char *str)
Initialize a channel layout from a given string description.
int nb_samples
number of audio samples (per channel) described by this frame
#define i(width, name, range_min, range_max)
Structure holding the queue.
uint8_t ** extended_data
pointers to the data planes/channels.
#define av_malloc_array(a, b)
static const int weights[]
cqueue ** gain_history_minimum
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Used for passing data between threads.
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this just let it vf default value
static double gaussian_filter(DynamicAudioNormalizerContext *s, cqueue *q, cqueue *tq)
const char * name
Pad name.
void * av_calloc(size_t nmemb, size_t size)
static double erf(double z)
erf function Algorithm taken from the Boost project, source: http://www.boost.org/doc/libs/1_46_1/boo...
static double limit(double x)
static double bound(const double threshold, const double val)
static void amplify_channel(DynamicAudioNormalizerContext *s, AVFrame *in, AVFrame *frame, int enabled, int c)
static double cqueue_peek(cqueue *q, int index)
static double compute_frame_rms(AVFrame *frame, int channel)
double fmax(double, double)
static void init_gaussian_filter(DynamicAudioNormalizerContext *s)
static const AVOption dynaudnorm_options[]
cqueue ** gain_history_original
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.
void av_channel_layout_uninit(AVChannelLayout *channel_layout)
Free any allocated data in the channel layout and reset the channel count to 0.
@ AV_SAMPLE_FMT_DBLP
double, planar
AVRational time_base
Define the time base used by the PTS of the frames/samples which will pass through this link.
int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src)
Make a copy of a channel layout.
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
static int bypass_channel(DynamicAudioNormalizerContext *s, AVFrame *frame, int ch)
#define FILTER_OUTPUTS(array)
static double fade(double prev, double next, int pos, int length)
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL
Same as AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, except that the filter will have its filter_frame() c...
#define flags(name, subs,...)
static void perform_compression(DynamicAudioNormalizerContext *s, AVFrame *frame)
static av_always_inline int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
static double setup_compress_thresh(double threshold)
cqueue ** gain_history_smoothed
static int cqueue_dequeue(cqueue *q, double *element)
void ff_filter_set_ready(AVFilterContext *filter, unsigned priority)
Mark a filter ready and schedule it for activation.