diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2011-12-25 00:53:49 +0100 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2011-12-25 00:53:49 +0100 |
commit | 0e05292a6c443bc3eec160d5b0af107bb91e074d (patch) | |
tree | cb2fbefd73eadee314ce6f53f7f3398c1b84126a | |
parent | b769df8ff248364d1e4c084121a9eb32cf8befad (diff) | |
parent | 23f228a0d0ad3049a99dbf586e4139d86b6297be (diff) | |
download | ffmpeg-0e05292a6c443bc3eec160d5b0af107bb91e074d.tar.gz |
Merge remote-tracking branch 'qatar/release/0.5' into release/0.5
* qatar/release/0.5:
Bump version number for 0.5.6 release.
svq1dec: call avcodec_set_dimensions() after dimensions changed.
vmd: fix segfaults on corruped streams
vp6: partially propagate huffman tree building errors during coeff model parsing and fix misspelling
Plug some memory leaks in the VP6 decoder
vp6: Reset the internal state when aborting key frames header parsing
vp6: Fix illegal read.
vp6: Fix illegal read.
Fix out of bound reads in the QDM2 decoder.
Check for out of bound writes in the QDM2 decoder.
qdm2: check output buffer size before decoding
Fix qdm2 decoder packet handling to match the api
Conflicts:
libavcodec/qdm2.c
Merged-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | libavcodec/qdm2.c | 30 | ||||
-rw-r--r-- | libavcodec/vmdav.c | 94 | ||||
-rw-r--r-- | libavcodec/vp56.c | 11 | ||||
-rw-r--r-- | libavcodec/vp6.c | 20 |
4 files changed, 115 insertions, 40 deletions
diff --git a/libavcodec/qdm2.c b/libavcodec/qdm2.c index f9fed4f71c..8567ea8acf 100644 --- a/libavcodec/qdm2.c +++ b/libavcodec/qdm2.c @@ -1378,6 +1378,8 @@ static void qdm2_fft_decode_tones (QDM2Context *q, int duration, GetBitContext * return; local_int_14 = (offset >> local_int_8); + if (local_int_14 >= FF_ARRAY_ELEMS(fft_level_index_table)) + return; if (q->nb_channels > 1) { channel = get_bits1(gb); @@ -1912,7 +1914,7 @@ static av_cold int qdm2_decode_close(AVCodecContext *avctx) } -static void qdm2_decode (QDM2Context *q, const uint8_t *in, int16_t *out) +static int qdm2_decode (QDM2Context *q, const uint8_t *in, int16_t *out) { int ch, i; const int frame_size = (q->frame_size * q->channels); @@ -1951,7 +1953,7 @@ static void qdm2_decode (QDM2Context *q, const uint8_t *in, int16_t *out) if (!q->has_errors && q->sub_packet_list_C[0].packet != NULL) { SAMPLES_NEEDED_2("has errors, and C list is not empty") - return; + return -1; } } @@ -1972,6 +1974,8 @@ static void qdm2_decode (QDM2Context *q, const uint8_t *in, int16_t *out) out[i] = value; } + + return 0; } @@ -1980,25 +1984,33 @@ static int qdm2_decode_frame(AVCodecContext *avctx, const uint8_t *buf, int buf_size) { QDM2Context *s = avctx->priv_data; + int16_t *out = data; + int i, out_size; if(!buf) return 0; if(buf_size < s->checksum_size) return -1; - *data_size = s->channels * s->frame_size * sizeof(int16_t); + out_size = 16 * s->channels * s->frame_size * + av_get_bits_per_sample_format(avctx->sample_fmt)/8; + if (*data_size < out_size) { + av_log(avctx, AV_LOG_ERROR, "Output buffer is too small\n"); + return AVERROR(EINVAL); + } av_log(avctx, AV_LOG_DEBUG, "decode(%d): %p[%d] -> %p[%d]\n", buf_size, buf, s->checksum_size, data, *data_size); - qdm2_decode(s, buf, data); - - // reading only when next superblock found - if (s->sub_packet == 0) { - return s->checksum_size; + for (i = 0; i < 16; i++) { + if (qdm2_decode(s, buf, out) < 0) + return -1; + out += s->channels * s->frame_size; } - return 0; + *data_size = out_size; + + return buf_size; } AVCodec qdm2_decoder = diff --git a/libavcodec/vmdav.c b/libavcodec/vmdav.c index a63afb0cdc..60dc7f958c 100644 --- a/libavcodec/vmdav.c +++ b/libavcodec/vmdav.c @@ -73,9 +73,11 @@ typedef struct VmdVideoContext { #define QUEUE_SIZE 0x1000 #define QUEUE_MASK 0x0FFF -static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_len) +static void lz_unpack(const unsigned char *src, int src_len, + unsigned char *dest, int dest_len) { const unsigned char *s; + unsigned int s_len; unsigned char *d; unsigned char *d_end; unsigned char queue[QUEUE_SIZE]; @@ -88,13 +90,16 @@ static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_le unsigned int i, j; s = src; + s_len = src_len; d = dest; d_end = d + dest_len; dataleft = AV_RL32(s); - s += 4; + s += 4; s_len -= 4; memset(queue, 0x20, QUEUE_SIZE); + if (s_len < 4) + return; if (AV_RL32(s) == 0x56781234) { - s += 4; + s += 4; s_len -= 4; qpos = 0x111; speclen = 0xF + 3; } else { @@ -102,32 +107,41 @@ static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_le speclen = 100; /* no speclen */ } - while (dataleft > 0) { - tag = *s++; + while (dataleft > 0 && s_len > 0) { + tag = *s++; s_len--; if ((tag == 0xFF) && (dataleft > 8)) { - if (d + 8 > d_end) + if (d + 8 > d_end || s_len < 8) return; for (i = 0; i < 8; i++) { queue[qpos++] = *d++ = *s++; qpos &= QUEUE_MASK; } + s_len -= 8; dataleft -= 8; } else { for (i = 0; i < 8; i++) { if (dataleft == 0) break; if (tag & 0x01) { - if (d + 1 > d_end) + if (d + 1 > d_end || s_len < 1) return; queue[qpos++] = *d++ = *s++; qpos &= QUEUE_MASK; dataleft--; + s_len--; } else { + if (s_len < 2) + return; chainofs = *s++; chainofs |= ((*s & 0xF0) << 4); chainlen = (*s++ & 0x0F) + 3; - if (chainlen == speclen) + s_len -= 2; + if (chainlen == speclen) { + if (s_len < 1) + return; chainlen = *s++ + 0xF + 3; + s_len--; + } if (d + chainlen > d_end) return; for (j = 0; j < chainlen; j++) { @@ -144,7 +158,7 @@ static void lz_unpack(const unsigned char *src, unsigned char *dest, int dest_le } static int rle_unpack(const unsigned char *src, unsigned char *dest, - int src_len, int dest_len) + int src_count, int src_size, int dest_len) { const unsigned char *ps; unsigned char *pd; @@ -153,31 +167,40 @@ static int rle_unpack(const unsigned char *src, unsigned char *dest, ps = src; pd = dest; - if (src_len & 1) + if (src_count & 1) { + if (src_size < 1) + return 0; *pd++ = *ps++; + src_size--; + } - src_len >>= 1; + src_count >>= 1; i = 0; do { + if (src_size < 1) + break; l = *ps++; + src_size--; if (l & 0x80) { l = (l & 0x7F) * 2; - if (pd + l > dest_end) + if (pd + l > dest_end || src_size < l) return ps - src; memcpy(pd, ps, l); ps += l; + src_size -= l; pd += l; } else { - if (pd + i > dest_end) + if (pd + i > dest_end || src_size < 2) return ps - src; for (i = 0; i < l; i++) { *pd++ = ps[0]; *pd++ = ps[1]; } ps += 2; + src_size -= 2; } i += l; - } while (i < src_len); + } while (i < src_count); return ps - src; } @@ -192,6 +215,7 @@ static void vmd_decode(VmdVideoContext *s) const unsigned char *p = s->buf + 16; const unsigned char *pb; + unsigned int pb_size; unsigned char meth; unsigned char *dp; /* pointer to current frame */ unsigned char *pp; /* pointer to previous frame */ @@ -228,8 +252,9 @@ static void vmd_decode(VmdVideoContext *s) /* if only a certain region will be updated, copy the entire previous * frame before the decode */ - if (frame_x || frame_y || (frame_width != s->avctx->width) || - (frame_height != s->avctx->height)) { + if (s->prev_frame.data[0] && + (frame_x || frame_y || (frame_width != s->avctx->width) || + (frame_height != s->avctx->height))) { memcpy(s->frame.data[0], s->prev_frame.data[0], s->avctx->height * s->frame.linesize[0]); @@ -247,14 +272,19 @@ static void vmd_decode(VmdVideoContext *s) } s->size -= (256 * 3 + 2); } - if (s->size >= 0) { + if (s->size > 0) { /* originally UnpackFrame in VAG's code */ pb = p; - meth = *pb++; + pb_size = s->buf + s->size - pb; + if (pb_size < 1) + return; + meth = *pb++; pb_size--; if (meth & 0x80) { - lz_unpack(pb, s->unpack_buffer, s->unpack_buffer_size); + lz_unpack(pb, pb_size, + s->unpack_buffer, s->unpack_buffer_size); meth &= 0x7F; pb = s->unpack_buffer; + pb_size = s->unpack_buffer_size; } dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x]; @@ -265,17 +295,21 @@ static void vmd_decode(VmdVideoContext *s) for (i = 0; i < frame_height; i++) { ofs = 0; do { + if (pb_size < 1) + return; len = *pb++; + pb_size--; if (len & 0x80) { len = (len & 0x7F) + 1; - if (ofs + len > frame_width) + if (ofs + len > frame_width || pb_size < len) return; memcpy(&dp[ofs], pb, len); pb += len; + pb_size -= len; ofs += len; } else { /* interframe pixel copy */ - if (ofs + len + 1 > frame_width) + if (ofs + len + 1 > frame_width || !s->prev_frame.data[0]) return; memcpy(&dp[ofs], &pp[ofs], len + 1); ofs += len + 1; @@ -293,8 +327,11 @@ static void vmd_decode(VmdVideoContext *s) case 2: for (i = 0; i < frame_height; i++) { + if (pb_size < frame_width) + return; memcpy(dp, pb, frame_width); pb += frame_width; + pb_size -= frame_width; dp += s->frame.linesize[0]; pp += s->prev_frame.linesize[0]; } @@ -304,18 +341,27 @@ static void vmd_decode(VmdVideoContext *s) for (i = 0; i < frame_height; i++) { ofs = 0; do { + if (pb_size < 1) + return; len = *pb++; + pb_size--; if (len & 0x80) { len = (len & 0x7F) + 1; + if (pb_size < 1) + return; if (*pb++ == 0xFF) - len = rle_unpack(pb, &dp[ofs], len, frame_width - ofs); - else + len = rle_unpack(pb, &dp[ofs], len, pb_size, frame_width - ofs); + else { + if (pb_size < len) + return; memcpy(&dp[ofs], pb, len); + } pb += len; + pb_size -= 1 + len; ofs += len; } else { /* interframe pixel copy */ - if (ofs + len + 1 > frame_width) + if (ofs + len + 1 > frame_width || !s->prev_frame.data[0]) return; memcpy(&dp[ofs], &pp[ofs], len + 1); ofs += len + 1; diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c index 65ddb8b421..1ca8a402f0 100644 --- a/libavcodec/vp56.c +++ b/libavcodec/vp56.c @@ -695,6 +695,7 @@ av_cold void vp56_init(AVCodecContext *avctx, int flip, int has_alpha) av_cold int vp56_free(AVCodecContext *avctx) { VP56Context *s = avctx->priv_data; + int pt; av_free(s->above_blocks); av_free(s->macroblocks); @@ -705,5 +706,15 @@ av_cold int vp56_free(AVCodecContext *avctx) avctx->release_buffer(avctx, s->framep[VP56_FRAME_GOLDEN2]); if (s->framep[VP56_FRAME_PREVIOUS]->data[0]) avctx->release_buffer(avctx, s->framep[VP56_FRAME_PREVIOUS]); + + for (pt=0; pt < 2; pt++) { + int ct, cg; + free_vlc(&s->dccv_vlc[pt]); + free_vlc(&s->runv_vlc[pt]); + for (ct=0; ct<3; ct++) + for (cg = 0; cg < 6; cg++) + free_vlc(&s->ract_vlc[pt][ct][cg]); + } + return 0; } diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c index b89ff498da..d9e9711cca 100644 --- a/libavcodec/vp6.c +++ b/libavcodec/vp6.c @@ -136,8 +136,11 @@ static int vp6_parse_header(VP56Context *s, const uint8_t *buf, int buf_size, if (coeff_offset) { buf += coeff_offset; buf_size -= coeff_offset; - if (buf_size < 0) + if (buf_size < 0) { + if (s->framep[VP56_FRAME_CURRENT]->key_frame) + avcodec_set_dimensions(s->avctx, 0, 0); return 0; + } if (s->use_huffman) { s->parse_coeff = vp6_parse_coeff_huffman; init_get_bits(&s->gb, buf, buf_size<<3); @@ -212,8 +215,8 @@ static int vp6_huff_cmp(const void *va, const void *vb) return (a->count - b->count)*16 + (b->sym - a->sym); } -static void vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], - const uint8_t *map, unsigned size, VLC *vlc) +static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], + const uint8_t *map, unsigned size, VLC *vlc) { Node nodes[2*size], *tmp = &nodes[size]; int a, b, i; @@ -227,9 +230,10 @@ static void vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[], nodes[map[2*i+1]].count = b + !b; } - /* then build the huffman tree accodring to probabilities */ - ff_huff_build_tree(s->avctx, vlc, size, nodes, vp6_huff_cmp, - FF_HUFFMAN_FLAG_HNODE_FIRST); + free_vlc(vlc); + /* then build the huffman tree according to probabilities */ + return ff_huff_build_tree(s->avctx, vlc, size, nodes, vp6_huff_cmp, + FF_HUFFMAN_FLAG_HNODE_FIRST); } static void vp6_parse_coeff_models(VP56Context *s) @@ -365,7 +369,7 @@ static void vp6_parse_coeff_huffman(VP56Context *s) if (b > 3) pt = 1; vlc_coeff = &s->dccv_vlc[pt]; - for (coeff_idx=0; coeff_idx<64; ) { + for (coeff_idx = 0;;) { int run = 1; if (coeff_idx<2 && s->nb_null[coeff_idx][pt]) { s->nb_null[coeff_idx][pt]--; @@ -400,6 +404,8 @@ static void vp6_parse_coeff_huffman(VP56Context *s) } } coeff_idx+=run; + if (coeff_idx >= 64) + break; cg = FFMIN(vp6_coeff_groups[coeff_idx], 3); vlc_coeff = &s->ract_vlc[pt][ct][cg]; } |