Go to the documentation of this file.
32 #define MIN_FILTER_SIZE 3
33 #define MAX_FILTER_SIZE 301
35 #define FF_BUFQUEUE_SIZE (MAX_FILTER_SIZE + 1)
89 #define OFFSET(x) offsetof(DynamicAudioNormalizerContext, x)
90 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
122 if (!(
s->filter_size & 1)) {
223 for (
int i = 0;
i < side;
i++)
227 int count = (q->
size - new_size + 1) / 2;
238 double total_weight = 0.0;
239 const double sigma = (((
s->filter_size / 2.0) - 1.0) / 3.0) + (1.0 / 3.0);
244 const int offset =
s->filter_size / 2;
245 const double c1 = 1.0 / (sigma * sqrt(2.0 *
M_PI));
246 const double c2 = 2.0 * sigma * sigma;
249 for (
i = 0;
i <
s->filter_size;
i++) {
253 total_weight +=
s->weights[
i];
257 adjust = 1.0 / total_weight;
258 for (
i = 0;
i <
s->filter_size;
i++) {
272 for (
c = 0;
c <
s->channels;
c++) {
273 if (
s->gain_history_original)
275 if (
s->gain_history_minimum)
277 if (
s->gain_history_smoothed)
279 if (
s->threshold_history)
289 s->is_enabled =
NULL;
304 s->channels =
inlink->channels;
309 s->dc_correction_value =
av_calloc(
inlink->channels,
sizeof(*
s->dc_correction_value));
310 s->compress_threshold =
av_calloc(
inlink->channels,
sizeof(*
s->compress_threshold));
311 s->gain_history_original =
av_calloc(
inlink->channels,
sizeof(*
s->gain_history_original));
312 s->gain_history_minimum =
av_calloc(
inlink->channels,
sizeof(*
s->gain_history_minimum));
313 s->gain_history_smoothed =
av_calloc(
inlink->channels,
sizeof(*
s->gain_history_smoothed));
314 s->threshold_history =
av_calloc(
inlink->channels,
sizeof(*
s->threshold_history));
317 if (!
s->prev_amplification_factor || !
s->dc_correction_value ||
318 !
s->compress_threshold ||
319 !
s->gain_history_original || !
s->gain_history_minimum ||
320 !
s->gain_history_smoothed || !
s->threshold_history ||
321 !
s->is_enabled || !
s->weights)
325 s->prev_amplification_factor[
c] = 1.0;
332 if (!
s->gain_history_original[
c] || !
s->gain_history_minimum[
c] ||
333 !
s->gain_history_smoothed[
c] || !
s->threshold_history[
c])
342 static inline double fade(
double prev,
double next,
int pos,
int length)
344 const double step_size = 1.0 / length;
345 const double f0 = 1.0 - (step_size * (
pos + 1.0));
346 const double f1 = 1.0 - f0;
347 return f0 * prev + f1 * next;
355 static inline double bound(
const double threshold,
const double val)
357 const double CONST = 0.8862269254527580136490837416705725913987747280611935;
363 double max = DBL_EPSILON;
367 for (
c = 0;
c <
frame->channels;
c++) {
368 double *data_ptr = (
double *)
frame->extended_data[
c];
374 double *data_ptr = (
double *)
frame->extended_data[
channel];
385 double rms_value = 0.0;
389 for (
c = 0;
c <
frame->channels;
c++) {
390 const double *data_ptr = (
double *)
frame->extended_data[
c];
393 rms_value +=
pow_2(data_ptr[
i]);
397 rms_value /=
frame->nb_samples *
frame->channels;
399 const double *data_ptr = (
double *)
frame->extended_data[
channel];
401 rms_value +=
pow_2(data_ptr[
i]);
404 rms_value /=
frame->nb_samples;
407 return FFMAX(sqrt(rms_value), DBL_EPSILON);
414 const double maximum_gain =
s->peak_value / peak_magnitude;
418 gain.
threshold = peak_magnitude >
s->threshold;
419 gain.max_gain =
bound(
s->max_amplification,
FFMIN(maximum_gain, rms_gain));
426 double min = DBL_MAX;
438 double result = 0.0, tsum = 0.0;
456 const int pre_fill_size =
s->filter_size / 2;
459 s->prev_amplification_factor[
channel] = initial_value;
473 const int pre_fill_size =
s->filter_size / 2;
474 double initial_value =
s->alt_boundary_mode ?
cqueue_peek(
s->gain_history_original[
channel], 0) : 1.0;
475 int input = pre_fill_size;
494 double smoothed,
limit;
507 static inline double update_value(
double new,
double old,
double aggressiveness)
509 av_assert0((aggressiveness >= 0.0) && (aggressiveness <= 1.0));
510 return aggressiveness *
new + (1.0 - aggressiveness) * old;
515 const double diff = 1.0 /
frame->nb_samples;
516 int is_first_frame =
cqueue_empty(
s->gain_history_original[0]);
519 for (
c = 0;
c <
s->channels;
c++) {
520 double *dst_ptr = (
double *)
frame->extended_data[
c];
521 double current_average_value = 0.0;
525 current_average_value += dst_ptr[
i] *
diff;
527 prev_value = is_first_frame ? current_average_value :
s->dc_correction_value[
c];
528 s->dc_correction_value[
c] = is_first_frame ? current_average_value :
update_value(current_average_value,
s->dc_correction_value[
c], 0.1);
530 for (
i = 0;
i <
frame->nb_samples;
i++) {
531 dst_ptr[
i] -=
fade(prev_value,
s->dc_correction_value[
c],
i,
frame->nb_samples);
538 if ((threshold > DBL_EPSILON) && (threshold < (1.0 - DBL_EPSILON))) {
539 double current_threshold = threshold;
540 double step_size = 1.0;
542 while (step_size > DBL_EPSILON) {
543 while ((
llrint((current_threshold + step_size) * (UINT64_C(1) << 63)) >
544 llrint(current_threshold * (UINT64_C(1) << 63))) &&
545 (
bound(current_threshold + step_size, 1.0) <= threshold)) {
546 current_threshold += step_size;
552 return current_threshold;
561 double variance = 0.0;
565 for (
c = 0;
c <
s->channels;
c++) {
566 const double *data_ptr = (
double *)
frame->extended_data[
c];
569 variance +=
pow_2(data_ptr[
i]);
572 variance /= (
s->channels *
frame->nb_samples) - 1;
574 const double *data_ptr = (
double *)
frame->extended_data[
channel];
577 variance +=
pow_2(data_ptr[
i]);
579 variance /=
frame->nb_samples - 1;
582 return FFMAX(sqrt(variance), DBL_EPSILON);
587 int is_first_frame =
cqueue_empty(
s->gain_history_original[0]);
590 if (
s->channels_coupled) {
592 const double current_threshold =
FFMIN(1.0,
s->compress_factor * standard_deviation);
594 const double prev_value = is_first_frame ? current_threshold :
s->compress_threshold[0];
595 double prev_actual_thresh, curr_actual_thresh;
596 s->compress_threshold[0] = is_first_frame ? current_threshold :
update_value(current_threshold,
s->compress_threshold[0], (1.0/3.0));
601 for (
c = 0;
c <
s->channels;
c++) {
602 double *
const dst_ptr = (
double *)
frame->extended_data[
c];
604 const double localThresh =
fade(prev_actual_thresh, curr_actual_thresh,
i,
frame->nb_samples);
609 for (
c = 0;
c <
s->channels;
c++) {
613 const double prev_value = is_first_frame ? current_threshold :
s->compress_threshold[
c];
614 double prev_actual_thresh, curr_actual_thresh;
616 s->compress_threshold[
c] = is_first_frame ? current_threshold :
update_value(current_threshold,
s->compress_threshold[
c], 1.0/3.0);
621 dst_ptr = (
double *)
frame->extended_data[
c];
623 const double localThresh =
fade(prev_actual_thresh, curr_actual_thresh,
i,
frame->nb_samples);
632 if (
s->dc_correction) {
636 if (
s->compress_factor > DBL_EPSILON) {
640 if (
s->channels_coupled) {
644 for (
c = 0;
c <
s->channels;
c++)
649 for (
c = 0;
c <
s->channels;
c++)
659 for (
c = 0;
c <
s->channels;
c++) {
661 double *dst_ptr = (
double *)
frame->extended_data[
c];
662 double current_amplification_factor;
666 for (
i = 0;
i <
frame->nb_samples && enabled;
i++) {
667 const double amplification_factor =
fade(
s->prev_amplification_factor[
c],
668 current_amplification_factor,
i,
671 dst_ptr[
i] = src_ptr[
i] * amplification_factor;
674 s->prev_amplification_factor[
c] = current_amplification_factor;
685 while (((
s->queue.available >=
s->filter_size) ||
686 (
s->eof &&
s->queue.available)) &&
733 for (
c = 0;
c <
s->channels;
c++) {
734 double *dst_ptr = (
double *)
out->extended_data[
c];
737 dst_ptr[
i] =
s->alt_boundary_mode ? DBL_EPSILON : ((
s->target_rms > DBL_EPSILON) ?
FFMIN(
s->peak_value,
s->target_rms) :
s->peak_value);
738 if (
s->dc_correction) {
739 dst_ptr[
i] *= ((
i % 2) == 1) ? -1 : 1;
740 dst_ptr[
i] +=
s->dc_correction_value[
c];
757 }
else if (
s->queue.available) {
800 if (
s->eof &&
s->queue.available)
801 return flush(outlink);
803 if (
s->eof && !
s->queue.available) {
815 char *res,
int res_len,
int flags)
819 int prev_filter_size =
s->filter_size;
827 if (prev_filter_size !=
s->filter_size) {
830 for (
int c = 0;
c <
s->channels;
c++) {
858 .
name =
"dynaudnorm",
867 .priv_class = &dynaudnorm_class,
static int config_input(AVFilterLink *inlink)
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)
they must not be accessed directly The fifo field contains the frames that are queued in the input for processing by the filter The status_in and status_out fields contains the queued status(EOF or error) of the link
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
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
#define AVERROR_EOF
End of file.
static void analyze_frame(DynamicAudioNormalizerContext *s, AVFrame *frame)
#define FILTER_SINGLE_SAMPLEFMT(sample_fmt_)
AVFILTER_DEFINE_CLASS(dynaudnorm)
static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *in, AVFrame *frame, int enabled)
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)
double * dc_correction_value
static void cqueue_resize(cqueue *q, int new_size)
const char * name
Filter name.
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 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.
static double val(void *priv, double ch)
static cqueue * cqueue_create(int size, int max_size)
static int activate(AVFilterContext *ctx)
static double update_value(double new, double old, double aggressiveness)
A filter pad used for either input or output.
static const AVFilterPad avfilter_af_dynaudnorm_outputs[]
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.
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)
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)
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 cqueue_enqueue(cqueue *q, double element)
static float minimum(float src0, float src1)
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.
double * prev_amplification_factor
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.
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 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
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 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)
cqueue ** gain_history_minimum
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)
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
static double cqueue_peek(cqueue *q, int index)
static double compute_frame_rms(AVFrame *frame, int channel)
static void init_gaussian_filter(DynamicAudioNormalizerContext *s)
static const AVOption dynaudnorm_options[]
cqueue ** gain_history_original
@ 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.
#define CONST(name, help, val, unit)
static av_always_inline int diff(const uint32_t a, const uint32_t b)
#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 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.