]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/indeo3.c
Only use .size in ARM assembly when targeting ELF
[ffmpeg] / libavcodec / indeo3.c
index 9594628666f97a0249a1078ec067269c688bba27..05f79258b34531a8a6468a8145acf5eb2c6e2244 100644 (file)
@@ -22,7 +22,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
 
 #include "avcodec.h"
 #include "dsputil.h"
@@ -107,6 +106,7 @@ static av_cold int iv_alloc_frames(Indeo3DecodeContext *s)
     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;
@@ -142,12 +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);
 }
 
-typedef struct {
+struct ustr {
     long xpos;
     long ypos;
     long width;
@@ -155,7 +155,7 @@ typedef struct {
     long split_flag;
     long split_direction;
     long usl7;
-} ustr_t;
+};
 
 
 #define LV1_CHECK(buf1,rle_v3,lv1,lp2)  \
@@ -202,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;
@@ -213,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;
@@ -252,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);
@@ -314,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);
@@ -326,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 {
@@ -380,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;
@@ -423,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;
                             }
@@ -568,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;
@@ -929,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;
@@ -970,37 +975,55 @@ static av_cold int indeo3_decode_init(AVCodecContext *avctx)
     return ret;
 }
 
-static unsigned long iv_decode_frame(Indeo3DecodeContext *s,
-                                     const uint8_t *buf, int buf_size)
+static int iv_decode_frame(AVCodecContext *avctx,
+                           const uint8_t *buf, int buf_size)
 {
-    unsigned int hdr_width, hdr_height,
+    Indeo3DecodeContext *s = avctx->priv_data;
+    unsigned int image_width, image_height,
                  chroma_width, chroma_height;
-    unsigned long fflags1, fflags2, fflags3, offs1, offs2, offs3, offs;
+    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;
+    buf_pos += 18; /* skip OS header (16 bytes) and version number */
 
-    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);
+    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(NULL, hdr_width, hdr_height))
+    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 = ((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;
+    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(fflags3 == 0x80) return 4;
+    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(fflags1 & 0x200) {
+    if(flags & 0x200) {
         s->cur_frame = s->iv_frame + 1;
         s->ref_frame = s->iv_frame;
     } else {
@@ -1008,28 +1031,40 @@ static unsigned long iv_decode_frame(Indeo3DecodeContext *s,
         s->ref_frame = s->iv_frame + 1;
     }
 
-    buf_pos = buf + 16 + offs1;
-    offs = bytestream_get_le32(&buf_pos);
+    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, hdr_width,
-                    hdr_height, buf_pos + offs * 2, fflags2, hdr_pos, buf_pos,
-                    FFMIN(hdr_width, 160));
+    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 + offs2;
-        offs = bytestream_get_le32(&buf_pos);
+        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 + offs * 2, fflags2, hdr_pos, buf_pos,
+                chroma_height, buf_pos + mc_vector_count * 2, cb_offset, hdr_pos, buf_pos,
                 FFMIN(chroma_width, 40));
 
-        buf_pos = buf + 16 + offs3;
-        offs = bytestream_get_le32(&buf_pos);
+        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 + offs * 2, fflags2, hdr_pos, buf_pos,
+                chroma_height, buf_pos + mc_vector_count * 2, cb_offset, hdr_pos, buf_pos,
                 FFMIN(chroma_width, 40));
 
     }
@@ -1039,13 +1074,16 @@ static unsigned long iv_decode_frame(Indeo3DecodeContext *s,
 
 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);
@@ -1107,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"),
 };