From 0cc51734b20032a5fea3020e40db968c5da91d1f Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Thu, 13 Nov 2008 03:18:13 +0000 Subject: add support for spectral extension Originally committed as revision 15812 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavcodec/eac3dec.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 8 deletions(-) (limited to 'libavcodec/eac3dec.c') diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index 0b10b41848..58376f2929 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -36,6 +36,104 @@ typedef enum { #define EAC3_SR_CODE_REDUCED 3 + +void ff_eac3_apply_spectral_extension(AC3DecodeContext *s) +{ + int bin, bnd, ch, i; + int wrapflag[SPX_MAX_BANDS]={0,}, num_copy_sections, copy_sizes[SPX_MAX_BANDS]; + int rms_energy[SPX_MAX_BANDS]; + + /* Set copy index mapping table. Set wrap flags to apply a notch filter at + wrap points later on. */ + bin = s->spx_copy_start_freq; + num_copy_sections = 0; + for (bnd = 0; bnd < s->num_spx_bands; bnd++) { + int bandsize = s->spx_band_sizes[bnd]; + if ((bin + bandsize) > s->spx_start_freq) { + copy_sizes[num_copy_sections++] = bin - s->spx_copy_start_freq; + bin = s->spx_copy_start_freq; + wrapflag[bnd] = 1; + } + for (i = 0; i < bandsize; i++) { + if (bin == s->spx_start_freq) { + copy_sizes[num_copy_sections++] = bin - s->spx_copy_start_freq; + bin = s->spx_copy_start_freq; + } + bin++; + } + } + copy_sizes[num_copy_sections++] = bin - s->spx_copy_start_freq; + + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (!s->channel_in_spx[ch]) + continue; + + /* Copy coeffs from normal bands to extension bands */ + bin = s->spx_start_freq; + for (bnd = 0; bnd < num_copy_sections; bnd++) { + memcpy(&s->fixed_coeffs[ch][bin], + &s->fixed_coeffs[ch][s->spx_copy_start_freq], + copy_sizes[bnd]*sizeof(int)); + bin += copy_sizes[bnd]; + } + + /* Calculate RMS energy for each SPX band. */ + bin = s->spx_start_freq; + for (bnd = 0; bnd < s->num_spx_bands; bnd++) { + int bandsize = s->spx_band_sizes[bnd]; + int64_t accum = 0; + for (i = 0; i < bandsize; i++) { + int64_t coeff = s->fixed_coeffs[ch][bin++]; + accum += coeff * coeff; + } + rms_energy[bnd] = ff_sqrt((accum >> 15) / bandsize) * M_SQRT_POW2_15; + } + + /* Apply a notch filter at transitions between normal and extension + bands and at all wrap points. */ + if (s->spx_atten_code[ch] >= 0) { + const int32_t *atten_tab = ff_eac3_spx_atten_tab[s->spx_atten_code[ch]]; + /* apply notch filter at baseband / extension region border */ + bin = s->spx_start_freq - 2; + for (i = 0; i < 5; i++) { + s->fixed_coeffs[ch][bin] = ((int64_t)atten_tab[2-abs(i-2)] * + (int64_t)s->fixed_coeffs[ch][bin]) >> 23; + bin++; + } + /* apply notch at all other wrap points */ + bin += s->spx_band_sizes[0]; + for (bnd = 1; bnd < s->num_spx_bands; bnd++) { + if (wrapflag[bnd]) { + bin -= 5; + for (i = 0; i < 5; i++) { + s->fixed_coeffs[ch][bin] = (atten_tab[2-abs(i-2)] * + (int64_t)s->fixed_coeffs[ch][bin]) >> 23; + bin++; + } + } + bin += s->spx_band_sizes[bnd]; + } + } + + /* Apply noise-blended coefficient scaling based on previously + calculated RMS energy, blending factors, and SPX coordinates for + each band. */ + bin = s->spx_start_freq; + for (bnd = 0; bnd < s->num_spx_bands; bnd++) { + int64_t nscale, sscale, spxco; + nscale = (s->spx_noise_blend [ch][bnd] * rms_energy[bnd]) >> 23; + nscale = (nscale * 14529495) >> 23; + sscale = s->spx_signal_blend[ch][bnd]; + spxco = s->spx_coords[ch][bnd]; + for (i = 0; i < s->spx_band_sizes[bnd]; i++) { + int64_t noise = (nscale * (((int)av_lfg_get(&s->dith_state))>>8)) >> 23; + int64_t signal = (sscale * s->fixed_coeffs[ch][bin]) >> 23; + s->fixed_coeffs[ch][bin++] = ((noise + signal) * spxco) >> 23; + } + } + } +} + /** lrint(M_SQRT2*cos(2*M_PI/12)*(1<<23)) */ #define COEFF_0 10273905LL @@ -459,14 +557,12 @@ int ff_eac3_parse_header(AC3DecodeContext *s) } /* spectral extension attenuation data */ - if (parse_spx_atten_data) { - av_log_missing_feature(s->avctx, "Spectral extension attenuation", 1); - for (ch = 1; ch <= s->fbw_channels; ch++) { - if (get_bits1(gbc)) { // channel has spx attenuation - skip_bits(gbc, 5); // skip spx attenuation code - } - } - } + for (ch = 1; ch <= s->fbw_channels; ch++) { + if (parse_spx_atten_data && get_bits1(gbc)) + s->spx_atten_code[ch] = get_bits(gbc, 5); + else + s->spx_atten_code[ch] = -1; + } /* block start information */ if (s->num_blocks > 1 && get_bits1(gbc)) { @@ -480,6 +576,7 @@ int ff_eac3_parse_header(AC3DecodeContext *s) /* syntax state initialization */ for (ch = 1; ch <= s->fbw_channels; ch++) { + s->first_spx_coords[ch] = 1; s->first_cpl_coords[ch] = 1; } s->first_cpl_leak = 1; -- cgit v1.2.3