mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-02-04 06:08:26 +02:00
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>
This commit is contained in:
commit
0e05292a6c
@ -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 =
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user