LCOV - code coverage report
Current view: top level - libavcodec - targa.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 115 168 68.5 %
Date: 2017-12-14 19:11:59 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Targa (.tga) image decoder
       3             :  * Copyright (c) 2006 Konstantin Shishkov
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include "libavutil/intreadwrite.h"
      23             : #include "libavutil/imgutils.h"
      24             : #include "avcodec.h"
      25             : #include "bytestream.h"
      26             : #include "internal.h"
      27             : #include "targa.h"
      28             : 
      29             : typedef struct TargaContext {
      30             :     GetByteContext gb;
      31             : } TargaContext;
      32             : 
      33        7392 : static uint8_t *advance_line(uint8_t *start, uint8_t *line,
      34             :                              int stride, int *y, int h, int interleave)
      35             : {
      36        7392 :     *y += interleave;
      37             : 
      38        7392 :     if (*y < h) {
      39        7355 :         return line + interleave * stride;
      40             :     } else {
      41          37 :         *y = (*y + 1) & (interleave - 1);
      42          37 :         if (*y && *y < h) {
      43           0 :             return start + *y * stride;
      44             :         } else {
      45          37 :             return NULL;
      46             :         }
      47             :     }
      48             : }
      49             : 
      50          12 : static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s,
      51             :                             uint8_t *start, int w, int h, int stride,
      52             :                             int bpp, int interleave)
      53             : {
      54             :     int x, y;
      55          12 :     int depth = (bpp + 1) >> 3;
      56             :     int type, count;
      57          12 :     uint8_t *line = start;
      58          12 :     uint8_t *dst  = line;
      59             : 
      60          12 :     x = y = count = 0;
      61       22068 :     while (dst) {
      62       22044 :         if (bytestream2_get_bytes_left(&s->gb) <= 0) {
      63           0 :             av_log(avctx, AV_LOG_ERROR,
      64             :                    "Ran ouf of data before end-of-image\n");
      65           0 :             return AVERROR_INVALIDDATA;
      66             :         }
      67       22044 :         type  = bytestream2_get_byteu(&s->gb);
      68       22044 :         count = (type & 0x7F) + 1;
      69       22044 :         type &= 0x80;
      70       22044 :         if (!type) {
      71             :             do {
      72        1284 :                 int n  = FFMIN(count, w - x);
      73        1284 :                 bytestream2_get_buffer(&s->gb, dst, n * depth);
      74        1284 :                 count -= n;
      75        1284 :                 dst   += n * depth;
      76        1284 :                 x     += n;
      77        1284 :                 if (x == w) {
      78         512 :                     x    = 0;
      79         512 :                     dst = line = advance_line(start, line, stride, &y, h, interleave);
      80             :                 }
      81        1284 :             } while (dst && count > 0);
      82             :         } else {
      83             :             uint8_t tmp[4];
      84       20760 :             bytestream2_get_buffer(&s->gb, tmp, depth);
      85             :             do {
      86       20760 :                 int n  = FFMIN(count, w - x);
      87       20760 :                 count -= n;
      88       20760 :                 x     += n;
      89             :                 do {
      90      164400 :                     memcpy(dst, tmp, depth);
      91      164400 :                     dst += depth;
      92      164400 :                 } while (--n);
      93       20760 :                 if (x == w) {
      94        1280 :                     x    = 0;
      95        1280 :                     dst = line = advance_line(start, line, stride, &y, h, interleave);
      96             :                 }
      97       20760 :             } while (dst && count > 0);
      98             :         }
      99             :     }
     100             : 
     101          12 :     if (count) {
     102           0 :         av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds\n");
     103           0 :         return AVERROR_INVALIDDATA;
     104             :     }
     105             : 
     106          12 :     return 0;
     107             : }
     108             : 
     109          37 : static int decode_frame(AVCodecContext *avctx,
     110             :                         void *data, int *got_frame,
     111             :                         AVPacket *avpkt)
     112             : {
     113          37 :     TargaContext * const s = avctx->priv_data;
     114          37 :     AVFrame * const p = data;
     115             :     uint8_t *dst;
     116             :     int stride;
     117             :     int idlen, pal, compr, y, w, h, bpp, flags, ret;
     118             :     int first_clr, colors, csize;
     119             :     int interleave;
     120             : 
     121          37 :     bytestream2_init(&s->gb, avpkt->data, avpkt->size);
     122             : 
     123             :     /* parse image header */
     124          37 :     idlen     = bytestream2_get_byte(&s->gb);
     125          37 :     pal       = bytestream2_get_byte(&s->gb);
     126          37 :     compr     = bytestream2_get_byte(&s->gb);
     127          37 :     first_clr = bytestream2_get_le16(&s->gb);
     128          37 :     colors    = bytestream2_get_le16(&s->gb);
     129          37 :     csize     = bytestream2_get_byte(&s->gb);
     130          37 :     bytestream2_skip(&s->gb, 4); /* 2: x, 2: y */
     131          37 :     w         = bytestream2_get_le16(&s->gb);
     132          37 :     h         = bytestream2_get_le16(&s->gb);
     133          37 :     bpp       = bytestream2_get_byte(&s->gb);
     134             : 
     135          37 :     if (bytestream2_get_bytes_left(&s->gb) <= idlen) {
     136           0 :         av_log(avctx, AV_LOG_ERROR,
     137             :                 "Not enough data to read header\n");
     138           0 :         return AVERROR_INVALIDDATA;
     139             :     }
     140             : 
     141          37 :     flags     = bytestream2_get_byte(&s->gb);
     142             : 
     143          37 :     if (!pal && (first_clr || colors || csize)) {
     144           0 :         av_log(avctx, AV_LOG_WARNING, "File without colormap has colormap information set.\n");
     145             :         // specification says we should ignore those value in this case
     146           0 :         first_clr = colors = csize = 0;
     147             :     }
     148             : 
     149             :     // skip identifier if any
     150          37 :     bytestream2_skip(&s->gb, idlen);
     151             : 
     152          37 :     switch (bpp) {
     153           8 :     case 8:
     154           8 :         avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_PAL8;
     155           8 :         break;
     156           4 :     case 15:
     157             :     case 16:
     158           4 :         avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
     159           4 :         break;
     160          21 :     case 24:
     161          21 :         avctx->pix_fmt = AV_PIX_FMT_BGR24;
     162          21 :         break;
     163           4 :     case 32:
     164           4 :         avctx->pix_fmt = AV_PIX_FMT_BGRA;
     165           4 :         break;
     166           0 :     default:
     167           0 :         av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", bpp);
     168           0 :         return AVERROR_INVALIDDATA;
     169             :     }
     170             : 
     171          37 :     if (colors && (colors + first_clr) > 256) {
     172           0 :         av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
     173           0 :         return AVERROR_INVALIDDATA;
     174             :     }
     175             : 
     176          37 :     if ((ret = ff_set_dimensions(avctx, w, h)) < 0)
     177           0 :         return ret;
     178             : 
     179          37 :     if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
     180           0 :         return ret;
     181          37 :     p->pict_type = AV_PICTURE_TYPE_I;
     182             : 
     183          37 :     if (flags & TGA_TOPTOBOTTOM) {
     184          17 :         dst = p->data[0];
     185          17 :         stride = p->linesize[0];
     186             :     } else { //image is upside-down
     187          20 :         dst = p->data[0] + p->linesize[0] * (h - 1);
     188          20 :         stride = -p->linesize[0];
     189             :     }
     190             : 
     191          74 :     interleave = flags & TGA_INTERLEAVE2 ? 2 :
     192          37 :                  flags & TGA_INTERLEAVE4 ? 4 : 1;
     193             : 
     194          37 :     if (colors) {
     195             :         int pal_size, pal_sample_size;
     196             : 
     197           4 :         switch (csize) {
     198           0 :         case 32: pal_sample_size = 4; break;
     199           0 :         case 24: pal_sample_size = 3; break;
     200           4 :         case 16:
     201           4 :         case 15: pal_sample_size = 2; break;
     202           0 :         default:
     203           0 :             av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize);
     204           0 :             return AVERROR_INVALIDDATA;
     205             :         }
     206           4 :         pal_size = colors * pal_sample_size;
     207           4 :         if (avctx->pix_fmt != AV_PIX_FMT_PAL8) //should not occur but skip palette anyway
     208           0 :             bytestream2_skip(&s->gb, pal_size);
     209             :         else {
     210             :             int t;
     211           4 :             uint32_t *pal = ((uint32_t *)p->data[1]) + first_clr;
     212             : 
     213           4 :             if (bytestream2_get_bytes_left(&s->gb) < pal_size) {
     214           0 :                 av_log(avctx, AV_LOG_ERROR,
     215             :                        "Not enough data to read palette\n");
     216           0 :                 return AVERROR_INVALIDDATA;
     217             :             }
     218           4 :             switch (pal_sample_size) {
     219           0 :             case 4:
     220           0 :                 for (t = 0; t < colors; t++)
     221           0 :                     *pal++ = bytestream2_get_le32u(&s->gb);
     222           0 :                 break;
     223           0 :             case 3:
     224             :                 /* RGB24 */
     225           0 :                 for (t = 0; t < colors; t++)
     226           0 :                     *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb);
     227           0 :                 break;
     228           4 :             case 2:
     229             :                 /* RGB555 */
     230        1028 :                 for (t = 0; t < colors; t++) {
     231        1024 :                     uint32_t v = bytestream2_get_le16u(&s->gb);
     232        3072 :                     v = ((v & 0x7C00) <<  9) |
     233        1024 :                         ((v & 0x03E0) <<  6) |
     234        1024 :                         ((v & 0x001F) <<  3);
     235             :                     /* left bit replication */
     236        1024 :                     v |= (v & 0xE0E0E0U) >> 5;
     237        1024 :                     *pal++ = (0xffU<<24) | v;
     238             :                 }
     239           4 :                 break;
     240             :             }
     241           4 :             p->palette_has_changed = 1;
     242             :         }
     243             :     }
     244             : 
     245          37 :     if ((compr & (~TGA_RLE)) == TGA_NODATA) {
     246           0 :         memset(p->data[0], 0, p->linesize[0] * h);
     247             :     } else {
     248          37 :         if (compr & TGA_RLE) {
     249          12 :             int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave);
     250          12 :             if (res < 0)
     251           0 :                 return res;
     252             :         } else {
     253          25 :             size_t img_size = w * ((bpp + 1) >> 3);
     254             :             uint8_t *line;
     255          25 :             if (bytestream2_get_bytes_left(&s->gb) < img_size * h) {
     256           0 :                 av_log(avctx, AV_LOG_ERROR,
     257             :                        "Not enough data available for image\n");
     258           0 :                 return AVERROR_INVALIDDATA;
     259             :             }
     260             : 
     261          25 :             line = dst;
     262          25 :             y = 0;
     263             :             do {
     264        5600 :                 bytestream2_get_buffer(&s->gb, line, img_size);
     265        5600 :                 line = advance_line(dst, line, stride, &y, h, interleave);
     266        5600 :             } while (line);
     267             :         }
     268             : 
     269          37 :         if (flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip
     270             :             int x;
     271           0 :             for (y = 0; y < h; y++) {
     272           0 :                 void *line = &p->data[0][y * p->linesize[0]];
     273           0 :                 for (x = 0; x < w >> 1; x++) {
     274           0 :                     switch (bpp) {
     275           0 :                     case 32:
     276           0 :                         FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]);
     277           0 :                         break;
     278           0 :                     case 24:
     279           0 :                         FFSWAP(uint8_t, ((uint8_t *)line)[3 * x    ], ((uint8_t *)line)[3 * w - 3 * x - 3]);
     280           0 :                         FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]);
     281           0 :                         FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]);
     282           0 :                         break;
     283           0 :                     case 16:
     284           0 :                         FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]);
     285           0 :                         break;
     286           0 :                     case 8:
     287           0 :                         FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]);
     288             :                     }
     289             :                 }
     290             :             }
     291             :         }
     292             :     }
     293             : 
     294             : 
     295          37 :     *got_frame = 1;
     296             : 
     297          37 :     return avpkt->size;
     298             : }
     299             : 
     300             : AVCodec ff_targa_decoder = {
     301             :     .name           = "targa",
     302             :     .long_name      = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
     303             :     .type           = AVMEDIA_TYPE_VIDEO,
     304             :     .id             = AV_CODEC_ID_TARGA,
     305             :     .priv_data_size = sizeof(TargaContext),
     306             :     .decode         = decode_frame,
     307             :     .capabilities   = AV_CODEC_CAP_DR1,
     308             : };

Generated by: LCOV version 1.13