[Ffmpeg-devel] wma v2 decoding - attempt at fixing

Reimar Döffinger Reimar.Doeffinger
Sun Dec 25 19:54:08 CET 2005


Hi,
the attached patch is what my test resulted in so far.
The sample I looked at was:
With this patch, about 10% instead of 0% of it decode correctly.
The patch is crappy, ugly and sure opens a few security holes, but since
I won't work on it for the next few weeks (on holiday without PC :-) ),
I thought posting it won't hurt. Hopefully someone can find the real
fix ;-)...

Greetings,
Reimar D?ffinger
-------------- next part --------------
Index: libavcodec/wmadec.c
===================================================================
RCS file: /cvsroot/ffmpeg/ffmpeg/libavcodec/wmadec.c,v
retrieving revision 1.26
diff -u -r1.26 wmadec.c
--- libavcodec/wmadec.c	17 Dec 2005 18:14:31 -0000	1.26
+++ libavcodec/wmadec.c	25 Dec 2005 18:53:18 -0000
@@ -34,6 +34,7 @@
 #include "avcodec.h"
 #include "bitstream.h"
 #include "dsputil.h"
+#undef printf
 
 /* size of blocks */
 #define BLOCK_MIN_BITS 7
@@ -98,6 +99,7 @@
     int block_len; /* block length in samples */
     int block_num; /* block number in current frame */
     int block_pos; /* current position in frame */
+    int block_noncoded;
     uint8_t ms_stereo; /* true if mid/side stereo mode */
     uint8_t channel_coded[MAX_CHANNELS]; /* true if channel is coded */
     float exponents[MAX_CHANNELS][BLOCK_MAX_SIZE] __attribute__((aligned(16)));
@@ -108,7 +110,7 @@
     float *windows[BLOCK_NB_SIZES];
     FFTSample mdct_tmp[BLOCK_MAX_SIZE] __attribute__((aligned(16))); /* temporary storage for imdct */
     /* output buffer for one frame and the last for IMDCT windowing */
-    float frame_out[MAX_CHANNELS][BLOCK_MAX_SIZE * 2] __attribute__((aligned(16)));
+    float frame_out[MAX_CHANNELS][BLOCK_MAX_SIZE * 32] __attribute__((aligned(16)));
     /* last frame info */
     uint8_t last_superframe[MAX_CODED_SUPERFRAME_SIZE + 4]; /* padding added */
     int last_bitoffset;
@@ -241,6 +243,7 @@
     s->use_bit_reservoir = flags2 & 0x0002;
     s->use_variable_block_len = flags2 & 0x0004;
 
+    s->sample_rate *= 2;
     /* compute MDCT block size */
     if (s->sample_rate <= 16000) {
         s->frame_len_bits = 9;
@@ -250,12 +253,15 @@
     } else {
         s->frame_len_bits = 11;
     }
+printf("info: %i %i %i %i\n", s->sample_rate, s->version, s->bit_rate, s->nb_channels);
+    s->sample_rate /= 2;
     s->frame_len = 1 << s->frame_len_bits;
     if (s->use_variable_block_len) {
         int nb_max, nb;
         nb = ((flags2 >> 3) & 3) + 1;
         if ((s->bit_rate / s->nb_channels) >= 32000)
             nb += 2;
+	nb++;
         nb_max = s->frame_len_bits - BLOCK_MIN_BITS;
         if (nb > nb_max)
             nb = nb_max;
@@ -518,6 +524,8 @@
                   &coef_vlcs[coef_vlc_table * 2]);
     init_coef_vlc(&s->coef_vlc[1], &s->run_table[1], &s->level_table[1],
                   &coef_vlcs[coef_vlc_table * 2 + 1]);
+    s->sample_rate *= 2;
+    avctx->sample_rate = s->sample_rate;
     return 0;
 }
 
@@ -716,6 +724,7 @@
     tprintf("***decode_block: %d:%d\n", s->frame_count - 1, s->block_num);
 #endif
 
+printf("1\n");
     /* compute current block length */
     if (s->use_variable_block_len) {
         n = av_log2(s->nb_block_sizes - 1) + 1;
@@ -723,10 +732,12 @@
         if (s->reset_block_lengths) {
             s->reset_block_lengths = 0;
             v = get_bits(&s->gb, n);
+printf("1b: %i, %i\n", v, s->nb_block_sizes);
             if (v >= s->nb_block_sizes)
                 return -1;
             s->prev_block_len_bits = s->frame_len_bits - v;
             v = get_bits(&s->gb, n);
+printf("1c: %i, %i\n", v, s->nb_block_sizes);
             if (v >= s->nb_block_sizes)
                 return -1;
             s->block_len_bits = s->frame_len_bits - v;
@@ -736,6 +747,7 @@
             s->block_len_bits = s->next_block_len_bits;
         }
         v = get_bits(&s->gb, n);
+printf("1d: %i, %i\n", v, s->nb_block_sizes);
         if (v >= s->nb_block_sizes)
             return -1;
         s->next_block_len_bits = s->frame_len_bits - v;
@@ -745,11 +757,7 @@
         s->prev_block_len_bits = s->frame_len_bits;
         s->block_len_bits = s->frame_len_bits;
     }
