summaryrefslogtreecommitdiff
path: root/libavcodec/wmaprodec.c
diff options
context:
space:
mode:
authorSascha Sommer <saschasommer@freenet.de>2009-08-02 12:57:07 +0000
committerSascha Sommer <saschasommer@freenet.de>2009-08-02 12:57:07 +0000
commitda136c7e05246f59d019773d34bbabe66ced517d (patch)
tree89d295ad4e886881d27f800b6a3f7ad3f4bfa535 /libavcodec/wmaprodec.c
parent577d383b0c8f4c79a1a69394a6b108e7dc540f10 (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.c145
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;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+