summaryrefslogtreecommitdiff
path: root/libavcodec/dpcm.c
diff options
context:
space:
mode:
authorJustin Ruggles <justin.ruggles@gmail.com>2011-09-11 11:51:08 -0400
committerJustin Ruggles <justin.ruggles@gmail.com>2011-09-30 18:15:52 -0400
commit76db17dc7d4f19f9a03bdd6de79c2ea37b76888f (patch)
treec1f32f9d7bb3dd40ac3459143ac610d8bb21a5a3 /libavcodec/dpcm.c
parent3db8db406ff213bf177cc23c44f6cbc8778b1bea (diff)
dpcm: calculate and check actual output data size prior to decoding.
Diffstat (limited to 'libavcodec/dpcm.c')
-rw-r--r--libavcodec/dpcm.c50
1 files changed, 34 insertions, 16 deletions
diff --git a/libavcodec/dpcm.c b/libavcodec/dpcm.c
index 185d04e0b2..3f3b422d96 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;
}