X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Findeo3.c;h=05f79258b34531a8a6468a8145acf5eb2c6e2244;hb=e380b9182be0908ec60dd6e135ca6f498371b46f;hp=3c98a610e61a84b03dd1d6a827f9383a7eb39258;hpb=950c0373fd65501aeca4bab07be84886b885164d;p=ffmpeg diff --git a/libavcodec/indeo3.c b/libavcodec/indeo3.c index 3c98a610e61..05f79258b34 100644 --- a/libavcodec/indeo3.c +++ b/libavcodec/indeo3.c @@ -22,7 +22,6 @@ #include #include #include -#include #include "avcodec.h" #include "dsputil.h" @@ -35,7 +34,6 @@ typedef struct uint8_t *Ybuf; uint8_t *Ubuf; uint8_t *Vbuf; - unsigned int the_buf_size; unsigned short y_w, y_h; unsigned short uv_w, uv_h; } YUVBufs; @@ -96,34 +94,25 @@ static av_cold int build_modpred(Indeo3DecodeContext *s) return 0; } -static void iv_Decode_Chunk(Indeo3DecodeContext *s, uint8_t *cur, - uint8_t *ref, int width, int height, const uint8_t *buf1, - long fflags2, const uint8_t *hdr, - const uint8_t *buf2, int min_width_160); - static av_cold int iv_alloc_frames(Indeo3DecodeContext *s) { - int luma_width, luma_height, luma_pixels, chroma_width, chroma_height, - chroma_pixels, i; - unsigned int bufsize; - - luma_width = (s->width + 3) & (~3); - luma_height = (s->height + 3) & (~3); - chroma_width = ((luma_width >> 2) + 3) & (~3); - chroma_height = ((luma_height>> 2) + 3) & (~3); - luma_pixels = luma_width * luma_height; - chroma_pixels = chroma_width * chroma_height; - - bufsize = luma_pixels * 2 + luma_width * 3 + - (chroma_pixels + chroma_width) * 4; - + int luma_width = (s->width + 3) & ~3, + luma_height = (s->height + 3) & ~3, + chroma_width = ((luma_width >> 2) + 3) & ~3, + chroma_height = ((luma_height >> 2) + 3) & ~3, + luma_pixels = luma_width * luma_height, + chroma_pixels = chroma_width * chroma_height, + i; + unsigned int bufsize = luma_pixels * 2 + luma_width * 3 + + (chroma_pixels + chroma_width) * 4; + + av_freep(&s->buf); if(!(s->buf = av_malloc(bufsize))) return AVERROR(ENOMEM); s->iv_frame[0].y_w = s->iv_frame[1].y_w = luma_width; s->iv_frame[0].y_h = s->iv_frame[1].y_h = luma_height; s->iv_frame[0].uv_w = s->iv_frame[1].uv_w = chroma_width; s->iv_frame[0].uv_h = s->iv_frame[1].uv_h = chroma_height; - s->iv_frame[0].the_buf_size = bufsize; s->iv_frame[0].Ybuf = s->buf + luma_width; i = luma_pixels + luma_width * 2; @@ -153,79 +142,12 @@ static av_cold int iv_alloc_frames(Indeo3DecodeContext *s) static av_cold void iv_free_func(Indeo3DecodeContext *s) { - av_free(s->buf); - av_free(s->ModPred); - av_free(s->corrector_type); + av_freep(&s->buf); + av_freep(&s->ModPred); + av_freep(&s->corrector_type); } -static unsigned long iv_decode_frame(Indeo3DecodeContext *s, - const uint8_t *buf, int buf_size) -{ - unsigned int hdr_width, hdr_height, - chroma_width, chroma_height; - unsigned long fflags1, fflags2, fflags3, offs1, offs2, offs3, offs; - const uint8_t *hdr_pos, *buf_pos; - - buf_pos = buf; - buf_pos += 18; - - fflags1 = bytestream_get_le16(&buf_pos); - fflags3 = bytestream_get_le32(&buf_pos); - fflags2 = *buf_pos++; - buf_pos += 3; - hdr_height = bytestream_get_le16(&buf_pos); - hdr_width = bytestream_get_le16(&buf_pos); - - if(avcodec_check_dimensions(NULL, hdr_width, hdr_height)) - return -1; - - chroma_height = ((hdr_height >> 2) + 3) & 0x7ffc; - chroma_width = ((hdr_width >> 2) + 3) & 0x7ffc; - offs1 = bytestream_get_le32(&buf_pos); - offs2 = bytestream_get_le32(&buf_pos); - offs3 = bytestream_get_le32(&buf_pos); - buf_pos += 4; - hdr_pos = buf_pos; - if(fflags3 == 0x80) return 4; - - if(fflags1 & 0x200) { - s->cur_frame = s->iv_frame + 1; - s->ref_frame = s->iv_frame; - } else { - s->cur_frame = s->iv_frame; - s->ref_frame = s->iv_frame + 1; - } - - buf_pos = buf + 16 + offs1; - offs = bytestream_get_le32(&buf_pos); - - iv_Decode_Chunk(s, s->cur_frame->Ybuf, s->ref_frame->Ybuf, hdr_width, - hdr_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos, - FFMIN(hdr_width, 160)); - - if (!(s->avctx->flags & CODEC_FLAG_GRAY)) - { - - buf_pos = buf + 16 + offs2; - offs = bytestream_get_le32(&buf_pos); - - iv_Decode_Chunk(s, s->cur_frame->Vbuf, s->ref_frame->Vbuf, chroma_width, - chroma_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos, - FFMIN(chroma_width, 40)); - - buf_pos = buf + 16 + offs3; - offs = bytestream_get_le32(&buf_pos); - - iv_Decode_Chunk(s, s->cur_frame->Ubuf, s->ref_frame->Ubuf, chroma_width, - chroma_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos, - FFMIN(chroma_width, 40)); - - } - - return 8; -} - -typedef struct { +struct ustr { long xpos; long ypos; long width; @@ -233,7 +155,7 @@ typedef struct { long split_flag; long split_direction; long usl7; -} ustr_t; +}; #define LV1_CHECK(buf1,rle_v3,lv1,lp2) \ @@ -280,7 +202,7 @@ typedef struct { static void iv_Decode_Chunk(Indeo3DecodeContext *s, uint8_t *cur, uint8_t *ref, int width, int height, - const uint8_t *buf1, long fflags2, const uint8_t *hdr, + const uint8_t *buf1, long cb_offset, const uint8_t *hdr, const uint8_t *buf2, int min_width_160) { uint8_t bit_buf; @@ -291,7 +213,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, uint32_t *cur_lp, *ref_lp; const uint32_t *correction_lp[2], *correctionloworder_lp[2], *correctionhighorder_lp[2]; uint8_t *correction_type_sp[2]; - ustr_t strip_tbl[20], *strip; + struct ustr strip_tbl[20], *strip; int i, j, k, lp1, lp2, flag1, cmd, blks_width, blks_height, region_160_width, rle_v1, rle_v2, rle_v3; unsigned short res; @@ -330,14 +252,22 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, if(cmd == 0) { strip++; - memcpy(strip, strip-1, sizeof(ustr_t)); + if(strip >= strip_tbl + FF_ARRAY_ELEMS(strip_tbl)) { + av_log(s->avctx, AV_LOG_WARNING, "out of range strip\n"); + break; + } + memcpy(strip, strip-1, sizeof(*strip)); strip->split_flag = 1; strip->split_direction = 0; strip->height = (strip->height > 8 ? ((strip->height+8)>>4)<<3 : 4); continue; } else if(cmd == 1) { strip++; - memcpy(strip, strip-1, sizeof(ustr_t)); + if(strip >= strip_tbl + FF_ARRAY_ELEMS(strip_tbl)) { + av_log(s->avctx, AV_LOG_WARNING, "out of range strip\n"); + break; + } + memcpy(strip, strip-1, sizeof(*strip)); strip->split_flag = 1; strip->split_direction = 1; strip->width = (strip->width > 8 ? ((strip->width+8)>>4)<<3 : 4); @@ -392,7 +322,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, k = *buf1 >> 4; j = *buf1 & 0x0f; buf1++; - lv = j + fflags2; + lv = j + cb_offset; if((lv - 8) <= 7 && (k == 0 || k == 3 || k == 10)) { cp2 = s->ModPred + ((lv - 8) << 7); @@ -404,10 +334,10 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, } if(k == 1 || k == 4) { - lv = (hdr[j] & 0xf) + fflags2; + lv = (hdr[j] & 0xf) + cb_offset; correction_type_sp[0] = s->corrector_type + (lv << 8); correction_lp[0] = correction + (lv << 8); - lv = (hdr[j] >> 4) + fflags2; + lv = (hdr[j] >> 4) + cb_offset; correction_lp[1] = correction + (lv << 8); correction_type_sp[1] = s->corrector_type + (lv << 8); } else { @@ -458,13 +388,13 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, if(lp2 == 0) { RLE_V3_CHECK(buf1,rle_v1,rle_v2,rle_v3) - if(rle_v1 == 1 || ref_vectors != NULL) { - for(i = 0, j = 0; i < 4; i++, j += width_tbl[1]) - cur_lp[j] = ref_lp[j]; - } + if(rle_v1 == 1 || ref_vectors != NULL) { + for(i = 0, j = 0; i < 4; i++, j += width_tbl[1]) + cur_lp[j] = ref_lp[j]; + } RLE_V2_CHECK(buf1,rle_v2, rle_v3,lp2) - break; + break; } else { rle_v1 = 1; rle_v2 = *buf1 - 1; @@ -501,7 +431,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, cur_lp[j] = lv; LV1_CHECK(buf1,rle_v3,lv1,lp2) - break; + break; default: return; } @@ -646,7 +576,7 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, lv1 = ref_lp[0]; lv2 = ref_lp[1]; if(lp2 == 0 && flag1 != 0) { -#ifdef WORDS_BIGENDIAN +#if HAVE_BIGENDIAN lv1 = lv1 & 0xFF00FF00; lv1 = (lv1 >> 8) | lv1; lv2 = lv2 & 0xFF00FF00; @@ -1007,9 +937,6 @@ static void iv_Decode_Chunk(Indeo3DecodeContext *s, } } - if(strip < strip_tbl) - return; - for( ; strip >= strip_tbl; strip--) { if(strip->split_flag != 0) { strip->split_flag = 0; @@ -1048,15 +975,115 @@ static av_cold int indeo3_decode_init(AVCodecContext *avctx) return ret; } +static int iv_decode_frame(AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + Indeo3DecodeContext *s = avctx->priv_data; + unsigned int image_width, image_height, + chroma_width, chroma_height; + unsigned long flags, cb_offset, data_size, + y_offset, v_offset, u_offset, mc_vector_count; + const uint8_t *hdr_pos, *buf_pos; + + buf_pos = buf; + buf_pos += 18; /* skip OS header (16 bytes) and version number */ + + flags = bytestream_get_le16(&buf_pos); + data_size = bytestream_get_le32(&buf_pos); + cb_offset = *buf_pos++; + buf_pos += 3; /* skip reserved byte and checksum */ + image_height = bytestream_get_le16(&buf_pos); + image_width = bytestream_get_le16(&buf_pos); + + if(avcodec_check_dimensions(avctx, image_width, image_height)) + return -1; + if (image_width != avctx->width || image_height != avctx->height) { + int ret; + avcodec_set_dimensions(avctx, image_width, image_height); + s->width = avctx->width; + s->height = avctx->height; + ret = iv_alloc_frames(s); + if (ret < 0) { + s->width = s->height = 0; + return ret; + } + } + + chroma_height = ((image_height >> 2) + 3) & 0x7ffc; + chroma_width = ((image_width >> 2) + 3) & 0x7ffc; + y_offset = bytestream_get_le32(&buf_pos); + v_offset = bytestream_get_le32(&buf_pos); + u_offset = bytestream_get_le32(&buf_pos); + buf_pos += 4; /* reserved */ + hdr_pos = buf_pos; + if(data_size == 0x80) return 4; + + if(FFMAX3(y_offset, v_offset, u_offset) >= buf_size-16) { + av_log(s->avctx, AV_LOG_ERROR, "y/u/v offset outside buffer\n"); + return -1; + } + + if(flags & 0x200) { + s->cur_frame = s->iv_frame + 1; + s->ref_frame = s->iv_frame; + } else { + s->cur_frame = s->iv_frame; + s->ref_frame = s->iv_frame + 1; + } + + buf_pos = buf + 16 + y_offset; + mc_vector_count = bytestream_get_le32(&buf_pos); + if(2LL*mc_vector_count >= buf_size-16-y_offset) { + av_log(s->avctx, AV_LOG_ERROR, "mc_vector_count too large\n"); + return -1; + } + + iv_Decode_Chunk(s, s->cur_frame->Ybuf, s->ref_frame->Ybuf, image_width, + image_height, buf_pos + mc_vector_count * 2, cb_offset, hdr_pos, buf_pos, + FFMIN(image_width, 160)); + + if (!(s->avctx->flags & CODEC_FLAG_GRAY)) + { + + buf_pos = buf + 16 + v_offset; + mc_vector_count = bytestream_get_le32(&buf_pos); + if(2LL*mc_vector_count >= buf_size-16-v_offset) { + av_log(s->avctx, AV_LOG_ERROR, "mc_vector_count too large\n"); + return -1; + } + + iv_Decode_Chunk(s, s->cur_frame->Vbuf, s->ref_frame->Vbuf, chroma_width, + chroma_height, buf_pos + mc_vector_count * 2, cb_offset, hdr_pos, buf_pos, + FFMIN(chroma_width, 40)); + + buf_pos = buf + 16 + u_offset; + mc_vector_count = bytestream_get_le32(&buf_pos); + if(2LL*mc_vector_count >= buf_size-16-u_offset) { + av_log(s->avctx, AV_LOG_ERROR, "mc_vector_count too large\n"); + return -1; + } + + iv_Decode_Chunk(s, s->cur_frame->Ubuf, s->ref_frame->Ubuf, chroma_width, + chroma_height, buf_pos + mc_vector_count * 2, cb_offset, hdr_pos, buf_pos, + FFMIN(chroma_width, 40)); + + } + + return 8; +} + static int indeo3_decode_frame(AVCodecContext *avctx, void *data, int *data_size, - const uint8_t *buf, int buf_size) + AVPacket *avpkt) { + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; Indeo3DecodeContext *s=avctx->priv_data; uint8_t *src, *dest; int y; - iv_decode_frame(s, buf, buf_size); + if (iv_decode_frame(avctx, buf, buf_size) < 0) + return -1; if(s->frame.data[0]) avctx->release_buffer(avctx, &s->frame); @@ -1118,7 +1145,7 @@ AVCodec indeo3_decoder = { NULL, indeo3_decode_end, indeo3_decode_frame, - 0, + CODEC_CAP_DR1, NULL, .long_name = NULL_IF_CONFIG_SMALL("Intel Indeo 3"), };