summaryrefslogtreecommitdiffstats
path: root/libavcodec/aac.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/aac.c')
-rw-r--r--libavcodec/aac.c222
1 files changed, 209 insertions, 13 deletions
diff --git a/libavcodec/aac.c b/libavcodec/aac.c
index 47237ff..cd59c20 100644
--- a/libavcodec/aac.c
+++ b/libavcodec/aac.c
@@ -82,6 +82,7 @@
#include "aac.h"
#include "aactab.h"
+#include "aacdectab.h"
#include "mpeg4audio.h"
#include <assert.h>
@@ -91,6 +92,7 @@
#ifndef CONFIG_HARDCODED_TABLES
static float ff_aac_ivquant_tab[IVQUANT_SIZE];
+ static float ff_aac_pow2sf_tab[316];
#endif /* CONFIG_HARDCODED_TABLES */
static VLC vlc_scalefactors;
@@ -104,27 +106,29 @@ static VLC vlc_spectral[11];
num_assoc_data = get_bits(gb, 3);
num_cc = get_bits(gb, 4);
- newpcs->mono_mixdown_tag = get_bits1(gb) ? get_bits(gb, 4) : -1;
- newpcs->stereo_mixdown_tag = get_bits1(gb) ? get_bits(gb, 4) : -1;
+ if (get_bits1(gb))
+ skip_bits(gb, 4); // mono_mixdown_tag
+ if (get_bits1(gb))
+ skip_bits(gb, 4); // stereo_mixdown_tag
- if (get_bits1(gb)) {
- newpcs->mixdown_coeff_index = get_bits(gb, 2);
- newpcs->pseudo_surround = get_bits1(gb);
- }
+ if (get_bits1(gb))
+ skip_bits(gb, 3); // mixdown_coeff_index and pseudo_surround
- program_config_element_parse_tags(newpcs->che_type[ID_CPE], newpcs->che_type[ID_SCE], AAC_CHANNEL_FRONT, gb, num_front);
- program_config_element_parse_tags(newpcs->che_type[ID_CPE], newpcs->che_type[ID_SCE], AAC_CHANNEL_SIDE, gb, num_side );
- program_config_element_parse_tags(newpcs->che_type[ID_CPE], newpcs->che_type[ID_SCE], AAC_CHANNEL_BACK, gb, num_back );
- program_config_element_parse_tags(NULL, newpcs->che_type[ID_LFE], AAC_CHANNEL_LFE, gb, num_lfe );
+ decode_channel_map(new_che_pos[TYPE_CPE], new_che_pos[TYPE_SCE], AAC_CHANNEL_FRONT, gb, num_front);
+ decode_channel_map(new_che_pos[TYPE_CPE], new_che_pos[TYPE_SCE], AAC_CHANNEL_SIDE, gb, num_side );
+ decode_channel_map(new_che_pos[TYPE_CPE], new_che_pos[TYPE_SCE], AAC_CHANNEL_BACK, gb, num_back );
+ decode_channel_map(NULL, new_che_pos[TYPE_LFE], AAC_CHANNEL_LFE, gb, num_lfe );
skip_bits_long(gb, 4 * num_assoc_data);
- program_config_element_parse_tags(newpcs->che_type[ID_CCE], newpcs->che_type[ID_CCE], AAC_CHANNEL_CC, gb, num_cc );
+ decode_channel_map(new_che_pos[TYPE_CCE], new_che_pos[TYPE_CCE], AAC_CHANNEL_CC, gb, num_cc );
align_get_bits(gb);
/* comment field, first byte is length */
skip_bits_long(gb, 8 * get_bits(gb, 8));
+ return 0;
+}
static av_cold int aac_decode_init(AVCodecContext * avccontext) {
AACContext * ac = avccontext->priv_data;
@@ -132,6 +136,10 @@ static av_cold int aac_decode_init(AVCodecContext * avccontext) {
ac->avccontext = avccontext;
+ if (avccontext->extradata_size <= 0 ||
+ decode_audio_specific_config(ac, avccontext->extradata, avccontext->extradata_size))
+ return -1;
+
avccontext->sample_rate = ac->m4ac.sample_rate;
avccontext->frame_size = 1024;
@@ -166,6 +174,8 @@ static av_cold int aac_decode_init(AVCodecContext * avccontext) {
#ifndef CONFIG_HARDCODED_TABLES
for (i = 1 - IVQUANT_SIZE/2; i < IVQUANT_SIZE/2; i++)
ff_aac_ivquant_tab[i + IVQUANT_SIZE/2 - 1] = cbrt(fabs(i)) * i;
+ for (i = 0; i < 316; i++)
+ ff_aac_pow2sf_tab[i] = pow(2, (i - 200)/4.);
#endif /* CONFIG_HARDCODED_TABLES */
INIT_VLC_STATIC(&vlc_scalefactors, 7, sizeof(ff_aac_scalefactor_code)/sizeof(ff_aac_scalefactor_code[0]),
@@ -200,6 +210,112 @@ static inline float ivquant(int a) {
return cbrtf(fabsf(a)) * a;
}
+ int band_type_run_end[120], GetBitContext * gb, IndividualChannelStream * ics) {
+ int g, idx = 0;
+ const int bits = (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) ? 3 : 5;
+ for (g = 0; g < ics->num_window_groups; g++) {
+ int k = 0;
+ while (k < ics->max_sfb) {
+ uint8_t sect_len = k;
+ int sect_len_incr;
+ int sect_band_type = get_bits(gb, 4);
+ if (sect_band_type == 12) {
+ av_log(ac->avccontext, AV_LOG_ERROR, "invalid band type\n");
+ return -1;
+ }
+ while ((sect_len_incr = get_bits(gb, bits)) == (1 << bits)-1)
+ sect_len += sect_len_incr;
+ sect_len += sect_len_incr;
+ if (sect_len > ics->max_sfb) {
+ av_log(ac->avccontext, AV_LOG_ERROR,
+ "Number of bands (%d) exceeds limit (%d).\n",
+ sect_len, ics->max_sfb);
+ return -1;
+ }
+
+ *
+ * @param mix_gain channel gain (Not used by AAC bitstream.)
+ * @param global_gain first scalefactor value as scalefactors are differentially coded
+ * @param band_type array of the used band type
+ * @param band_type_run_end array of the last scalefactor band of a band type run
+ * @param sf array of scalefactors or intensity stereo positions
+ *
+ * @return Returns error status. 0 - OK, !0 - error
+ */
+static int decode_scalefactors(AACContext * ac, float sf[120], GetBitContext * gb,
+ float mix_gain, unsigned int global_gain, IndividualChannelStream * ics,
+ enum BandType band_type[120], int band_type_run_end[120]) {
+ const int sf_offset = ac->sf_offset + (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE ? 12 : 0);
+ int g, i, idx = 0;
+ int offset[3] = { global_gain, global_gain - 90, 100 };
+ int noise_flag = 1;
+ static const char *sf_str[3] = { "Global gain", "Noise gain", "Intensity stereo position" };
+ ics->intensity_present = 0;
+ for (g = 0; g < ics->num_window_groups; g++) {
+ for (i = 0; i < ics->max_sfb;) {
+ int run_end = band_type_run_end[idx];
+ if (band_type[idx] == ZERO_BT) {
+ for(; i < run_end; i++, idx++)
+ sf[idx] = 0.;
+ }else if((band_type[idx] == INTENSITY_BT) || (band_type[idx] == INTENSITY_BT2)) {
+ ics->intensity_present = 1;
+ for(; i < run_end; i++, idx++) {
+ offset[2] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60;
+ if(offset[2] > 255U) {
+ av_log(ac->avccontext, AV_LOG_ERROR,
+ "%s (%d) out of range.\n", sf_str[2], offset[2]);
+ return -1;
+ }
+ sf[idx] = ff_aac_pow2sf_tab[-offset[2] + 300];
+ sf[idx] *= mix_gain;
+ }
+ }else if(band_type[idx] == NOISE_BT) {
+ for(; i < run_end; i++, idx++) {
+ if(noise_flag-- > 0)
+ offset[1] += get_bits(gb, 9) - 256;
+ else
+ offset[1] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60;
+ if(offset[1] > 255U) {
+ av_log(ac->avccontext, AV_LOG_ERROR,
+ "%s (%d) out of range.\n", sf_str[1], offset[1]);
+ return -1;
+ }
+ sf[idx] = -ff_aac_pow2sf_tab[ offset[1] + sf_offset];
+ sf[idx] *= mix_gain;
+ }
+ }else {
+ for(; i < run_end; i++, idx++) {
+ offset[0] += get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60;
+ if(offset[0] > 255U) {
+ av_log(ac->avccontext, AV_LOG_ERROR,
+ "%s (%d) out of range.\n", sf_str[0], offset[0]);
+ return -1;
+ }
+ sf[idx] = -ff_aac_pow2sf_tab[ offset[0] + sf_offset];
+ sf[idx] *= mix_gain;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Decode pulse data; reference: table 4.7.
+ */
+static void decode_pulses(Pulse * pulse, GetBitContext * gb) {
+ int i;
+ pulse->num_pulse = get_bits(gb, 2) + 1;
+ pulse->start = get_bits(gb, 6);
+ for (i = 0; i < pulse->num_pulse; i++) {
+ pulse->offset[i] = get_bits(gb, 5);
+ pulse->amp [i] = get_bits(gb, 4);
+ }
+}
+
+/**
+ * Add pulses with particular amplitudes to the quantized spectral data; reference: 4.6.3.3.
+ *
* @param pulse pointer to pulse data struct
* @param icoef array of quantized spectral data
*/
@@ -213,18 +329,97 @@ static void add_pulses(int icoef[1024], const Pulse * pulse, const IndividualCha
}
}
+/**
+ * Parse Spectral Band Replication extension data; reference: table 4.55.
+ *
+ * @param crc flag indicating the presence of CRC checksum
+ * @param cnt length of TYPE_FIL syntactic element in bytes
+ * @return Returns number of bytes consumed from the TYPE_FIL element.
+ */
+static int decode_sbr_extension(AACContext * ac, GetBitContext * gb, int crc, int cnt) {
+ // TODO : sbr_extension implementation
+ av_log(ac->avccontext, AV_LOG_DEBUG, "aac: SBR not yet supported.\n");
+ skip_bits_long(gb, 8*cnt - 4); // -4 due to reading extension type
+ return cnt;
+}
+
+ int crc_flag = 0;
+ int res = cnt;
+ switch (get_bits(gb, 4)) { // extension type
+ case EXT_SBR_DATA_CRC:
+ crc_flag++;
+ case EXT_SBR_DATA:
+ res = decode_sbr_extension(ac, gb, crc_flag, cnt);
+ break;
+ case EXT_DYNAMIC_RANGE:
+ res = decode_dynamic_range(&ac->che_drc, gb, cnt);
+ break;
+ case EXT_FILL:
+ case EXT_FILL_DATA:
+ case EXT_DATA_ELEMENT:
+ default:
+ skip_bits_long(gb, 8*cnt - 4);
+ break;
+ };
+ return res;
+}
+
+/**
+ * Apply dependent channel coupling (applied before IMDCT).
+ *
+ * @param index index into coupling gain array
+ */
+static void apply_dependent_coupling(AACContext * ac, SingleChannelElement * sce, ChannelElement * cc, int index) {
+ IndividualChannelStream * ics = &cc->ch[0].ics;
+ const uint16_t * offsets = ics->swb_offset;
+ float * dest = sce->coeffs;
+ const float * src = cc->ch[0].coeffs;
+ int g, i, group, k, idx = 0;
+ if(ac->m4ac.object_type == AOT_AAC_LTP) {
+ av_log(ac->avccontext, AV_LOG_ERROR,
+ "Dependent coupling is not supported together with LTP\n");
+ return;
+ }
+ for (g = 0; g < ics->num_window_groups; g++) {
+ for (i = 0; i < ics->max_sfb; i++, idx++) {
+ if (cc->ch[0].band_type[idx] != ZERO_BT) {
+ float gain = cc->coup.gain[index][idx] * sce->mixing_gain;
+ for (group = 0; group < ics->group_len[g]; group++) {
+ for (k = offsets[i]; k < offsets[i+1]; k++) {
+ // XXX dsputil-ize
+ dest[group*128+k] += gain * src[group*128+k];
+ }
+ }
+ }
+ }
+ dest += ics->group_len[g]*128;
+ src += ics->group_len[g]*128;
+ }
+}
+
+/**
+ * Apply independent channel coupling (applied after IMDCT).
+ *
+ * @param index index into coupling gain array
+ */
+static void apply_independent_coupling(AACContext * ac, SingleChannelElement * sce, ChannelElement * cc, int index) {
+ int i;
+ float gain = cc->coup.gain[index][0] * sce->mixing_gain;
+ for (i = 0; i < 1024; i++)
+ sce->ret[i] += gain * (cc->ch[0].ret[i] - ac->add_bias);
+}
+
static av_cold int aac_decode_close(AVCodecContext * avccontext) {
AACContext * ac = avccontext->priv_data;
int i, j;
- for (i = 0; i < MAX_TAGID; i++) {
+ for (i = 0; i < MAX_ELEM_ID; i++) {
for(j = 0; j < 4; j++)
av_freep(&ac->che[j][i]);
}
ff_mdct_end(&ac->mdct);
ff_mdct_end(&ac->mdct_small);
- av_freep(&ac->interleaved_output);
return 0 ;
}
@@ -238,4 +433,5 @@ AVCodec aac_decoder = {
aac_decode_close,
aac_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("Advanced Audio Coding"),
+ .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
};
OpenPOWER on IntegriCloud