[FFmpeg-cvslog] r14770 - in trunk/libavcodec: aac.c aac.h
superdump
subversion
Fri Aug 15 02:05:09 CEST 2008
Author: superdump
Date: Fri Aug 15 02:05:09 2008
New Revision: 14770
Log:
More OKed sections of AAC decoder code
Modified:
trunk/libavcodec/aac.c
trunk/libavcodec/aac.h
Modified: trunk/libavcodec/aac.c
==============================================================================
--- trunk/libavcodec/aac.c (original)
+++ trunk/libavcodec/aac.c Fri Aug 15 02:05:09 2008
@@ -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(AA
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(
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 *
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,
*/
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, G
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(AACConte
}
/**
+ * 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(AACConte
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(A
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;
Modified: trunk/libavcodec/aac.h
==============================================================================
--- trunk/libavcodec/aac.h (original)
+++ trunk/libavcodec/aac.h Fri Aug 15 02:05:09 2008
@@ -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
More information about the ffmpeg-cvslog
mailing list