Go to the documentation of this file.
   32 #define FF_BUFQUEUE_SIZE 302 
   81 #define OFFSET(x) offsetof(DynamicAudioNormalizerContext, x) 
   82 #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM 
  103     if (!(
s->filter_size & 1)) {
 
  149     const double step_size = 1.0 / frame_len;
 
  152     for (pos = 0; pos < frame_len; pos++) {
 
  153         fade_factors[0][pos] = 1.0 - (step_size * (pos + 1.0));
 
  154         fade_factors[1][pos] = 1.0 - fade_factors[0][pos];
 
  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++) {
 
  274     for (
c = 0; 
c < 
s->channels; 
c++) {
 
  275         if (
s->gain_history_original)
 
  277         if (
s->gain_history_minimum)
 
  279         if (
s->gain_history_smoothed)
 
  288     s->is_enabled = 
NULL;
 
  310     s->dc_correction_value = 
av_calloc(
inlink->channels, 
sizeof(*
s->dc_correction_value));
 
  311     s->compress_threshold = 
av_calloc(
inlink->channels, 
sizeof(*
s->compress_threshold));
 
  312     s->gain_history_original = 
av_calloc(
inlink->channels, 
sizeof(*
s->gain_history_original));
 
  313     s->gain_history_minimum = 
av_calloc(
inlink->channels, 
sizeof(*
s->gain_history_minimum));
 
  314     s->gain_history_smoothed = 
av_calloc(
inlink->channels, 
sizeof(*
s->gain_history_smoothed));
 
  317     if (!
s->prev_amplification_factor || !
s->dc_correction_value ||
 
  318         !
s->compress_threshold || !
s->fade_factors[0] || !
s->fade_factors[1] ||
 
  319         !
s->gain_history_original || !
s->gain_history_minimum ||
 
  320         !
s->gain_history_smoothed || !
s->is_enabled || !
s->weights)
 
  324         s->prev_amplification_factor[
c] = 1.0;
 
  330         if (!
s->gain_history_original[
c] || !
s->gain_history_minimum[
c] ||
 
  331             !
s->gain_history_smoothed[
c])
 
  338     s->channels = 
inlink->channels;
 
  339     s->delay = 
s->filter_size;
 
  344 static inline double fade(
double prev, 
double next, 
int pos,
 
  345                           double *fade_factors[2])
 
  347     return fade_factors[0][pos] * prev + fade_factors[1][pos] * 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);
 
  415     return bound(
s->max_amplification, 
FFMIN(maximum_gain, rms_gain));
 
  420     double min = DBL_MAX;
 
  443                                 double current_gain_factor)
 
  447         const int pre_fill_size = 
s->filter_size / 2;
 
  448         const double initial_value = 
s->alt_boundary_mode ? current_gain_factor : 1.0;
 
  450         s->prev_amplification_factor[
channel] = initial_value;
 
  464             const int pre_fill_size = 
s->filter_size / 2;
 
  465             double initial_value = 
s->alt_boundary_mode ? 
cqueue_peek(
s->gain_history_original[
channel], 0) : 1.0;
 
  466             int input = pre_fill_size;
 
  493 static inline double update_value(
double new, 
double old, 
double aggressiveness)
 
  495     av_assert0((aggressiveness >= 0.0) && (aggressiveness <= 1.0));
 
  496     return aggressiveness * 
new + (1.0 - aggressiveness) * old;
 
  501     const double diff = 1.0 / 
frame->nb_samples;
 
  502     int is_first_frame = 
cqueue_empty(
s->gain_history_original[0]);
 
  505     for (
c = 0; 
c < 
s->channels; 
c++) {
 
  506         double *dst_ptr = (
double *)
frame->extended_data[
c];
 
  507         double current_average_value = 0.0;
 
  511             current_average_value += dst_ptr[
i] * 
diff;
 
  513         prev_value = is_first_frame ? current_average_value : 
s->dc_correction_value[
c];
 
  514         s->dc_correction_value[
c] = is_first_frame ? current_average_value : 
update_value(current_average_value, 
s->dc_correction_value[
c], 0.1);
 
  516         for (
i = 0; 
i < 
frame->nb_samples; 
i++) {
 
  517             dst_ptr[
i] -= 
fade(prev_value, 
s->dc_correction_value[
c], 
i, 
s->fade_factors);
 
  524     if ((threshold > DBL_EPSILON) && (threshold < (1.0 - DBL_EPSILON))) {
 
  525         double current_threshold = threshold;
 
  526         double step_size = 1.0;
 
  528         while (step_size > DBL_EPSILON) {
 
  529             while ((
llrint((current_threshold + step_size) * (UINT64_C(1) << 63)) >
 
  530                     llrint(current_threshold * (UINT64_C(1) << 63))) &&
 
  531                    (
bound(current_threshold + step_size, 1.0) <= threshold)) {
 
  532                 current_threshold += step_size;
 
  538         return current_threshold;
 
  547     double variance = 0.0;
 
  551         for (
c = 0; 
c < 
s->channels; 
c++) {
 
  552             const double *data_ptr = (
double *)
frame->extended_data[
c];
 
  555                 variance += 
pow_2(data_ptr[
i]);  
 
  558         variance /= (
s->channels * 
frame->nb_samples) - 1;
 
  560         const double *data_ptr = (
double *)
frame->extended_data[
channel];
 
  563             variance += 
pow_2(data_ptr[
i]);      
 
  565         variance /= 
frame->nb_samples - 1;
 
  568     return FFMAX(sqrt(variance), DBL_EPSILON);
 
  573     int is_first_frame = 
cqueue_empty(
s->gain_history_original[0]);
 
  576     if (
s->channels_coupled) {
 
  578         const double current_threshold  = 
FFMIN(1.0, 
s->compress_factor * standard_deviation);
 
  580         const double prev_value = is_first_frame ? current_threshold : 
s->compress_threshold[0];
 
  581         double prev_actual_thresh, curr_actual_thresh;
 
  582         s->compress_threshold[0] = is_first_frame ? current_threshold : 
update_value(current_threshold, 
s->compress_threshold[0], (1.0/3.0));
 
  587         for (
c = 0; 
c < 
s->channels; 
c++) {
 
  588             double *
const dst_ptr = (
double *)
frame->extended_data[
c];
 
  590                 const double localThresh = 
fade(prev_actual_thresh, curr_actual_thresh, 
i, 
s->fade_factors);
 
  595         for (
c = 0; 
c < 
s->channels; 
c++) {
 
  599             const double prev_value = is_first_frame ? current_threshold : 
s->compress_threshold[
c];
 
  600             double prev_actual_thresh, curr_actual_thresh;
 
  602             s->compress_threshold[
c] = is_first_frame ? current_threshold : 
update_value(current_threshold, 
s->compress_threshold[
c], 1.0/3.0);
 
  607             dst_ptr = (
double *)
frame->extended_data[
c];
 
  609                 const double localThresh = 
fade(prev_actual_thresh, curr_actual_thresh, 
i, 
s->fade_factors);
 
  618     if (
s->dc_correction) {
 
  622     if (
s->compress_factor > DBL_EPSILON) {
 
  626     if (
s->channels_coupled) {
 
  630         for (
c = 0; 
c < 
s->channels; 
c++)
 
  635         for (
c = 0; 
c < 
s->channels; 
c++)
 
  644     for (
c = 0; 
c < 
s->channels; 
c++) {
 
  645         double *dst_ptr = (
double *)
frame->extended_data[
c];
 
  646         double current_amplification_factor;
 
  650         for (
i = 0; 
i < 
frame->nb_samples && enabled; 
i++) {
 
  651             const double amplification_factor = 
fade(
s->prev_amplification_factor[
c],
 
  652                                                      current_amplification_factor, 
i,
 
  655             dst_ptr[
i] *= amplification_factor;
 
  657             if (fabs(dst_ptr[
i]) > 
s->peak_value)
 
  661         s->prev_amplification_factor[
c] = current_amplification_factor;
 
  699     for (
c = 0; 
c < 
s->channels; 
c++) {
 
  700         double *dst_ptr = (
double *)
out->extended_data[
c];
 
  703             dst_ptr[
i] = 
s->alt_boundary_mode ? DBL_EPSILON : ((
s->target_rms > DBL_EPSILON) ? 
FFMIN(
s->peak_value, 
s->target_rms) : 
s->peak_value);
 
  704             if (
s->dc_correction) {
 
  705                 dst_ptr[
i] *= ((
i % 2) == 1) ? -1 : 1;
 
  706                 dst_ptr[
i] += 
s->dc_correction_value[
c];
 
  723     } 
else if (
s->queue.available) {
 
  728         s->delay = 
s->queue.available;
 
  766     if (
s->eof && 
s->delay > 0)
 
  767         return flush(outlink);
 
  769     if (
s->eof && 
s->delay <= 0) {
 
  798     .
name          = 
"dynaudnorm",
 
  807     .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.
A list of supported channel layouts.
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
static void update_gain_history(DynamicAudioNormalizerContext *s, int channel, double current_gain_factor)
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
static enum AVSampleFormat sample_fmts[]
enum MovChannelLayoutTag * layouts
#define AVERROR_EOF
End of file.
static void analyze_frame(DynamicAudioNormalizerContext *s, AVFrame *frame)
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
static double fade(double prev, double next, int pos, double *fade_factors[2])
This structure describes decoded (raw) audio or video data.
int av_frame_make_writable(AVFrame *frame)
Ensure that the frame data is writable, avoiding data copy if possible.
static av_cold int init(AVFilterContext *ctx)
double * dc_correction_value
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 get_max_local_gain(DynamicAudioNormalizerContext *s, AVFrame *frame, int channel)
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[]
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
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)
#define av_assert0(cond)
assert() equivalent, that is always enabled.
static const AVFilterPad outputs[]
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
static av_always_inline double copysign(double x, double y)
static int cqueue_size(cqueue *q)
static av_cold void uninit(AVFilterContext *ctx)
Describe the class of an AVClass context structure.
and forward the result(frame or status change) to the corresponding input. If nothing is possible
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.
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)
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 inputs
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
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)
AVFilter ff_af_dynaudnorm
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 void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *frame, int enabled)
static int cqueue_pop(cqueue *q)
AVFilterContext * src
source filter
const char const char void * val
static void cqueue_free(cqueue *q)
static int filter_frame(AVFilterLink *inlink, AVFrame *in)
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 int query_formats(AVFilterContext *ctx)
static cqueue * cqueue_create(int size)
double * compress_threshold
uint8_t pi<< 24) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0f/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_U8, uint8_t,(*(const uint8_t *) pi - 0x80) *(1.0/(1<< 7))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S16, int16_t,(*(const int16_t *) pi >> 8)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0f/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S16, int16_t, *(const int16_t *) pi *(1.0/(1<< 15))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_S32, int32_t,(*(const int32_t *) pi >> 24)+0x80) CONV_FUNC_GROUP(AV_SAMPLE_FMT_FLT, float, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0f/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_DBL, double, AV_SAMPLE_FMT_S32, int32_t, *(const int32_t *) pi *(1.0/(1U<< 31))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_FLT, float, av_clip_uint8(lrintf(*(const float *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, float, av_clip_int16(lrintf(*(const float *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, float, av_clipl_int32(llrintf(*(const float *) pi *(1U<< 31)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_U8, uint8_t, AV_SAMPLE_FMT_DBL, double, av_clip_uint8(lrint(*(const double *) pi *(1<< 7))+0x80)) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, double, av_clip_int16(lrint(*(const double *) pi *(1<< 15)))) CONV_FUNC_GROUP(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, double, av_clipl_int32(llrint(*(const double *) pi *(1U<< 31)))) #define SET_CONV_FUNC_GROUP(ofmt, ifmt) static void set_generic_function(AudioConvert *ac) { } void ff_audio_convert_free(AudioConvert **ac) { if(! *ac) return;ff_dither_free(&(*ac) ->dc);av_freep(ac);} AudioConvert *ff_audio_convert_alloc(AVAudioResampleContext *avr, enum AVSampleFormat out_fmt, enum AVSampleFormat in_fmt, int channels, int sample_rate, int apply_map) { AudioConvert *ac;int in_planar, out_planar;ac=av_mallocz(sizeof(*ac));if(!ac) return NULL;ac->avr=avr;ac->out_fmt=out_fmt;ac->in_fmt=in_fmt;ac->channels=channels;ac->apply_map=apply_map;if(avr->dither_method !=AV_RESAMPLE_DITHER_NONE &&av_get_packed_sample_fmt(out_fmt)==AV_SAMPLE_FMT_S16 &&av_get_bytes_per_sample(in_fmt) > 2) { ac->dc=ff_dither_alloc(avr, out_fmt, in_fmt, channels, sample_rate, apply_map);if(!ac->dc) { av_free(ac);return NULL;} return ac;} in_planar=ff_sample_fmt_is_planar(in_fmt, channels);out_planar=ff_sample_fmt_is_planar(out_fmt, channels);if(in_planar==out_planar) { ac->func_type=CONV_FUNC_TYPE_FLAT;ac->planes=in_planar ? ac->channels :1;} else if(in_planar) ac->func_type=CONV_FUNC_TYPE_INTERLEAVE;else ac->func_type=CONV_FUNC_TYPE_DEINTERLEAVE;set_generic_function(ac);if(ARCH_AARCH64) ff_audio_convert_init_aarch64(ac);if(ARCH_ARM) ff_audio_convert_init_arm(ac);if(ARCH_X86) ff_audio_convert_init_x86(ac);return ac;} int ff_audio_convert(AudioConvert *ac, AudioData *out, AudioData *in) { int use_generic=1;int len=in->nb_samples;int p;if(ac->dc) { av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (dithered)\n", len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt));return ff_convert_dither(ac-> in
#define av_assert2(cond)
assert() equivalent, that does lie in speed critical code.
#define i(width, name, range_min, range_max)
Structure holding the queue.
#define av_malloc_array(a, b)
cqueue ** gain_history_minimum
AVSampleFormat
Audio sample formats.
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
const char * name
Pad name.
int ff_inlink_queued_samples(AVFilterLink *link)
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 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)
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
static const AVOption dynaudnorm_options[]
cqueue ** gain_history_original
@ AV_SAMPLE_FMT_DBLP
double, planar
#define CONST(name, help, val, unit)
static void precalculate_fade_factors(double *fade_factors[2], int frame_len)
static av_always_inline int diff(const uint32_t a, const uint32_t b)
#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 gaussian_filter(DynamicAudioNormalizerContext *s, cqueue *q)
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.