[FFmpeg-devel] [PATCH 2/4] targa: support 2-way and 4-way interleaved files

Bobby Bingham uhmmmm at gmail.com
Mon Oct 8 07:41:19 CEST 2012


Fixes ticket #701

Signed-off-by: Bobby Bingham <uhmmmm at gmail.com>
---
 libavcodec/targa.c | 76 +++++++++++++++++++++++++++++++++++-------------------
 libavcodec/targa.h |  4 ++-
 2 files changed, 53 insertions(+), 27 deletions(-)

diff --git a/libavcodec/targa.c b/libavcodec/targa.c
index e3d917e..68f6577 100644
--- a/libavcodec/targa.c
+++ b/libavcodec/targa.c
@@ -33,17 +33,35 @@ typedef struct TargaContext {
     int compression_type;
 } TargaContext;
 
+static uint8_t *advance_line(uint8_t *start, uint8_t *line,
+                             int stride, int *y, int h, int interleave)
+{
+    *y += interleave;
+
+    if (*y < h) {
+        return line + interleave * stride;
+    } else {
+        *y = (*y + 1) & (interleave - 1);
+        if (*y) {
+            return start + *y * stride;
+        } else {
+            return NULL;
+        }
+    }
+}
+
 static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
-                            uint8_t *dst, int w, int h, int stride, int bpp)
+                            uint8_t *dst, int w, int h, int stride,
+                            int bpp, int interleave)
 {
     int x, y;
     int depth = (bpp + 1) >> 3;
     int type, count;
-    int diff;
+    uint8_t *line = dst;
+    uint8_t *cur  = line;
 
-    diff = stride - w * depth;
-    x = y = 0;
-    while (y < h) {
+    x = y = count = 0;
+    while (cur) {
         if (bytestream2_get_bytes_left(&s->gb) <= 0) {
             av_log(avctx, AV_LOG_ERROR,
                    "Ran ouf of data before end-of-image\n");
@@ -52,25 +70,18 @@ static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
         type  = bytestream2_get_byteu(&s->gb);
         count = (type & 0x7F) + 1;
         type &= 0x80;
-        if(x + count > (h - y) * w){
-            av_log(avctx, AV_LOG_ERROR,
-                   "Packet went out of bounds: position (%i,%i) size %i\n",
-                   x, y, count);
-            return AVERROR_INVALIDDATA;
-        }
         if (!type) {
             do {
                 int n  = FFMIN(count, w - x);
-                bytestream2_get_buffer(&s->gb, dst, n * depth);
+                bytestream2_get_buffer(&s->gb, cur, n * depth);
                 count -= n;
-                dst   += n * depth;
+                cur   += n * depth;
                 x     += n;
                 if (x == w) {
                     x    = 0;
-                    y++;
-                    dst += diff;
+                    cur = line = advance_line(dst, line, stride, &y, h, interleave);
                 }
-            } while (count > 0);
+            } while (cur && count > 0);
         } else {
             uint8_t tmp[4];
             bytestream2_get_buffer(&s->gb, tmp, depth);
@@ -79,17 +90,22 @@ static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
                 count -= n;
                 x     += n;
                 do {
-                    memcpy(dst, tmp, depth);
-                    dst += depth;
+                    memcpy(cur, tmp, depth);
+                    cur += depth;
                 } while (--n);
                 if (x == w) {
                     x    = 0;
-                    y++;
-                    dst += diff;
+                    cur = line = advance_line(dst, line, stride, &y, h, interleave);
                 }
-            } while (count > 0);
+            } while (cur && count > 0);
         }
     }
+
+    if(count) {
+        av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     return 0;
 }
 
@@ -104,6 +120,7 @@ static int decode_frame(AVCodecContext *avctx,
     int stride;
     int idlen, pal, compr, y, w, h, bpp, flags;
     int first_clr, colors, csize;
+    int interleave;
 
     bytestream2_init(&s->gb, avpkt->data, avpkt->size);
 
@@ -174,6 +191,9 @@ static int decode_frame(AVCodecContext *avctx,
         stride = -p->linesize[0];
     }
 
+    interleave = flags & TGA_INTERLEAVE2 ? 2 :
+                 flags & TGA_INTERLEAVE4 ? 4 : 1;
+
     if(colors){
         int pal_size, pal_sample_size;
         if((colors + first_clr) > 256){
@@ -226,20 +246,24 @@ static int decode_frame(AVCodecContext *avctx,
         memset(p->data[0], 0, p->linesize[0] * h);
     } else {
         if(compr & TGA_RLE){
-            int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp);
+            int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave);
             if (res < 0)
                 return res;
         } else {
             size_t img_size = w * ((bpp + 1) >> 3);
+            uint8_t *line;
             if (bytestream2_get_bytes_left(&s->gb) < img_size * h) {
                 av_log(avctx, AV_LOG_ERROR,
                        "Not enough data available for image\n");
                 return AVERROR_INVALIDDATA;
             }
-            for (y = 0; y < h; y++) {
-                bytestream2_get_bufferu(&s->gb, dst, img_size);
-                dst += stride;
-            }
+
+            line = dst;
+            y = 0;
+            do {
+                bytestream2_get_bufferu(&s->gb, line, img_size);
+                line = advance_line(dst, line, stride, &y, h, interleave);
+            } while (line);
         }
     }
     if(flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip
diff --git a/libavcodec/targa.h b/libavcodec/targa.h
index 8b22b16..901cb20 100644
--- a/libavcodec/targa.h
+++ b/libavcodec/targa.h
@@ -41,6 +41,8 @@ enum TargaCompr {
 enum TargaFlags {
 	TGA_RIGHTTOLEFT = 0x10, // right-to-left (flipped horizontally)
 	TGA_TOPTOBOTTOM = 0x20, // top-to-bottom (NOT flipped vertically)
-}
+	TGA_INTERLEAVE2 = 0x40, // 2-way interleave, odd then even lines
+	TGA_INTERLEAVE4 = 0x80, // 4-way interleave
+};
 
 #endif /* AVCODEC_TARGA_H */
-- 
1.7.12



More information about the ffmpeg-devel mailing list