+ 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;