]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/adpcm.c
adpcm: check buffer size in Funcom ISS decoder before reading header.
[ffmpeg] / libavcodec / adpcm.c
index df316fb6461019fb9ba2bbfa87bc12a4d5b6e17d..75d32633be1e02ff8125462074d9de9d0667c75e 100644 (file)
@@ -340,7 +340,6 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
     ADPCMDecodeContext *c = avctx->priv_data;
     ADPCMChannelStatus *cs;
     int n, m, channel, i;
-    int block_predictor[2];
     short *samples;
     short *samples_end;
     const uint8_t *src;
@@ -448,60 +447,66 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
         }
 
         while(src < buf + buf_size){
-            for(m=0; m<4; m++){
-                for(i=0; i<=st; i++)
-                    *samples++ = adpcm_ima_expand_nibble(&c->status[i], src[4*i] & 0x0F, 3);
-                for(i=0; i<=st; i++)
-                    *samples++ = adpcm_ima_expand_nibble(&c->status[i], src[4*i] >> 4  , 3);
-                src++;
+            for (i = 0; i < avctx->channels; i++) {
+                cs = &c->status[i];
+                for (m = 0; m < 4; m++) {
+                    uint8_t v = *src++;
+                    *samples = adpcm_ima_expand_nibble(cs, v & 0x0F, 3);
+                    samples += avctx->channels;
+                    *samples = adpcm_ima_expand_nibble(cs, v >> 4  , 3);
+                    samples += avctx->channels;
+                }
+                samples -= 8 * avctx->channels - 1;
             }
-            src += 4*st;
+            samples += 7 * avctx->channels;
         }
         break;
     case CODEC_ID_ADPCM_4XM:
-        cs = &(c->status[0]);
-        c->status[0].predictor= (int16_t)bytestream_get_le16(&src);
-        if(st){
-            c->status[1].predictor= (int16_t)bytestream_get_le16(&src);
-        }
-        c->status[0].step_index= (int16_t)bytestream_get_le16(&src);
-        if(st){
-            c->status[1].step_index= (int16_t)bytestream_get_le16(&src);
-        }
-        if (cs->step_index < 0) cs->step_index = 0;
-        if (cs->step_index > 88) cs->step_index = 88;
+        for (i = 0; i < avctx->channels; i++)
+            c->status[i].predictor= (int16_t)bytestream_get_le16(&src);
 
-        m= (buf_size - (src - buf))>>st;
-        for(i=0; i<m; i++) {
-            *samples++ = adpcm_ima_expand_nibble(&c->status[0], src[i] & 0x0F, 4);
-            if (st)
-                *samples++ = adpcm_ima_expand_nibble(&c->status[1], src[i+m] & 0x0F, 4);
-            *samples++ = adpcm_ima_expand_nibble(&c->status[0], src[i] >> 4, 4);
-            if (st)
-                *samples++ = adpcm_ima_expand_nibble(&c->status[1], src[i+m] >> 4, 4);
+        for (i = 0; i < avctx->channels; i++) {
+            c->status[i].step_index= (int16_t)bytestream_get_le16(&src);
+            c->status[i].step_index = av_clip(c->status[i].step_index, 0, 88);
         }
 
-        src += m<<st;
+        m= (buf_size - (src - buf))>>st;
 
+        for (i = 0; i < avctx->channels; i++) {
+            samples = (short*)data + i;
+            cs = &c->status[i];
+            for (n = 0; n < m; n++) {
+                uint8_t v = *src++;
+                *samples = adpcm_ima_expand_nibble(cs, v & 0x0F, 4);
+                samples += avctx->channels;
+                *samples = adpcm_ima_expand_nibble(cs, v >> 4  , 4);
+                samples += avctx->channels;
+            }
+        }
+        samples -= (avctx->channels - 1);
         break;
     case CODEC_ID_ADPCM_MS:
+    {
+        int block_predictor;
+
         if (avctx->block_align != 0 && buf_size > avctx->block_align)
             buf_size = avctx->block_align;
         n = buf_size - 7 * avctx->channels;
         if (n < 0)
             return -1;
-        block_predictor[0] = av_clip(*src++, 0, 6);
-        block_predictor[1] = 0;
-        if (st)
-            block_predictor[1] = av_clip(*src++, 0, 6);
+
+        block_predictor = av_clip(*src++, 0, 6);
+        c->status[0].coeff1 = ff_adpcm_AdaptCoeff1[block_predictor];
+        c->status[0].coeff2 = ff_adpcm_AdaptCoeff2[block_predictor];
+        if (st) {
+            block_predictor = av_clip(*src++, 0, 6);
+            c->status[1].coeff1 = ff_adpcm_AdaptCoeff1[block_predictor];
+            c->status[1].coeff2 = ff_adpcm_AdaptCoeff2[block_predictor];
+        }
         c->status[0].idelta = (int16_t)bytestream_get_le16(&src);
         if (st){
             c->status[1].idelta = (int16_t)bytestream_get_le16(&src);
         }
-        c->status[0].coeff1 = ff_adpcm_AdaptCoeff1[block_predictor[0]];
-        c->status[0].coeff2 = ff_adpcm_AdaptCoeff2[block_predictor[0]];
-        c->status[1].coeff1 = ff_adpcm_AdaptCoeff1[block_predictor[1]];
-        c->status[1].coeff2 = ff_adpcm_AdaptCoeff2[block_predictor[1]];
 
         c->status[0].sample1 = bytestream_get_le16(&src);
         if (st) c->status[1].sample1 = bytestream_get_le16(&src);
@@ -518,21 +523,25 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
             src ++;
         }
         break;
+    }
     case CODEC_ID_ADPCM_IMA_DK4:
         if (avctx->block_align != 0 && buf_size > avctx->block_align)
             buf_size = avctx->block_align;
 
-        c->status[0].predictor  = (int16_t)bytestream_get_le16(&src);
-        c->status[0].step_index = *src++;
-        src++;
-        *samples++ = c->status[0].predictor;
-        if (st) {
-            c->status[1].predictor  = (int16_t)bytestream_get_le16(&src);
-            c->status[1].step_index = *src++;
+        n = buf_size - 4 * avctx->channels;
+        if (n < 0) {
+            av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
+            return AVERROR(EINVAL);
+        }
+
+        for (channel = 0; channel < avctx->channels; channel++) {
+            cs = &c->status[channel];
+            cs->predictor  = (int16_t)bytestream_get_le16(&src);
+            cs->step_index = *src++;
             src++;
-            *samples++ = c->status[1].predictor;
+            *samples++ = cs->predictor;
         }
-        while (src < buf + buf_size) {
+        while (n-- > 0) {
             uint8_t v = *src++;
             *samples++ = adpcm_ima_expand_nibble(&c->status[0 ], v >> 4  , 3);
             *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
@@ -584,16 +593,20 @@ static int adpcm_decode_frame(AVCodecContext *avctx,
         }
         break;
     case CODEC_ID_ADPCM_IMA_ISS:
-        c->status[0].predictor  = (int16_t)AV_RL16(src + 0);
-        c->status[0].step_index = src[2];
-        src += 4;
-        if(st) {
-            c->status[1].predictor  = (int16_t)AV_RL16(src + 0);
-            c->status[1].step_index = src[2];
-            src += 4;
+        n = buf_size - 4 * avctx->channels;
+        if (n < 0) {
+            av_log(avctx, AV_LOG_ERROR, "packet is too small\n");
+            return AVERROR(EINVAL);
         }
 
-        while (src < buf + buf_size) {
+        for (channel = 0; channel < avctx->channels; channel++) {
+            cs = &c->status[channel];
+            cs->predictor  = (int16_t)bytestream_get_le16(&src);
+            cs->step_index = *src++;
+            src++;
+        }
+
+        while (n-- > 0) {
             uint8_t v1, v2;
             uint8_t v = *src++;
             /* nibbles are swapped for mono */