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

This commit is contained in:
Justin Ruggles 2011-09-11 11:51:08 -04:00
parent 3db8db406f
commit 76db17dc7d

View File

@ -178,9 +178,30 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
if (!buf_size) if (!buf_size)
return 0; return 0;
// almost every DPCM variant expands one byte of data into two /* calculate output size */
if(*data_size/2 < buf_size) switch(avctx->codec->id) {
return -1; 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) { switch(avctx->codec->id) {
@ -195,10 +216,10 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
SE_16BIT(predictor[1]); SE_16BIT(predictor[1]);
/* decode the samples */ /* 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] += s->roq_square_array[buf[in]];
predictor[ch] = av_clip_int16(predictor[ch]); predictor[ch] = av_clip_int16(predictor[ch]);
output_samples[out] = predictor[ch]; *output_samples++ = predictor[ch];
/* toggle channel */ /* toggle channel */
ch ^= stereo; ch ^= stereo;
@ -210,23 +231,22 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
predictor[0] = AV_RL16(&buf[in]); predictor[0] = AV_RL16(&buf[in]);
in += 2; in += 2;
SE_16BIT(predictor[0]) SE_16BIT(predictor[0])
output_samples[out++] = predictor[0]; *output_samples++ = predictor[0];
if (stereo) { if (stereo) {
predictor[1] = AV_RL16(&buf[in]); predictor[1] = AV_RL16(&buf[in]);
in += 2; in += 2;
SE_16BIT(predictor[1]) SE_16BIT(predictor[1])
output_samples[out++] = predictor[1]; *output_samples++ = predictor[1];
} }
while (in < buf_size) { while (in < buf_size) {
predictor[ch] += interplay_delta_table[buf[in++]]; predictor[ch] += interplay_delta_table[buf[in++]];
predictor[ch] = av_clip_int16(predictor[ch]); predictor[ch] = av_clip_int16(predictor[ch]);
output_samples[out++] = predictor[ch]; *output_samples++ = predictor[ch];
/* toggle channel */ /* toggle channel */
ch ^= stereo; ch ^= stereo;
} }
break; break;
case CODEC_ID_XAN_DPCM: case CODEC_ID_XAN_DPCM:
@ -256,7 +276,7 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
predictor[ch] += diff; predictor[ch] += diff;
predictor[ch] = av_clip_int16(predictor[ch]); predictor[ch] = av_clip_int16(predictor[ch]);
output_samples[out++] = predictor[ch]; *output_samples++ = predictor[ch];
/* toggle channel */ /* toggle channel */
ch ^= stereo; ch ^= stereo;
@ -265,8 +285,6 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
case CODEC_ID_SOL_DPCM: case CODEC_ID_SOL_DPCM:
in = 0; in = 0;
if (avctx->codec_tag != 3) { if (avctx->codec_tag != 3) {
if(*data_size/4 < buf_size)
return -1;
while (in < buf_size) { while (in < buf_size) {
int n1, n2; int n1, n2;
n1 = (buf[in] >> 4) & 0xF; n1 = (buf[in] >> 4) & 0xF;
@ -274,11 +292,11 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
s->sample[0] += s->sol_table[n1]; s->sample[0] += s->sol_table[n1];
if (s->sample[0] < 0) s->sample[0] = 0; if (s->sample[0] < 0) s->sample[0] = 0;
if (s->sample[0] > 255) s->sample[0] = 255; 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]; s->sample[stereo] += s->sol_table[n2];
if (s->sample[stereo] < 0) s->sample[stereo] = 0; if (s->sample[stereo] < 0) s->sample[stereo] = 0;
if (s->sample[stereo] > 255) s->sample[stereo] = 255; 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 { } else {
while (in < buf_size) { 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]; if (n & 0x80) s->sample[ch] -= s->sol_table[n & 0x7F];
else 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]); s->sample[ch] = av_clip_int16(s->sample[ch]);
output_samples[out++] = s->sample[ch]; *output_samples++ = s->sample[ch];
/* toggle channel */ /* toggle channel */
ch ^= stereo; ch ^= stereo;
} }
@ -295,7 +313,7 @@ static int dpcm_decode_frame(AVCodecContext *avctx,
break; break;
} }
*data_size = out * sizeof(short); *data_size = out;
return buf_size; return buf_size;
} }