diff options
author | Hendrik Leppkes <h.leppkes@gmail.com> | 2012-12-16 13:03:27 +0400 |
---|---|---|
committer | Hendrik Leppkes <h.leppkes@gmail.com> | 2017-08-04 20:12:11 +0300 |
commit | 8d82b6a793f6c1f316ef27cd0b6bc672f69fbb0b (patch) | |
tree | c8849489446fc9c4c5bba33eab4252f24258c6ef /libavresample | |
parent | ebb94701619fc84e9ec1bad127a19970d1a33186 (diff) |
avresample: add a "clipping protection" mode when mixing
This mode normalizes audio down to stay below 1.0 after mixing, so no clipping occurs when converting to integer formats.
Diffstat (limited to 'libavresample')
-rw-r--r-- | libavresample/audio_mix.c | 20 | ||||
-rw-r--r-- | libavresample/internal.h | 2 | ||||
-rw-r--r-- | libavresample/options.c | 1 |
3 files changed, 23 insertions, 0 deletions
diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c index 7ae0aeb74d..ae1a09b892 100644 --- a/libavresample/audio_mix.c +++ b/libavresample/audio_mix.c @@ -56,6 +56,9 @@ struct AudioMix { int32_t *matrix_q15[AVRESAMPLE_MAX_CHANNELS]; float *matrix_flt[AVRESAMPLE_MAX_CHANNELS]; void **matrix; + + int clip_protection; + float clip_max; }; void ff_audio_mix_set_func(AudioMix *am, enum AVSampleFormat fmt, @@ -362,6 +365,8 @@ AudioMix *ff_audio_mix_alloc(AVAudioResampleContext *avr) am->out_layout = avr->out_channel_layout; am->in_channels = avr->in_channels; am->out_channels = avr->out_channels; + am->clip_protection = avr->internal_sample_fmt == AV_SAMPLE_FMT_FLTP && avr->clip_protection; + am->clip_max = 1.0f; /* build matrix if the user did not already set one */ if (avr->mix_matrix) { @@ -477,6 +482,21 @@ int ff_audio_mix(AudioMix *am, AudioData *src) ff_audio_data_set_channels(src, am->out_channels); + /* clip protection is only enabled when the internal sample format is fltp, so we don't need to check here */ + if (am->clip_protection) { + for(i = 0; i < src->nb_samples; i++) { + for (j = 0; j < src->channels; j++) { + const float sample = fabs(((float **)src->data)[j][i]); + if (sample > am->clip_max) { + am->clip_max = sample; + av_log(am->avr, AV_LOG_INFO, "Clipping protection at %.3f\n", sample); + } + if (am->clip_max > 1.0f) + ((float **)src->data)[j][i] /= am->clip_max; + } + } + } + return 0; } diff --git a/libavresample/internal.h b/libavresample/internal.h index 2fc3f6da67..815be824a8 100644 --- a/libavresample/internal.h +++ b/libavresample/internal.h @@ -105,6 +105,8 @@ struct AVAudioResampleContext { int use_channel_map; enum RemapPoint remap_point; ChannelMapInfo ch_map_info; + + int clip_protection; }; diff --git a/libavresample/options.c b/libavresample/options.c index 5f08cd7e52..23575238f1 100644 --- a/libavresample/options.c +++ b/libavresample/options.c @@ -83,6 +83,7 @@ static const AVOption avresample_options[] = { {"triangular", "Triangular Dither", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR }, INT_MIN, INT_MAX, PARAM, "dither_method"}, {"triangular_hp", "Triangular Dither With High Pass", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_HP }, INT_MIN, INT_MAX, PARAM, "dither_method"}, {"triangular_ns", "Triangular Dither With Noise Shaping", 0, AV_OPT_TYPE_CONST, { .i64 = AV_RESAMPLE_DITHER_TRIANGULAR_NS }, INT_MIN, INT_MAX, PARAM, "dither_method"}, + { "clip_protection", "Clipping Protection", OFFSET(clip_protection), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, PARAM }, { NULL }, }; |