diff options
author | Sascha Sommer <saschasommer@freenet.de> | 2009-08-02 16:57:07 +0400 |
---|---|---|
committer | Sascha Sommer <saschasommer@freenet.de> | 2009-08-02 16:57:07 +0400 |
commit | da136c7e05246f59d019773d34bbabe66ced517d (patch) | |
tree | 89d295ad4e886881d27f800b6a3f7ad3f4bfa535 /libavcodec/wmaprodec.c | |
parent | 577d383b0c8f4c79a1a69394a6b108e7dc540f10 (diff) |
add approved hunks of the wmapro decoder
Originally committed as revision 19563 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/wmaprodec.c')
-rw-r--r-- | libavcodec/wmaprodec.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c new file mode 100644 index 0000000000..83c8cc5f77 --- /dev/null +++ b/libavcodec/wmaprodec.c @@ -0,0 +1,145 @@ +/** + *@brief Uninitialize the decoder and free all resources. + *@param avctx codec context + *@return 0 on success, < 0 otherwise + */ +static av_cold int decode_end(AVCodecContext *avctx) +{ + WMA3DecodeContext *s = avctx->priv_data; + int i; + + av_freep(&s->num_sfb); + av_freep(&s->sfb_offsets); + av_freep(&s->subwoofer_cutoffs); + av_freep(&s->sf_offsets); + + for (i=0 ; i<WMAPRO_BLOCK_SIZES ; i++) + ff_mdct_end(&s->mdct_ctx[i]); + + return 0; +} + +/** + *@brief Calculate a decorrelation matrix from the bitstream parameters. + *@param s codec context + *@param chgroup channel group for which the matrix needs to be calculated + */ +static void decode_decorrelation_matrix(WMA3DecodeContext* s, + WMA3ChannelGroup* chgroup) +{ + int i; + int offset = 0; + int8_t rotation_offset[WMAPRO_MAX_CHANNELS * WMAPRO_MAX_CHANNELS]; + memset(chgroup->decorrelation_matrix,0, + sizeof(float) *s->num_channels * s->num_channels); + + for (i=0;i<chgroup->num_channels * (chgroup->num_channels - 1) >> 1;i++) + rotation_offset[i] = get_bits(&s->gb,6); + + for (i=0;i<chgroup->num_channels;i++) + chgroup->decorrelation_matrix[chgroup->num_channels * i + i] = + get_bits1(&s->gb) ? 1.0 : -1.0; + + for (i=1;i<chgroup->num_channels;i++) { + int x; + for (x=0;x<i;x++) { + int y; + for (y=0;y < i + 1 ; y++) { + float v1 = chgroup->decorrelation_matrix[x * chgroup->num_channels + y]; + float v2 = chgroup->decorrelation_matrix[i * chgroup->num_channels + y]; + int n = rotation_offset[offset + x]; + float sinv; + float cosv; + + if (n<32) { + sinv = sin64[n]; + cosv = sin64[32-n]; + } else { + sinv = sin64[64-n]; + cosv = -sin64[n-32]; + } + + chgroup->decorrelation_matrix[y + x * chgroup->num_channels] = + (v1 * sinv) - (v2 * cosv); + chgroup->decorrelation_matrix[y + i * chgroup->num_channels] = + (v1 * cosv) + (v2 * sinv); + } + } + offset += i; + } +} + +/** + *@brief Reconstruct the individual channel data. + *@param s codec context + */ +static void inverse_channel_transform(WMA3DecodeContext *s) +{ + int i; + + for (i=0;i<s->num_chgroups;i++) { + + if (s->chgroup[i].transform == 1) { + /** M/S stereo decoding */ + int16_t* sfb_offsets = s->cur_sfb_offsets; + float* ch0 = *sfb_offsets + s->channel[0].coeffs; + float* ch1 = *sfb_offsets++ + s->channel[1].coeffs; + const char* tb = s->chgroup[i].transform_band; + const char* tb_end = tb + s->num_bands; + + while (tb < tb_end) { + const float* ch0_end = s->channel[0].coeffs + + FFMIN(*sfb_offsets,s->subframe_len); + if (*tb++ == 1) { + while (ch0 < ch0_end) { + const float v1 = *ch0; + const float v2 = *ch1; + *ch0++ = v1 - v2; + *ch1++ = v1 + v2; + } + } else { + while (ch0 < ch0_end) { + *ch0++ *= 181.0 / 128; + *ch1++ *= 181.0 / 128; + } + } + ++sfb_offsets; + } + } else if (s->chgroup[i].transform) { + float data[WMAPRO_MAX_CHANNELS]; + const int num_channels = s->chgroup[i].num_channels; + float** ch_data = s->chgroup[i].channel_data; + float** ch_end = ch_data + num_channels; + const int8_t* tb = s->chgroup[i].transform_band; + int16_t* sfb; + + /** multichannel decorrelation */ + for (sfb = s->cur_sfb_offsets ; + sfb < s->cur_sfb_offsets + s->num_bands;sfb++) { + if (*tb++ == 1) { + int y; + /** multiply values with the decorrelation_matrix */ + for (y=sfb[0];y<FFMIN(sfb[1], s->subframe_len);y++) { + const float* mat = s->chgroup[i].decorrelation_matrix; + const float* data_end= data + num_channels; + float* data_ptr= data; + float** ch; + + for (ch = ch_data;ch < ch_end; ch++) + *data_ptr++ = (*ch)[y]; + + for (ch = ch_data; ch < ch_end; ch++) { + float sum = 0; + data_ptr = data; + while (data_ptr < data_end) + sum += *data_ptr++ * *mat++; + + (*ch)[y] = sum; + } + } + } + } + } + } +} + |