diff options
author | Claudio Freire <klaussfreire@gmail.com> | 2015-07-20 22:53:24 -0300 |
---|---|---|
committer | Michael Niedermayer <michael@niedermayer.cc> | 2015-07-27 19:13:48 +0200 |
commit | 59216e0525a58714be4207be6ae8744750e62867 (patch) | |
tree | 8c5b41b3471b08e17396c159001da6deff7ce347 /libavcodec/aacenc.c | |
parent | c8c86b8f9b8c166633a7324c8646f38866801b88 (diff) | |
download | ffmpeg-59216e0525a58714be4207be6ae8744750e62867.tar.gz |
AAC Encoder: clipping avoidance
Avoid clipping due to quantization noise to produce audible
artifacts, by detecting near-clipping signals and both attenuating
them a little and encoding escape-encoded bands (usually the
loudest) rounding towards zero instead of nearest, which tends to
decrease overall energy and thus clipping.
Currently fate tests measure numerical error so this change makes
tests using asynth (which are near clipping) report higher error
not less, because of window attenuation. Yet, they sound better,
not worse (albeit subtle, other samples aren't subtle at all).
Only measuring psychoacoustically weighted error would make for
a representative test, so that will be left for a future patch.
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavcodec/aacenc.c')
-rw-r--r-- | libavcodec/aacenc.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index a3c31de684..c3c72aff31 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -472,13 +472,33 @@ static void encode_spectral_coeffs(AACEncContext *s, SingleChannelElement *sce) sce->ics.swb_sizes[i], sce->sf_idx[w*16 + i], sce->band_type[w*16 + i], - s->lambda); + s->lambda, sce->ics.window_clipping[w]); start += sce->ics.swb_sizes[i]; } } } /** + * Downscale spectral coefficients for near-clipping windows to avoid artifacts + */ +static void avoid_clipping(AACEncContext *s, SingleChannelElement *sce) +{ + int start, i, j, w; + + if (sce->ics.clip_avoidance_factor < 1.0f) { + for (w = 0; w < sce->ics.num_windows; w++) { + start = 0; + for (i = 0; i < sce->ics.max_sfb; i++) { + float *swb_coeffs = sce->coeffs + start + w*128; + for (j = 0; j < sce->ics.swb_sizes[i]; j++) + swb_coeffs[j] *= sce->ics.clip_avoidance_factor; + start += sce->ics.swb_sizes[i]; + } + } + } +} + +/** * Encode one channel of audio data. */ static int encode_individual_channel(AVCodecContext *avctx, AACEncContext *s, @@ -578,6 +598,7 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, for (ch = 0; ch < chans; ch++) { IndividualChannelStream *ics = &cpe->ch[ch].ics; int cur_channel = start_ch + ch; + float clip_avoidance_factor; overlap = &samples[cur_channel][0]; samples2 = overlap + 1024; la = samples2 + (448+64); @@ -605,14 +626,29 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ics->num_windows = wi[ch].num_windows; ics->swb_sizes = s->psy.bands [ics->num_windows == 8]; ics->num_swb = tag == TYPE_LFE ? ics->num_swb : s->psy.num_bands[ics->num_windows == 8]; + clip_avoidance_factor = 0.0f; for (w = 0; w < ics->num_windows; w++) ics->group_len[w] = wi[ch].grouping[w]; + for (w = 0; w < ics->num_windows; w++) { + if (wi[ch].clipping[w] > CLIP_AVOIDANCE_FACTOR) { + ics->window_clipping[w] = 1; + clip_avoidance_factor = FFMAX(clip_avoidance_factor, wi[ch].clipping[w]); + } else { + ics->window_clipping[w] = 0; + } + } + if (clip_avoidance_factor > CLIP_AVOIDANCE_FACTOR) { + ics->clip_avoidance_factor = CLIP_AVOIDANCE_FACTOR / clip_avoidance_factor; + } else { + ics->clip_avoidance_factor = 1.0f; + } apply_window_and_mdct(s, &cpe->ch[ch], overlap); if (isnan(cpe->ch->coeffs[0])) { av_log(avctx, AV_LOG_ERROR, "Input contains NaN\n"); return AVERROR(EINVAL); } + avoid_clipping(s, &cpe->ch[ch]); } start_ch += chans; } |