]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/targa.c
Merge remote-tracking branch 'qatar/master'
[ffmpeg] / libavcodec / targa.c
index 60c8e8d0a8d934b30b3b13e37b2196d26888da7f..d3740be5eff3569d8fa7977f5fd5cbcabca02571 100644 (file)
@@ -2,20 +2,20 @@
  * Targa (.tga) image decoder
  * Copyright (c) 2006 Konstantin Shishkov
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -52,7 +52,7 @@ static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
         type  = bytestream2_get_byteu(&s->gb);
         count = (type & 0x7F) + 1;
         type &= 0x80;
-        if (x + count > w && x + count + 1 > (h - y) * w) {
+        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);
@@ -102,14 +102,14 @@ static int decode_frame(AVCodecContext *avctx,
     AVFrame * const p = &s->picture;
     uint8_t *dst;
     int stride;
-    int idlen, compr, y, w, h, bpp, flags;
+    int idlen, pal, compr, y, w, h, bpp, flags;
     int first_clr, colors, csize;
 
     bytestream2_init(&s->gb, avpkt->data, avpkt->size);
 
     /* parse image header */
     idlen     = bytestream2_get_byte(&s->gb);
-    bytestream2_skip(&s->gb, 1); /* pal */
+    pal       = bytestream2_get_byte(&s->gb);
     compr     = bytestream2_get_byte(&s->gb);
     first_clr = bytestream2_get_le16(&s->gb);
     colors    = bytestream2_get_le16(&s->gb);
@@ -118,7 +118,21 @@ static int decode_frame(AVCodecContext *avctx,
     w         = bytestream2_get_le16(&s->gb);
     h         = bytestream2_get_le16(&s->gb);
     bpp       = bytestream2_get_byte(&s->gb);
+
+    if (bytestream2_get_bytes_left(&s->gb) <= idlen) {
+        av_log(avctx, AV_LOG_ERROR,
+                "Not enough data to read header\n");
+        return AVERROR_INVALIDDATA;
+    }
+
     flags     = bytestream2_get_byte(&s->gb);
+
+    if (!pal && (first_clr || colors || csize)) {
+        av_log(avctx, AV_LOG_WARNING, "File without colormap has colormap information set.\n");
+        // specification says we should ignore those value in this case
+        first_clr = colors = csize = 0;
+    }
+
     // skip identifier if any
     bytestream2_skip(&s->gb, idlen);
 
@@ -127,8 +141,6 @@ static int decode_frame(AVCodecContext *avctx,
         avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? PIX_FMT_GRAY8 : PIX_FMT_PAL8;
         break;
     case 15:
-        avctx->pix_fmt = PIX_FMT_RGB555LE;
-        break;
     case 16:
         avctx->pix_fmt = PIX_FMT_RGB555LE;
         break;
@@ -192,7 +204,7 @@ static int decode_frame(AVCodecContext *avctx,
             case 3:
                 /* RGB24 */
                 for (t = 0; t < colors; t++)
-                    *pal++ = bytestream2_get_le24u(&s->gb);
+                    *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb);
                 break;
             case 2:
                 /* RGB555 */
@@ -203,7 +215,7 @@ static int decode_frame(AVCodecContext *avctx,
                         ((v & 0x001F) <<  3);
                     /* left bit replication */
                     v |= (v & 0xE0E0E0U) >> 5;
-                    *pal++ = v;
+                    *pal++ = (0xffU<<24) | v;
                 }
                 break;
             }
@@ -230,6 +242,29 @@ static int decode_frame(AVCodecContext *avctx,
             }
         }
     }
+    if(flags & 0x10){ // right-to-left, needs horizontal flip
+        int x;
+        for(y = 0; y < h; y++){
+            void *line = &p->data[0][y * p->linesize[0]];
+            for(x = 0; x < w >> 1; x++){
+                switch(bpp){
+                case 32:
+                    FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]);
+                    break;
+                case 24:
+                    FFSWAP(uint8_t, ((uint8_t *)line)[3 * x    ], ((uint8_t *)line)[3 * w - 3 * x - 3]);
+                    FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]);
+                    FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]);
+                    break;
+                case 16:
+                    FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]);
+                    break;
+                case 8:
+                    FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]);
+                }
+            }
+        }
+    }
 
     *picture   = s->picture;
     *data_size = sizeof(AVPicture);
@@ -264,5 +299,5 @@ AVCodec ff_targa_decoder = {
     .close          = targa_end,
     .decode         = decode_frame,
     .capabilities   = CODEC_CAP_DR1,
-    .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
+    .long_name      = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
 };