-
-    /* now check if the block length is coherent with the frame length */
     s->block_len = 1 << s->block_len_bits;
-    if ((s->block_pos + s->block_len) > s->frame_len)
-        return -1;
 
     if (s->nb_channels == 2) {
         s->ms_stereo = get_bits(&s->gb, 1);
@@ -762,8 +770,17 @@
     }
     /* if no channel coded, no need to go further */
     /* XXX: fix potential framing problems */
-    if (!v)
-        goto next;
+    if (!v) {
+printf("non coded: %i %i\n", s->block_len, s->ms_stereo);
+        s->block_noncoded += s->block_len;
+        return 1;
+//        goto next;
+    }
+
+    /* now check if the block length is coherent with the frame length */
+printf("2: %i %i %i %i\n", s->block_pos, s->block_len, s->block_pos - s->block_noncoded + s->block_len, s->frame_len);
+//    if ((s->block_pos - s->block_noncoded + s->block_len) > s->frame_len)
+//        return -1;
 
     bsize = s->frame_len_bits - s->block_len_bits;
 
@@ -793,6 +810,7 @@
     for(ch = 0; ch < s->nb_channels; ch++)
         nb_coefs[ch] = n;
 
+printf("2b\n");
     /* complex coding */
     if (s->use_noise_coding) {
 
@@ -838,6 +856,7 @@
         parse_exponents = get_bits(&s->gb, 1);
     }
 
+printf("3\n");
     if (parse_exponents) {
         for(ch = 0; ch < s->nb_channels; ch++) {
             if (s->channel_coded[ch]) {
@@ -858,6 +877,7 @@
         }
     }
 
+printf("4\n");
     /* parse spectral coefficients : just RLE encoding */
     for(ch = 0; ch < s->nb_channels; ch++) {
         if (s->channel_coded[ch]) {
@@ -899,7 +919,7 @@
                     level = -level;
                 ptr += run;
                 if (ptr >= eptr)
-                    return -1;
+                    break;
                 *ptr++ = level;
                 /* NOTE: EOB can be omitted */
                 if (ptr >= eptr)
@@ -1018,6 +1038,7 @@
         }
     }
 
+printf("5\n");
 #ifdef TRACE
     for(ch = 0; ch < s->nb_channels; ch++) {
         if (s->channel_coded[ch]) {
@@ -1093,6 +1114,7 @@
     }
 
 
+printf("6\n");
     for(ch = 0; ch < s->nb_channels; ch++) {
         if (s->channel_coded[ch]) {
             FFTSample output[BLOCK_MAX_SIZE * 2] __attribute__((aligned(16)));
@@ -1134,7 +1156,7 @@
     /* update block number */
     s->block_num++;
     s->block_pos += s->block_len;
-    if (s->block_pos >= s->frame_len)
+    if (s->block_pos - s->block_noncoded >= s->frame_len)
         return 1;
     else
         return 0;
@@ -1154,16 +1176,18 @@
     /* read each block */
     s->block_num = 0;
     s->block_pos = 0;
+    s->block_noncoded = 0;
     for(;;) {
         ret = wma_decode_block(s);
         if (ret < 0)
-            return -1;
-        if (ret)
+printf("fail!\n");
+//            return -1;
+        if (ret > 0)
             break;
     }
 
     /* convert frame to integer */
-    n = s->frame_len;
+    n = s->block_pos;//s->frame_len;
     incr = s->nb_channels;
     for(ch = 0; ch < s->nb_channels; ch++) {
         ptr = samples + ch;
@@ -1244,7 +1268,7 @@
                current one */
             if (wma_decode_frame(s, samples) < 0)
                 goto fail;
-            samples += s->nb_channels * s->frame_len;
+            samples += s->nb_channels * s->block_pos;//s->frame_len;
         }
 
         /* read each frame starting from bit_offset */
@@ -1258,7 +1282,7 @@
         for(i=0;i<nb_frames;i++) {
             if (wma_decode_frame(s, samples) < 0)
                 goto fail;
-            samples += s->nb_channels * s->frame_len;
+            samples += s->nb_channels * s->block_pos;//s->frame_len;
         }
 
         /* we copy the end of the frame in the last frame buffer */
@@ -1275,7 +1299,7 @@
         /* single frame decode */
         if (wma_decode_frame(s, samples) < 0)
             goto fail;
-        samples += s->nb_channels * s->frame_len;
+        samples += s->nb_channels * s->block_pos;//s->frame_len;
     }
     *data_size = (int8_t *)samples - (int8_t *)data;
     return s->block_align;



More information about the ffmpeg-devel mailing list