Replace custom modified discrete cosine transform with ffmpeg's own.
authorIan Braithwaite <ian@braithwaite.dk>
Sun, 11 Mar 2007 20:30:06 +0000 (20:30 +0000)
committerBenjamin Larsson <banan@ludd.ltu.se>
Sun, 11 Mar 2007 20:30:06 +0000 (20:30 +0000)
This does alter the decoded output, but not by much.
The new output is closer to that produced by Real's "official" decoder,
and the decoder runs slightly faster.

Patch by Ian Braithwaite ian at braithwaite dot dk

Originally committed as revision 8325 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavcodec/cook.c

index 0bc9719..0a21945 100644 (file)
@@ -90,15 +90,9 @@ typedef struct {
     int                 random_state;
 
     /* transform data */
     int                 random_state;
 
     /* transform data */
-    FFTContext          fft_ctx;
-    DECLARE_ALIGNED_16(FFTSample, mlt_tmp[1024]);  /* temporary storage for imlt */
+    MDCTContext         mdct_ctx;
+    DECLARE_ALIGNED_16(FFTSample, mdct_tmp[1024]);  /* temporary storage for imlt */
     float*              mlt_window;
     float*              mlt_window;
-    float*              mlt_precos;
-    float*              mlt_presin;
-    float*              mlt_postcos;
-    int                 fft_size;
-    int                 fft_order;
-    int                 mlt_size;       //modulated lapped transform size
 
     /* gain buffers */
     cook_gains          gains1;
 
     /* gain buffers */
     cook_gains          gains1;
@@ -225,34 +219,25 @@ static int init_cook_vlc_tables(COOKContext *q) {
 static int init_cook_mlt(COOKContext *q) {
     int j;
     float alpha;
 static int init_cook_mlt(COOKContext *q) {
     int j;
     float alpha;
+    int mlt_size = q->samples_per_channel;
 
 
-    /* Allocate the buffers, could be replaced with a static [512]
-       array if needed. */
-    q->mlt_size = q->samples_per_channel;
-    q->mlt_window = av_malloc(sizeof(float)*q->mlt_size);
-    q->mlt_precos = av_malloc(sizeof(float)*q->mlt_size/2);
-    q->mlt_presin = av_malloc(sizeof(float)*q->mlt_size/2);
-    q->mlt_postcos = av_malloc(sizeof(float)*q->mlt_size/2);
+    if ((q->mlt_window = av_malloc(sizeof(float)*mlt_size)) == 0)
+      return -1;
 
     /* Initialize the MLT window: simple sine window. */
 
     /* Initialize the MLT window: simple sine window. */
-    alpha = M_PI / (2.0 * (float)q->mlt_size);
-    for(j=0 ; j<q->mlt_size ; j++) {
-        q->mlt_window[j] = sin((j + 512.0/(float)q->mlt_size) * alpha);
+    alpha = M_PI / (2.0 * (float)mlt_size);
+    for(j=0 ; j<mlt_size ; j++)
+        q->mlt_window[j] = sin((j + 0.5) * alpha) * sqrt(2.0 / q->samples_per_channel);
+
+    /* Initialize the MDCT. */
+    if (ff_mdct_init(&q->mdct_ctx, av_log2(mlt_size)+1, 1)) {
+      av_free(q->mlt_window);
+      return -1;
     }
     }
+    av_log(NULL,AV_LOG_DEBUG,"MDCT initialized, order = %d.\n",
+           av_log2(mlt_size)+1);
 
 
-    /* pre/post twiddle factors */
-    for (j=0 ; j<q->mlt_size/2 ; j++){
-        q->mlt_precos[j] = cos( ((j+0.25)*M_PI)/q->mlt_size);
-        q->mlt_presin[j] = sin( ((j+0.25)*M_PI)/q->mlt_size);
-        q->mlt_postcos[j] = (float)sqrt(2.0/(float)q->mlt_size)*cos( ((float)j*M_PI) /q->mlt_size); //sqrt(2/MLT_size) = scalefactor
-    }
-
-    /* Initialize the FFT. */
-    ff_fft_init(&q->fft_ctx, av_log2(q->mlt_size)-1, 0);
-    av_log(NULL,AV_LOG_DEBUG,"FFT initialized, order = %d.\n",
-           av_log2(q->samples_per_channel)-1);
-
-    return (int)(q->mlt_window && q->mlt_precos && q->mlt_presin && q->mlt_postcos);
+    return 0;
 }
 
 /*************** init functions end ***********/
 }
 
 /*************** init functions end ***********/
@@ -313,13 +298,10 @@ static int cook_decode_close(AVCodecContext *avctx)
 
     /* Free allocated memory buffers. */
     av_free(q->mlt_window);
 
     /* Free allocated memory buffers. */
     av_free(q->mlt_window);
-    av_free(q->mlt_precos);
-    av_free(q->mlt_presin);
-    av_free(q->mlt_postcos);
     av_free(q->decoded_bytes_buffer);
 
     /* Free the transform. */
     av_free(q->decoded_bytes_buffer);
 
     /* Free the transform. */
-    ff_fft_end(&q->fft_ctx);
+    ff_mdct_end(&q->mdct_ctx);
 
     /* Free the VLC tables. */
     for (i=0 ; i<13 ; i++) {
 
     /* Free the VLC tables. */
     for (i=0 ; i<13 ; i++) {
@@ -714,39 +696,17 @@ static void mono_decode(COOKContext *q, float* mlt_buffer) {
  * @param mlt_tmp           pointer to temporary storage space
  */
 
  * @param mlt_tmp           pointer to temporary storage space
  */
 
-static void cook_imlt(COOKContext *q, float* inbuffer, float* outbuffer,
-                      float* mlt_tmp){
+static void cook_imlt(COOKContext *q, float* inbuffer, float* outbuffer)
+{
     int i;
 
     int i;
 
-    /* prerotation */
-    for(i=0 ; i<q->mlt_size ; i+=2){
-        outbuffer[i] = (q->mlt_presin[i/2] * inbuffer[q->mlt_size-1-i]) +
-                       (q->mlt_precos[i/2] * inbuffer[i]);
-        outbuffer[i+1] = (q->mlt_precos[i/2] * inbuffer[q->mlt_size-1-i]) -
-                         (q->mlt_presin[i/2] * inbuffer[i]);
-    }
-
-    /* FFT */
-    ff_fft_permute(&q->fft_ctx, (FFTComplex *) outbuffer);
-    ff_fft_calc (&q->fft_ctx, (FFTComplex *) outbuffer);
+    q->mdct_ctx.fft.imdct_calc(&q->mdct_ctx, outbuffer, inbuffer, q->mdct_tmp);
 
 
-    /* postrotation */
-    for(i=0 ; i<q->mlt_size ; i+=2){
-        mlt_tmp[i] =               (q->mlt_postcos[(q->mlt_size-1-i)/2] * outbuffer[i+1]) +
-                                   (q->mlt_postcos[i/2] * outbuffer[i]);
-        mlt_tmp[q->mlt_size-1-i] = (q->mlt_postcos[(q->mlt_size-1-i)/2] * outbuffer[i]) -
-                                   (q->mlt_postcos[i/2] * outbuffer[i+1]);
-    }
+    for(i = 0; i < q->samples_per_channel; i++){
+        float tmp = outbuffer[i];
 
 
-    /* window and reorder */
-    for(i=0 ; i<q->mlt_size/2 ; i++){
-        outbuffer[i] = mlt_tmp[q->mlt_size/2-1-i] * q->mlt_window[i];
-        outbuffer[q->mlt_size-1-i]= mlt_tmp[q->mlt_size/2-1-i] *
-                                    q->mlt_window[q->mlt_size-1-i];
-        outbuffer[q->mlt_size+i]= mlt_tmp[q->mlt_size/2+i] *
-                                  q->mlt_window[q->mlt_size-1-i];
-        outbuffer[2*q->mlt_size-1-i]= -(mlt_tmp[q->mlt_size/2+i] *
-                                      q->mlt_window[i]);
+        outbuffer[i] = q->mlt_window[i] * outbuffer[q->samples_per_channel + i];
+        outbuffer[q->samples_per_channel + i] = q->mlt_window[q->samples_per_channel - 1 - i] * -tmp;
     }
 }
 
     }
 }
 
@@ -944,7 +904,7 @@ mlt_compensate_output(COOKContext *q, float *decode_buffer,
 {
     int j;
 
 {
     int j;
 
-    cook_imlt(q, decode_buffer, q->mono_mdct_output, q->mlt_tmp);
+    cook_imlt(q, decode_buffer, q->mono_mdct_output);
     gain_compensate(q, gains, previous_buffer);
 
     /* Clip and convert floats to 16 bits.
     gain_compensate(q, gains, previous_buffer);
 
     /* Clip and convert floats to 16 bits.
@@ -1045,7 +1005,6 @@ static void dump_cook_context(COOKContext *q)
     PRINT("samples_per_frame",q->samples_per_frame);
     PRINT("subbands",q->subbands);
     PRINT("random_state",q->random_state);
     PRINT("samples_per_frame",q->samples_per_frame);
     PRINT("subbands",q->subbands);
     PRINT("random_state",q->random_state);
-    PRINT("mlt_size",q->mlt_size);
     PRINT("js_subband_start",q->js_subband_start);
     PRINT("log2_numvector_size",q->log2_numvector_size);
     PRINT("numvector_size",q->numvector_size);
     PRINT("js_subband_start",q->js_subband_start);
     PRINT("log2_numvector_size",q->log2_numvector_size);
     PRINT("numvector_size",q->numvector_size);
@@ -1145,7 +1104,6 @@ static int cook_decode_init(AVCodecContext *avctx)
     }
 
     /* Initialize variable relations */
     }
 
     /* Initialize variable relations */
-    q->mlt_size = q->samples_per_channel;
     q->numvector_size = (1 << q->log2_numvector_size);
 
     /* Generate tables */
     q->numvector_size = (1 << q->log2_numvector_size);
 
     /* Generate tables */
@@ -1183,7 +1141,7 @@ static int cook_decode_init(AVCodecContext *avctx)
     q->gains2.previous = q->gain_4;
 
     /* Initialize transform. */
     q->gains2.previous = q->gain_4;
 
     /* Initialize transform. */
-    if ( init_cook_mlt(q) == 0 )
+    if ( init_cook_mlt(q) != 0 )
         return -1;
 
     /* Try to catch some obviously faulty streams, othervise it might be exploitable */
         return -1;
 
     /* Try to catch some obviously faulty streams, othervise it might be exploitable */