diff options
author | Robert Swain <robert.swain@gmail.com> | 2008-08-15 00:05:09 +0000 |
---|---|---|
committer | Robert Swain <robert.swain@gmail.com> | 2008-08-15 00:05:09 +0000 |
commit | 62a57fae59705a661b3d6725263215896e49fa6c (patch) | |
tree | 05536c3d8957f52c067c804dac6a02e5628cf2d7 | |
parent | e9b9a2f86fe297ce7c6370c36c6582840fd41ae6 (diff) | |
download | ffmpeg-62a57fae59705a661b3d6725263215896e49fa6c.tar.gz |
More OKed sections of AAC decoder code
Originally committed as revision 14770 to svn://svn.ffmpeg.org/ffmpeg/trunk
-rw-r--r-- | libavcodec/aac.c | 301 | ||||
-rw-r--r-- | libavcodec/aac.h | 46 |
2 files changed, 347 insertions, 0 deletions
diff --git a/libavcodec/aac.c b/libavcodec/aac.c index f8e2a9de01..42a25ebe64 100644 --- a/libavcodec/aac.c +++ b/libavcodec/aac.c @@ -100,6 +100,53 @@ static VLC vlc_spectral[11]; /** + * Configure output channel order based on the current program configuration element. + * + * @param che_pos current channel position configuration + * @param new_che_pos New channel position configuration - we only do something if it differs from the current one. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int output_configure(AACContext *ac, enum ChannelPosition che_pos[4][MAX_ELEM_ID], + enum ChannelPosition new_che_pos[4][MAX_ELEM_ID]) { + AVCodecContext *avctx = ac->avccontext; + int i, type, channels = 0; + + if(!memcmp(che_pos, new_che_pos, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]))) + return 0; /* no change */ + + memcpy(che_pos, new_che_pos, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0])); + + /* Allocate or free elements depending on if they are in the + * current program configuration. + * + * Set up default 1:1 output mapping. + * + * For a 5.1 stream the output order will be: + * [ Front Left ] [ Front Right ] [ Center ] [ LFE ] [ Surround Left ] [ Surround Right ] + */ + + for(i = 0; i < MAX_ELEM_ID; i++) { + for(type = 0; type < 4; type++) { + if(che_pos[type][i]) { + if(!ac->che[type][i] && !(ac->che[type][i] = av_mallocz(sizeof(ChannelElement)))) + return AVERROR(ENOMEM); + if(type != TYPE_CCE) { + ac->output_data[channels++] = ac->che[type][i]->ch[0].ret; + if(type == TYPE_CPE) { + ac->output_data[channels++] = ac->che[type][i]->ch[1].ret; + } + } + } else + av_freep(&ac->che[type][i]); + } + } + + avctx->channels = channels; + return 0; +} + +/** * Decode an array of 4 bit element IDs, optionally interleaved with a stereo/mono switching bit. * * @param cpe_map Stereo (Channel Pair Element) map, NULL if stereo bit is not present. @@ -209,6 +256,17 @@ static int set_default_channel_config(AACContext *ac, enum ChannelPosition new_c return 0; } +/** + * Decode GA "General Audio" specific configuration; reference: table 4.1. + * + * @return Returns error status. 0 - OK, !0 - error + */ +static int decode_ga_specific_config(AACContext * ac, GetBitContext * gb, int channel_config) { + enum ChannelPosition new_che_pos[4][MAX_ELEM_ID]; + int extension_flag, ret; + + if(get_bits1(gb)) { // frameLengthFlag + av_log_missing_feature(ac->avccontext, "960/120 MDCT window is", 1); return -1; } @@ -289,6 +347,17 @@ static int decode_audio_specific_config(AACContext * ac, void *data, int data_si return 0; } +/** + * linear congruential pseudorandom number generator + * + * @param previous_val pointer to the current state of the generator + * + * @return Returns a 32-bit pseudorandom integer + */ +static av_always_inline int lcg_random(int previous_val) { + return previous_val * 1664525 + 1013904223; +} + static av_cold int aac_decode_init(AVCodecContext * avccontext) { AACContext * ac = avccontext->priv_data; int i; @@ -381,6 +450,21 @@ static int decode_ics_info(AACContext * ac, IndividualChannelStream * ics, GetBi ics->num_window_groups = 1; ics->group_len[0] = 1; + if (get_bits1(gb)) { + av_log_missing_feature(ac->avccontext, "Predictor bit set but LTP is", 1); + memset(ics, 0, sizeof(IndividualChannelStream)); + return -1; + } + } + + if(ics->max_sfb > ics->num_swb) { + av_log(ac->avccontext, AV_LOG_ERROR, + "Number of scalefactor bands in group (%d) exceeds limit (%d).\n", + ics->max_sfb, ics->num_swb); + memset(ics, 0, sizeof(IndividualChannelStream)); + return -1; + } + return 0; } @@ -520,6 +604,14 @@ static void decode_pulses(Pulse * pulse, GetBitContext * gb) { */ static void decode_mid_side_stereo(ChannelElement * cpe, GetBitContext * gb, int ms_present) { + int idx; + if (ms_present == 1) { + for (idx = 0; idx < cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb; idx++) + cpe->ms_mask[idx] = get_bits1(gb); + } else if (ms_present == 2) { + memset(cpe->ms_mask, 1, cpe->ch[0].ics.num_window_groups * cpe->ch[0].ics.max_sfb * sizeof(cpe->ms_mask[0])); + } +} /** * Add pulses with particular amplitudes to the quantized spectral data; reference: 4.6.3.3. @@ -635,6 +727,64 @@ static int decode_cpe(AACContext * ac, GetBitContext * gb, int elem_id) { return 0; } + coup->coupling_point = 2*get_bits1(gb); + coup->num_coupled = get_bits(gb, 3); + for (c = 0; c <= coup->num_coupled; c++) { + num_gain++; + coup->type[c] = get_bits1(gb) ? TYPE_CPE : TYPE_SCE; + coup->id_select[c] = get_bits(gb, 4); + if (coup->type[c] == TYPE_CPE) { + coup->ch_select[c] = get_bits(gb, 2); + if (coup->ch_select[c] == 3) + num_gain++; + } else + coup->ch_select[c] = 1; + } + coup->coupling_point += get_bits1(gb); + + if (coup->coupling_point == 2) { + av_log(ac->avccontext, AV_LOG_ERROR, + "Independently switched CCE with 'invalid' domain signalled.\n"); + memset(coup, 0, sizeof(ChannelCoupling)); + return -1; + } + + sign = get_bits(gb, 1); + scale = pow(2., pow(2., get_bits(gb, 2) - 3)); + + if ((ret = decode_ics(ac, sce, gb, 0, 0))) + return ret; + + for (c = 0; c < num_gain; c++) { + int cge = 1; + int gain = 0; + float gain_cache = 1.; + if (c) { + cge = coup->coupling_point == AFTER_IMDCT ? 1 : get_bits1(gb); + gain = cge ? get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60: 0; + gain_cache = pow(scale, gain); + } + for (g = 0; g < sce->ics.num_window_groups; g++) + for (sfb = 0; sfb < sce->ics.max_sfb; sfb++, idx++) + if (sce->band_type[idx] != ZERO_BT) { + if (!cge) { + int t = get_vlc2(gb, vlc_scalefactors.table, 7, 3) - 60; + if (t) { + int s = 1; + if (sign) { + s -= 2 * (t & 0x1); + t >>= 1; + } + gain += t; + gain_cache = pow(scale, gain) * s; + } + } + coup->gain[c][idx] = gain_cache; + } + } + return 0; +} + /** * Decode Spectral Band Replication extension data; reference: table 4.55. * @@ -651,6 +801,23 @@ static int decode_sbr_extension(AACContext * ac, GetBitContext * gb, int crc, in } /** + * Parse whether channels are to be excluded from Dynamic Range Compression; reference: table 4.53. + * + * @return Returns number of bytes consumed. + */ +static int decode_drc_channel_exclusions(DynamicRangeControl *che_drc, GetBitContext * gb) { + int i; + int num_excl_chan = 0; + + do { + for (i = 0; i < 7; i++) + che_drc->exclude_mask[num_excl_chan++] = get_bits1(gb); + } while (num_excl_chan < MAX_CHANNELS - 7 && get_bits1(gb)); + + return num_excl_chan / 7; +} + +/** * Decode dynamic range information; reference: table 4.52. * * @param cnt length of TYPE_FIL syntactic element in bytes @@ -746,6 +913,55 @@ static void imdct_and_windowing(AACContext * ac, SingleChannelElement * sce) { float * buf = ac->buf_mdct; int i; + if (ics->window_sequence[0] == EIGHT_SHORT_SEQUENCE) { + if (ics->window_sequence[1] == ONLY_LONG_SEQUENCE || ics->window_sequence[1] == LONG_STOP_SEQUENCE) + av_log(ac->avccontext, AV_LOG_WARNING, + "Transition from an ONLY_LONG or LONG_STOP to an EIGHT_SHORT sequence detected. " + "If you heard an audible artifact, please submit the sample to the FFmpeg developers.\n"); + for (i = 0; i < 2048; i += 256) { + ff_imdct_calc(&ac->mdct_small, buf + i, in + i/2); + ac->dsp.vector_fmul_reverse(ac->revers + i/2, buf + i + 128, swindow, 128); + } + for (i = 0; i < 448; i++) out[i] = saved[i] + ac->add_bias; + + ac->dsp.vector_fmul_add_add(out + 448 + 0*128, buf + 0*128, swindow_prev, saved + 448 , ac->add_bias, 128, 1); + ac->dsp.vector_fmul_add_add(out + 448 + 1*128, buf + 2*128, swindow, ac->revers + 0*128, ac->add_bias, 128, 1); + ac->dsp.vector_fmul_add_add(out + 448 + 2*128, buf + 4*128, swindow, ac->revers + 1*128, ac->add_bias, 128, 1); + ac->dsp.vector_fmul_add_add(out + 448 + 3*128, buf + 6*128, swindow, ac->revers + 2*128, ac->add_bias, 128, 1); + ac->dsp.vector_fmul_add_add(out + 448 + 4*128, buf + 8*128, swindow, ac->revers + 3*128, ac->add_bias, 64, 1); + +#if 0 + vector_fmul_add_add_add(&ac->dsp, out + 448 + 1*128, buf + 2*128, swindow, saved + 448 + 1*128, ac->revers + 0*128, ac->add_bias, 128); + vector_fmul_add_add_add(&ac->dsp, out + 448 + 2*128, buf + 4*128, swindow, saved + 448 + 2*128, ac->revers + 1*128, ac->add_bias, 128); + vector_fmul_add_add_add(&ac->dsp, out + 448 + 3*128, buf + 6*128, swindow, saved + 448 + 3*128, ac->revers + 2*128, ac->add_bias, 128); + vector_fmul_add_add_add(&ac->dsp, out + 448 + 4*128, buf + 8*128, swindow, saved + 448 + 4*128, ac->revers + 3*128, ac->add_bias, 64); +#endif + + ac->dsp.vector_fmul_add_add(saved, buf + 1024 + 64, swindow + 64, ac->revers + 3*128+64, 0, 64, 1); + ac->dsp.vector_fmul_add_add(saved + 64, buf + 1024 + 2*128, swindow, ac->revers + 4*128, 0, 128, 1); + ac->dsp.vector_fmul_add_add(saved + 192, buf + 1024 + 4*128, swindow, ac->revers + 5*128, 0, 128, 1); + ac->dsp.vector_fmul_add_add(saved + 320, buf + 1024 + 6*128, swindow, ac->revers + 6*128, 0, 128, 1); + memcpy( saved + 448, ac->revers + 7*128, 128 * sizeof(float)); + memset( saved + 576, 0, 448 * sizeof(float)); + } else { + ff_imdct_calc(&ac->mdct, buf, in); + if (ics->window_sequence[0] == LONG_STOP_SEQUENCE) { + for (i = 0; i < 448; i++) out[i] = saved[i] + ac->add_bias; + ac->dsp.vector_fmul_add_add(out + 448, buf + 448, swindow_prev, saved + 448, ac->add_bias, 128, 1); + for (i = 576; i < 1024; i++) out[i] = buf[i] + saved[i] + ac->add_bias; + } else { + ac->dsp.vector_fmul_add_add(out, buf, lwindow_prev, saved, ac->add_bias, 1024, 1); + } + if (ics->window_sequence[0] == LONG_START_SEQUENCE) { + memcpy(saved, buf + 1024, 448 * sizeof(float)); + ac->dsp.vector_fmul_reverse(saved + 448, buf + 1024 + 448, swindow, 128); + memset(saved + 576, 0, 448 * sizeof(float)); + } else { + ac->dsp.vector_fmul_reverse(saved, buf + 1024, lwindow, 1024); + } + } +} + /** * Apply dependent channel coupling (applied before IMDCT). * @@ -789,6 +1005,91 @@ static void apply_independent_coupling(AACContext * ac, SingleChannelElement * s sce->ret[i] += cc->coup.gain[index][0] * (cc->ch[0].ret[i] - ac->add_bias); } + } + } + } +} + +static int aac_decode_frame(AVCodecContext * avccontext, void * data, int * data_size, const uint8_t * buf, int buf_size) { + AACContext * ac = avccontext->priv_data; + GetBitContext gb; + enum RawDataBlockType elem_type; + int err, elem_id, data_size_tmp; + + init_get_bits(&gb, buf, buf_size*8); + + // parse + while ((elem_type = get_bits(&gb, 3)) != TYPE_END) { + elem_id = get_bits(&gb, 4); + err = -1; + + if(elem_type == TYPE_SCE && elem_id == 1 && + !ac->che[TYPE_SCE][elem_id] && ac->che[TYPE_LFE][0]) { + /* Some streams incorrectly code 5.1 audio as SCE[0] CPE[0] CPE[1] SCE[1] + instead of SCE[0] CPE[0] CPE[0] LFE[0]. If we seem to have + encountered such a stream, transfer the LFE[0] element to SCE[1] */ + ac->che[TYPE_SCE][elem_id] = ac->che[TYPE_LFE][0]; + ac->che[TYPE_LFE][0] = NULL; + } + if(elem_type && elem_type < TYPE_DSE) { + if(!ac->che[elem_type][elem_id]) + return -1; + if(elem_type != TYPE_CCE) + ac->che[elem_type][elem_id]->coup.coupling_point = 4; + } + + switch (elem_type) { + + case TYPE_SCE: + err = decode_ics(ac, &ac->che[TYPE_SCE][elem_id]->ch[0], &gb, 0, 0); + break; + + case TYPE_CPE: + err = decode_cpe(ac, &gb, elem_id); + break; + + case TYPE_CCE: + err = decode_cce(ac, &gb, ac->che[TYPE_SCE][elem_id]); + break; + + case TYPE_LFE: + err = decode_ics(ac, &ac->che[TYPE_LFE][elem_id]->ch[0], &gb, 0, 0); + break; + + case TYPE_DSE: + skip_data_stream_element(&gb); + err = 0; + break; + + case TYPE_PCE: + { + enum ChannelPosition new_che_pos[4][MAX_ELEM_ID]; + memset(new_che_pos, 0, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0])); + if((err = decode_pce(ac, new_che_pos, &gb))) + break; + err = output_configure(ac, ac->che_pos, new_che_pos); + break; + } + + case TYPE_FIL: + if (elem_id == 15) + elem_id += get_bits(&gb, 8) - 1; + while (elem_id > 0) + elem_id -= decode_extension_payload(ac, &gb, elem_id); + err = 0; /* FIXME */ + break; + + default: + err = -1; /* should not happen, but keeps compiler happy */ + break; + } + + if(err) + return err; + } + + spectral_to_sample(ac); + if (!ac->is_saved) { ac->is_saved = 1; *data_size = 0; diff --git a/libavcodec/aac.h b/libavcodec/aac.h index aafb8261be..d1be156586 100644 --- a/libavcodec/aac.h +++ b/libavcodec/aac.h @@ -135,6 +135,17 @@ enum CouplingPoint { /** * Individual Channel Stream */ +typedef struct { + uint8_t max_sfb; ///< number of scalefactor bands per group + enum WindowSequence window_sequence[2]; + uint8_t use_kb_window[2]; ///< If set, use Kaiser-Bessel window, otherwise use a sinus window. + int num_window_groups; + uint8_t group_len[8]; + const uint16_t *swb_offset; ///< table of offsets to the lowest spectral coefficient of a scalefactor band, sfb, for a particular window + int num_swb; ///< number of scalefactor window bands + int num_windows; + int tns_max_bands; +} IndividualChannelStream; /** * Dynamic Range Control - decoded from the bitstream but not processed further. @@ -163,6 +174,41 @@ typedef struct { * coupling parameters */ typedef struct { + enum CouplingPoint coupling_point; ///< The point during decoding at which coupling is applied. + int num_coupled; ///< number of target elements + enum RawDataBlockType type[8]; ///< Type of channel element to be coupled - SCE or CPE. + int id_select[8]; ///< element id + int ch_select[8]; /**< [0] shared list of gains; [1] list of gains for left channel; + * [2] list of gains for right channel; [3] lists of gains for both channels + */ + float gain[16][120]; +} ChannelCoupling; + +/** + * Single Channel Element - used for both SCE and LFE elements. + */ +typedef struct { + IndividualChannelStream ics; + TemporalNoiseShaping tns; + enum BandType band_type[120]; ///< band types + int band_type_run_end[120]; ///< band type run end points + float sf[120]; ///< scalefactors + DECLARE_ALIGNED_16(float, coeffs[1024]); ///< coefficients for IMDCT + DECLARE_ALIGNED_16(float, saved[1024]); ///< overlap + DECLARE_ALIGNED_16(float, ret[1024]); ///< PCM output +} SingleChannelElement; + +/** + * channel element - generic struct for SCE/CPE/CCE/LFE + */ +typedef struct { + // CPE specific + uint8_t ms_mask[120]; ///< Set if mid/side stereo is used for each scalefactor window band + // shared + SingleChannelElement ch[2]; + // CCE specific + ChannelCoupling coup; +} ChannelElement; /** * main AAC context |