summaryrefslogtreecommitdiff
path: root/libavcodec
diff options
context:
space:
mode:
authorJustin Ruggles <justin.ruggles@gmail.com>2008-11-13 03:18:13 +0000
committerJustin Ruggles <justin.ruggles@gmail.com>2008-11-13 03:18:13 +0000
commit0cc51734b20032a5fea3020e40db968c5da91d1f (patch)
tree6052e9507c932776586f35c466a2b032061de8ae /libavcodec
parent0c5d750df9d0293b2ce27b6821c3209952c4e6b8 (diff)
add support for spectral extension
Originally committed as revision 15812 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec')
-rw-r--r--libavcodec/ac3dec.c101
-rw-r--r--libavcodec/ac3dec.h27
-rw-r--r--libavcodec/ac3dec_data.c46
-rw-r--r--libavcodec/ac3dec_data.h2
-rw-r--r--libavcodec/eac3dec.c113
5 files changed, 272 insertions, 17 deletions
diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c
index 3e8b0b5afc..fb6fc61340 100644
--- a/libavcodec/ac3dec.c
+++ b/libavcodec/ac3dec.c
@@ -818,14 +818,86 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
/* spectral extension strategy */
if (s->eac3 && (!blk || get_bits1(gbc))) {
- if (get_bits1(gbc)) {
- av_log_missing_feature(s->avctx, "Spectral extension", 1);
- return -1;
+ s->spx_in_use[blk] = get_bits1(gbc);
+ if (s->spx_in_use[blk]) {
+ int begf, endf;
+ int spx_end_subband;
+
+ /* determine which channels use spx */
+ if (s->channel_mode == AC3_CHMODE_MONO) {
+ s->channel_in_spx[1] = 1;
+ s->spx_coords_exist[1] = 0;
+ } else {
+ for (ch = 1; ch <= fbw_channels; ch++) {
+ s->channel_in_spx[ch] = get_bits1(gbc);
+ s->spx_coords_exist[ch] = 0;
+ }
+ }
+
+ s->spx_copy_start_freq = get_bits(gbc, 2) * 12 + 25;
+ begf = get_bits(gbc, 3);
+ endf = get_bits(gbc, 3);
+ s->spx_start_subband = begf < 6 ? begf+2 : 2*begf-3;
+ spx_end_subband = endf < 4 ? endf+5 : 2*endf+3;
+ s->num_spx_subbands = spx_end_subband - s->spx_start_subband;
+ s->spx_start_freq = s->spx_start_subband * 12 + 25;
+ s->spx_end_freq = spx_end_subband * 12 + 25;
+
+ decode_band_structure(gbc, blk, s->eac3, 0,
+ s->spx_start_subband, spx_end_subband,
+ ff_eac3_default_spx_band_struct,
+ s->spx_band_struct, NULL, &s->num_spx_bands,
+ s->spx_band_sizes);
+ } else {
+ for (ch = 1; ch <= fbw_channels; ch++) {
+ s->channel_in_spx[ch] = 0;
+ s->first_spx_coords[ch] = 1;
+ }
}
- /* TODO: parse spectral extension strategy info */
+ } else {
+ s->spx_in_use[blk] = blk ? s->spx_in_use[blk-1] : 0;
}
- /* TODO: spectral extension coordinates */
+ /* spectral extension coordinates */
+ if (s->spx_in_use[blk]) {
+ for (ch = 1; ch <= fbw_channels; ch++) {
+ if (s->channel_in_spx[ch]) {
+ if (s->first_spx_coords[ch] || get_bits1(gbc)) {
+ int bin, spx_blend;
+ int master_spx_coord;
+ s->first_spx_coords[ch] = 0;
+ s->spx_coords_exist[ch] = 1;
+ spx_blend = get_bits(gbc, 5) << 18;
+ master_spx_coord = get_bits(gbc, 2) * 3;
+ bin = s->spx_start_freq;
+ for (bnd = 0; bnd < s->num_spx_bands; bnd++) {
+ int spx_coord_exp, spx_coord_mant;
+
+ /* calculate blending factors */
+ int bandsize = s->spx_band_sizes[bnd];
+ int nratio = (((bin + (bandsize >> 1)) << 23) / s->spx_end_freq) - spx_blend;
+ nratio = av_clip(nratio, 0, INT24_MAX);
+ s->spx_noise_blend [ch][bnd] = ff_sqrt(( nratio) << 8) * M_SQRT_POW2_15;
+ s->spx_signal_blend[ch][bnd] = ff_sqrt((INT24_MAX - nratio) << 8) * M_SQRT_POW2_15;
+ bin += bandsize;
+
+ /* decode spx coordinates */
+ spx_coord_exp = get_bits(gbc, 4);
+ spx_coord_mant = get_bits(gbc, 2);
+ if (spx_coord_exp == 15)
+ s->spx_coords[ch][bnd] = spx_coord_mant << 26;
+ else
+ s->spx_coords[ch][bnd] = (spx_coord_mant + 4) << 25;
+ s->spx_coords[ch][bnd] >>= (spx_coord_exp + master_spx_coord);
+ }
+ } else {
+ s->spx_coords_exist[ch] = 0;
+ }
+ } else {
+ s->first_spx_coords[ch] = 1;
+ }
+ }
+ }
/* coupling strategy */
if (s->eac3 ? s->cpl_strategy_exists[blk] : get_bits1(gbc)) {
@@ -862,9 +934,12 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
s->phase_flags_in_use = get_bits1(gbc);
/* coupling frequency range */
- /* TODO: modify coupling end freq if spectral extension is used */
cpl_start_subband = get_bits(gbc, 4);
+ if (s->spx_in_use[blk]) {
+ cpl_end_subband = s->spx_start_subband - 1;
+ } else {
cpl_end_subband = get_bits(gbc, 4) + 3;
+ }
s->num_cpl_subbands = cpl_end_subband - cpl_start_subband;
if (s->num_cpl_subbands < 0) {
av_log(s->avctx, AV_LOG_ERROR, "invalid coupling range (%d > %d)\n",
@@ -939,8 +1014,14 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
if (channel_mode == AC3_CHMODE_STEREO) {
if ((s->eac3 && !blk) || get_bits1(gbc)) {
s->num_rematrixing_bands = 4;
- if(cpl_in_use && s->start_freq[CPL_CH] <= 61)
+ if (cpl_in_use) {
+ if (s->start_freq[CPL_CH] <= 61)
s->num_rematrixing_bands -= 1 + (s->start_freq[CPL_CH] == 37);
+ } else if (s->spx_in_use[blk]) {
+ if (s->spx_start_freq <= 61)
+ s->num_rematrixing_bands -= 1 + (s->spx_start_freq <= 37) +
+ (s->spx_start_freq <= 25);
+ }
for(bnd=0; bnd<s->num_rematrixing_bands; bnd++)
s->rematrixing_flags[bnd] = get_bits1(gbc);
} else if (!blk) {
@@ -965,6 +1046,8 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
int prev = s->end_freq[ch];
if (s->channel_in_cpl[ch])
s->end_freq[ch] = s->start_freq[CPL_CH];
+ else if (s->channel_in_spx[ch])
+ s->end_freq[ch] = s->spx_start_freq;
else {
int bandwidth_code = get_bits(gbc, 6);
if (bandwidth_code > 60) {
@@ -1155,12 +1238,12 @@ static int decode_audio_block(AC3DecodeContext *s, int blk)
/* TODO: generate enhanced coupling coordinates and uncouple */
- /* TODO: apply spectral extension */
-
/* recover coefficients if rematrixing is in use */
if(s->channel_mode == AC3_CHMODE_STEREO)
do_rematrixing(s);
+ ff_eac3_apply_spectral_extension(s);
+
/* apply scaling to coefficients (headroom, dynrng) */
for(ch=1; ch<=s->channels; ch++) {
float gain = s->mul_bias / 4194304.0f;
diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h
index 617080910b..7d34837e0c 100644
--- a/libavcodec/ac3dec.h
+++ b/libavcodec/ac3dec.h
@@ -42,6 +42,11 @@
#define AC3_MAX_COEFS 256
#define AC3_BLOCK_SIZE 256
#define MAX_BLOCKS 6
+#define SPX_MAX_BANDS 17
+
+#define INT24_MIN -8388608
+#define INT24_MAX 8388607
+#define M_SQRT_POW2_15 181
typedef struct {
AVCodecContext *avctx; ///< parent context
@@ -88,6 +93,26 @@ typedef struct {
int cpl_coords[AC3_MAX_CHANNELS][18]; ///< coupling coordinates (cplco)
///@}
+///@defgroup spx spectral extension
+///@{
+ int spx_in_use[MAX_BLOCKS]; ///< spectral extension in use (spxinu)
+ int channel_in_spx[AC3_MAX_CHANNELS]; ///< channel in spectral extension (chinspx)
+ int spx_atten_code[AC3_MAX_CHANNELS]; ///< spx attenuation code (spxattencod)
+ int spx_coords_exist[AC3_MAX_CHANNELS]; ///< indicates if a channel has spx coords (spxcoe)
+ int spx_start_subband; ///< spx beginning frequency band (spxbegf)
+ int spx_start_freq; ///< spx start frequency bin
+ int spx_end_freq; ///< spx end frequency bin
+ int spx_copy_start_freq; ///< spx starting frequency for copying (copystartmant)
+ int num_spx_subbands; ///< number of spectral extension subbands
+ int num_spx_bands; ///< number of spectral extension bands (nspxbnds)
+ uint8_t spx_band_struct[SPX_MAX_BANDS]; ///< spectral extension band structure (spxbndstrc)
+ int spx_band_sizes[SPX_MAX_BANDS]; ///< number of bins in each band (spxbndsztab)
+ int first_spx_coords[AC3_MAX_CHANNELS]; ///< first spx coordinates states (firstspxcos)
+ int spx_noise_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx noise blending factor (nblendfact)
+ int spx_signal_blend[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spx signal blending factor (sblendfact)
+ int spx_coords[AC3_MAX_CHANNELS][SPX_MAX_BANDS]; ///< spectral extension coordinates (spxco)
+///@}
+
///@defgroup aht adaptive hybrid transform
int channel_uses_aht[AC3_MAX_CHANNELS]; ///< channel AHT in use (chahtinu)
int pre_mantissa[AC3_MAX_CHANNELS][AC3_MAX_COEFS][MAX_BLOCKS]; ///< pre-IDCT mantissas
@@ -179,4 +204,6 @@ int ff_eac3_parse_header(AC3DecodeContext *s);
*/
void ff_eac3_decode_transform_coeffs_aht_ch(AC3DecodeContext *s, int ch);
+void ff_eac3_apply_spectral_extension(AC3DecodeContext *s);
+
#endif /* AVCODEC_AC3DEC_H */
diff --git a/libavcodec/ac3dec_data.c b/libavcodec/ac3dec_data.c
index a70c8fca45..fb21888c78 100644
--- a/libavcodec/ac3dec_data.c
+++ b/libavcodec/ac3dec_data.c
@@ -1127,6 +1127,52 @@ const uint8_t ff_eac3_frm_expstr[32][6] = {
const uint8_t ff_eac3_default_cpl_band_struct[18] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1 };
+ /**
+ * Table E2.15 Default Spectral Extension Banding Structure
+ */
+const uint8_t ff_eac3_default_spx_band_struct[17] =
+{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 };
+
+/**
+ * Table E.25: Spectral Extension Attenuation Table
+ * 24-bit fixed-point version of the floating-point table in the specification.
+ * ff_eac3_spx_atten_tab[code][bin]=lrint(pow(1<<(bin+1),(code+1)/-15.0)*(1<<23));
+ */
+const int32_t ff_eac3_spx_atten_tab[32][3] = {
+ { 8009792, 7648083, 7302707 },
+ { 7648083, 6972929, 6357376 },
+ { 7302707, 6357376, 5534417 },
+ { 6972929, 5796163, 4817990 },
+ { 6658043, 5284492, 4194304 },
+ { 6357376, 4817990, 3651354 },
+ { 6070287, 4392670, 3178688 },
+ { 5796163, 4004896, 2767209 },
+ { 5534417, 3651354, 2408995 },
+ { 5284492, 3329021, 2097152 },
+ { 5045853, 3035144, 1825677 },
+ { 4817990, 2767209, 1589344 },
+ { 4600417, 2522926, 1383604 },
+ { 4392670, 2300209, 1204498 },
+ { 4194304, 2097152, 1048576 },
+ { 4004896, 1912021, 912838 },
+ { 3824041, 1743232, 794672 },
+ { 3651354, 1589344, 691802 },
+ { 3486464, 1449041, 602249 },
+ { 3329021, 1321123, 524288 },
+ { 3178688, 1204498, 456419 },
+ { 3035144, 1098167, 397336 },
+ { 2898081, 1001224, 345901 },
+ { 2767209, 912838, 301124 },
+ { 2642246, 832255, 262144 },
+ { 2522926, 758786, 228210 },
+ { 2408995, 691802, 198668 },
+ { 2300209, 630732, 172951 },
+ { 2196335, 575052, 150562 },
+ { 2097152, 524288, 131072 },
+ { 2002448, 478005, 114105 },
+ { 1912021, 435808, 99334 }
+};
+
/**
* Table of bin locations for rematrixing bands
* reference: Section 7.5.2 Rematrixing : Frequency Band Definitions
diff --git a/libavcodec/ac3dec_data.h b/libavcodec/ac3dec_data.h
index 486d04a40b..73aae1e178 100644
--- a/libavcodec/ac3dec_data.h
+++ b/libavcodec/ac3dec_data.h
@@ -34,6 +34,8 @@ extern const int8_t ff_eac3_gaq_remap_2_4_b[9][2];
extern const int16_t (* const ff_eac3_mantissa_vq[8])[6];
extern const uint8_t ff_eac3_frm_expstr[32][6];
extern const uint8_t ff_eac3_default_cpl_band_struct[18];
+extern const uint8_t ff_eac3_default_spx_band_struct[17];
+extern const int32_t ff_eac3_spx_atten_tab[32][3];
extern const uint8_t ff_ac3_rematrix_band_tab[5];
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;