X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fzmbv.c;h=e3ccc16d0bca484973969ec48fa3e1958d8c269a;hb=ef6a9e5e311f09fa8032974fa4d0c1e166a959bb;hp=b01ce1bcf6e8ecef1acd61a132445b4600c9d0aa;hpb=2d62e06ff6a9f3dbd78136c1dc4a315a727c6f00;p=ffmpeg diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c index b01ce1bcf6e..e3ccc16d0bc 100644 --- a/libavcodec/zmbv.c +++ b/libavcodec/zmbv.c @@ -69,8 +69,8 @@ typedef struct ZmbvContext { int stride; int bw, bh, bx, by; int decomp_len; + int got_keyframe; z_stream zstream; - int (*decode_intra)(struct ZmbvContext *c); int (*decode_xor)(struct ZmbvContext *c); } ZmbvContext; @@ -121,6 +121,8 @@ static int zmbv_decode_xor_8(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, sizeof(*out) * bw2); } else { for (i = 0; i < bw2; i++) { if (mx + i < 0 || mx + i >= c->width) @@ -193,6 +195,8 @@ static int zmbv_decode_xor_16(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2 * 2); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, sizeof(*out) * bw2); } else { for (i = 0; i < bw2; i++) { if (mx + i < 0 || mx + i >= c->width) @@ -270,6 +274,8 @@ static int zmbv_decode_xor_24(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2 * 3); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, 3 * bw2); } else { for (i = 0; i < bw2; i++){ if (mx + i < 0 || mx + i >= c->width) { @@ -303,7 +309,7 @@ static int zmbv_decode_xor_24(ZmbvContext *c) prev += stride * c->bh; } if (src - c->decomp_buf != c->decomp_len) - av_log(c->avctx, AV_LOG_ERROR, "Used %i of %i bytes\n", + av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", src-c->decomp_buf, c->decomp_len); return 0; } @@ -351,6 +357,8 @@ static int zmbv_decode_xor_32(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2 * 4); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, sizeof(*out) * bw2); } else { for (i = 0; i < bw2; i++){ if (mx + i < 0 || mx + i >= c->width) @@ -409,6 +417,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac int zret = Z_OK; // Zlib return code int len = buf_size; int hi_ver, lo_ver, ret; + int expected_size; /* parse header */ if (len < 1) @@ -416,8 +425,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac c->flags = buf[0]; buf++; len--; if (c->flags & ZMBV_KEYFRAME) { - void *decode_intra = NULL; - c->decode_intra= NULL; + c->got_keyframe = 0; if (len < 6) return AVERROR_INVALIDDATA; @@ -427,7 +435,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac c->fmt = buf[3]; c->bw = buf[4]; c->bh = buf[5]; - c->decode_intra = NULL; c->decode_xor = NULL; buf += 6; @@ -451,7 +458,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac switch (c->fmt) { case ZMBV_FMT_8BPP: c->bpp = 8; - decode_intra = zmbv_decode_intra; c->decode_xor = zmbv_decode_xor_8; avctx->pix_fmt = AV_PIX_FMT_PAL8; c->stride = c->width; @@ -459,7 +465,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac case ZMBV_FMT_15BPP: case ZMBV_FMT_16BPP: c->bpp = 16; - decode_intra = zmbv_decode_intra; c->decode_xor = zmbv_decode_xor_16; if (c->fmt == ZMBV_FMT_15BPP) avctx->pix_fmt = AV_PIX_FMT_RGB555LE; @@ -470,15 +475,13 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac #ifdef ZMBV_ENABLE_24BPP case ZMBV_FMT_24BPP: c->bpp = 24; - decode_intra = zmbv_decode_intra; c->decode_xor = zmbv_decode_xor_24; - avctx->pix_fmt = AV_PIX_FMT_RGB24; + avctx->pix_fmt = AV_PIX_FMT_BGR24; c->stride = c->width * 3; break; #endif //ZMBV_ENABLE_24BPP case ZMBV_FMT_32BPP: c->bpp = 32; - decode_intra = zmbv_decode_intra; c->decode_xor = zmbv_decode_xor_32; avctx->pix_fmt = AV_PIX_FMT_BGR0; c->stride = c->width * 4; @@ -508,26 +511,32 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac } memset(c->cur, 0, avctx->width * avctx->height * (c->bpp / 8)); memset(c->prev, 0, avctx->width * avctx->height * (c->bpp / 8)); - c->decode_intra= decode_intra; + c->got_keyframe = 1; + } + if (c->flags & ZMBV_KEYFRAME) { + expected_size = avctx->width * avctx->height * (c->bpp / 8); + } else { + expected_size = (c->bx * c->by * 2 + 3) & ~3; } + if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && + (c->flags & (ZMBV_DELTAPAL | ZMBV_KEYFRAME))) + expected_size += 768; - if (!c->decode_intra) { + if (!c->got_keyframe) { av_log(avctx, AV_LOG_ERROR, "Error! Got no format or no keyframe!\n"); return AVERROR_INVALIDDATA; } - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - if (c->comp == 0) { // uncompressed data if (c->decomp_size < len) { av_log(avctx, AV_LOG_ERROR, "Buffer too small\n"); return AVERROR_INVALIDDATA; } memcpy(c->decomp_buf, buf, len); + c->decomp_len = len; } else { // ZLIB-compressed data c->zstream.total_in = c->zstream.total_out = 0; - c->zstream.next_in = (uint8_t*)buf; + c->zstream.next_in = buf; c->zstream.avail_in = len; c->zstream.next_out = c->decomp_buf; c->zstream.avail_out = c->decomp_size; @@ -538,10 +547,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac } c->decomp_len = c->zstream.total_out; } + if (expected_size > c->decomp_len || + (c->flags & ZMBV_KEYFRAME) && expected_size < c->decomp_len) { + av_log(avctx, AV_LOG_ERROR, "decompressed size %d is incorrect, expected %d\n", c->decomp_len, expected_size); + return AVERROR_INVALIDDATA; + } + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + if (c->flags & ZMBV_KEYFRAME) { frame->key_frame = 1; frame->pict_type = AV_PICTURE_TYPE_I; - c->decode_intra(c); + zmbv_decode_intra(c); } else { frame->key_frame = 0; frame->pict_type = AV_PICTURE_TYPE_P; @@ -647,4 +664,5 @@ AVCodec ff_zmbv_decoder = { .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, };