[FFmpeg-cvslog] dpcm: calculate and check actual output data size prior to decoding.

Justin Ruggles git at videolan.org
Sat Oct 1 03:06:42 CEST 2011


ffmpeg | branch: master | Justin Ruggles <justin.ruggles at gmail.com> | Sun Sep 11 11:51:08 2011 -0400| [76db17dc7d4f19f9a03bdd6de79c2ea37b76888f] | committer: Justin Ruggles

dpcm: calculate and check actual output data size prior to decoding.

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=76db17dc7d4f19f9a03bdd6de79c2ea37b76888f
---

 libavcodec/dpcm.c |   50 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/libavcodec/dpcm.c b/libavcodec/dpcm.c
index 185d04e..3f3b422 100644
--- a/libavcodec/dpcm.c
+++ b/libavcodec/dpcm.c
@@ -178,9 +178,30 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
     if (!buf_size)
         return 0;
 
-    // almost every DPCM variant expands one byte of data into two
-    if(*data_size/2 < buf_size)
-        return -1;
+    /* calculate output size */
+    switch(avctx->codec->id) {
+    case CODEC_ID_ROQ_DPCM:
+        out = buf_size - 8;
+        break;
+    case CODEC_ID_INTERPLAY_DPCM:
+        out = buf_size - 6 - s->channels;
+        break;
+    case CODEC_ID_XAN_DPCM:
+        out = buf_size - 2 * s->channels;
+        break;
+    case CODEC_ID_SOL_DPCM:
+        if (avctx->codec_tag != 3)
+            out = buf_size * 2;
+        else
+            out = buf_size;
+        break;
+    }
+    out *= av_get_bytes_per_sample(avctx->sample_fmt);
+
+    if (*data_size < out) {
+        av_log(avctx, AV_LOG_ERROR, "output buffer is too small\n");
+        return AVERROR(EINVAL);
+    }
 
     switch(avctx->codec->id) {
 
@@ -195,10 +216,10 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
         SE_16BIT(predictor[1]);
 
         /* decode the samples */
-        for (in = 8, out = 0; in < buf_size; in++, out++) {
+        for (in = 8; in < buf_size; in++) {
             predictor[ch] += s->roq_square_array[buf[in]];
             predictor[ch] = av_clip_int16(predictor[ch]);
-            output_samples[out] = predictor[ch];
+            *output_samples++ = predictor[ch];
 
             /* toggle channel */
             ch ^= stereo;
@@ -210,23 +231,22 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
         predictor[0] = AV_RL16(&buf[in]);
         in += 2;
         SE_16BIT(predictor[0])
-        output_samples[out++] = predictor[0];
+        *output_samples++ = predictor[0];
         if (stereo) {
             predictor[1] = AV_RL16(&buf[in]);
             in += 2;
             SE_16BIT(predictor[1])
-            output_samples[out++] = predictor[1];
+            *output_samples++ = predictor[1];
         }
 
         while (in < buf_size) {
             predictor[ch] += interplay_delta_table[buf[in++]];
             predictor[ch] = av_clip_int16(predictor[ch]);
-            output_samples[out++] = predictor[ch];
+            *output_samples++ = predictor[ch];
 
             /* toggle channel */
             ch ^= stereo;
         }
-
         break;
 
     case CODEC_ID_XAN_DPCM:
@@ -256,7 +276,7 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
             predictor[ch] += diff;
 
             predictor[ch] = av_clip_int16(predictor[ch]);
-            output_samples[out++] = predictor[ch];
+            *output_samples++ = predictor[ch];
 
             /* toggle channel */
             ch ^= stereo;
@@ -265,8 +285,6 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
     case CODEC_ID_SOL_DPCM:
         in = 0;
         if (avctx->codec_tag != 3) {
-            if(*data_size/4 < buf_size)
-                return -1;
             while (in < buf_size) {
                 int n1, n2;
                 n1 = (buf[in] >> 4) & 0xF;
@@ -274,11 +292,11 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
                 s->sample[0] += s->sol_table[n1];
                 if (s->sample[0] < 0)   s->sample[0] = 0;
                 if (s->sample[0] > 255) s->sample[0] = 255;
-                output_samples[out++] = (s->sample[0] - 128) << 8;
+                *output_samples++ = (s->sample[0] - 128) << 8;
                 s->sample[stereo] += s->sol_table[n2];
                 if (s->sample[stereo] < 0)   s->sample[stereo] = 0;
                 if (s->sample[stereo] > 255) s->sample[stereo] = 255;
-                output_samples[out++] = (s->sample[stereo] - 128) << 8;
+                *output_samples++ = (s->sample[stereo] - 128) << 8;
             }
         } else {
             while (in < buf_size) {
@@ -287,7 +305,7 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
                 if (n & 0x80) s->sample[ch] -= s->sol_table[n & 0x7F];
                 else s->sample[ch] += s->sol_table[n & 0x7F];
                 s->sample[ch] = av_clip_int16(s->sample[ch]);
-                output_samples[out++] = s->sample[ch];
+                *output_samples++ = s->sample[ch];
                 /* toggle channel */
                 ch ^= stereo;
             }
@@ -295,7 +313,7 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
         break;
     }
 
-    *data_size = out * sizeof(short);
+    *data_size = out;
     return buf_size;
 }
 



More information about the ffmpeg-cvslog mailing list