Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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. static uint8_t *advance_line(uint8_t *start, uint8_t *line,
  34.                              int stride, int *y, int h, int interleave)
  35. {
  36.     *y += interleave;
  37.  
  38.     if (*y < h) {
  39.         return line + interleave * stride;
  40.     } else {
  41.         *y = (*y + 1) & (interleave - 1);
  42.         if (*y && *y < h) {
  43.             return start + *y * stride;
  44.         } else {
  45.             return NULL;
  46.         }
  47.     }
  48. }
  49.  
  50. 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.     int depth = (bpp + 1) >> 3;
  56.     int type, count;
  57.     uint8_t *line = start;
  58.     uint8_t *dst  = line;
  59.  
  60.     x = y = count = 0;
  61.     while (dst) {
  62.         if (bytestream2_get_bytes_left(&s->gb) <= 0) {
  63.             av_log(avctx, AV_LOG_ERROR,
  64.                    "Ran ouf of data before end-of-image\n");
  65.             return AVERROR_INVALIDDATA;
  66.         }
  67.         type  = bytestream2_get_byteu(&s->gb);
  68.         count = (type & 0x7F) + 1;
  69.         type &= 0x80;
  70.         if (!type) {
  71.             do {
  72.                 int n  = FFMIN(count, w - x);
  73.                 bytestream2_get_buffer(&s->gb, dst, n * depth);
  74.                 count -= n;
  75.                 dst   += n * depth;
  76.                 x     += n;
  77.                 if (x == w) {
  78.                     x    = 0;
  79.                     dst = line = advance_line(start, line, stride, &y, h, interleave);
  80.                 }
  81.             } while (dst && count > 0);
  82.         } else {
  83.             uint8_t tmp[4];
  84.             bytestream2_get_buffer(&s->gb, tmp, depth);
  85.             do {
  86.                 int n  = FFMIN(count, w - x);
  87.                 count -= n;
  88.                 x     += n;
  89.                 do {
  90.                     memcpy(dst, tmp, depth);
  91.                     dst += depth;
  92.                 } while (--n);
  93.                 if (x == w) {
  94.                     x    = 0;
  95.                     dst = line = advance_line(start, line, stride, &y, h, interleave);
  96.                 }
  97.             } while (dst && count > 0);
  98.         }
  99.     }
  100.  
  101.     if (count) {
  102.         av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds\n");
  103.         return AVERROR_INVALIDDATA;
  104.     }
  105.  
  106.     return 0;
  107. }
  108.  
  109. static int decode_frame(AVCodecContext *avctx,
  110.                         void *data, int *got_frame,
  111.                         AVPacket *avpkt)
  112. {
  113.     TargaContext * const s = avctx->priv_data;
  114.     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.     bytestream2_init(&s->gb, avpkt->data, avpkt->size);
  122.  
  123.     /* parse image header */
  124.     idlen     = bytestream2_get_byte(&s->gb);
  125.     pal       = bytestream2_get_byte(&s->gb);
  126.     compr     = bytestream2_get_byte(&s->gb);
  127.     first_clr = bytestream2_get_le16(&s->gb);
  128.     colors    = bytestream2_get_le16(&s->gb);
  129.     csize     = bytestream2_get_byte(&s->gb);
  130.     bytestream2_skip(&s->gb, 4); /* 2: x, 2: y */
  131.     w         = bytestream2_get_le16(&s->gb);
  132.     h         = bytestream2_get_le16(&s->gb);
  133.     bpp       = bytestream2_get_byte(&s->gb);
  134.  
  135.     if (bytestream2_get_bytes_left(&s->gb) <= idlen) {
  136.         av_log(avctx, AV_LOG_ERROR,
  137.                 "Not enough data to read header\n");
  138.         return AVERROR_INVALIDDATA;
  139.     }
  140.  
  141.     flags     = bytestream2_get_byte(&s->gb);
  142.  
  143.     if (!pal && (first_clr || colors || csize)) {
  144.         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.         first_clr = colors = csize = 0;
  147.     }
  148.  
  149.     // skip identifier if any
  150.     bytestream2_skip(&s->gb, idlen);
  151.  
  152.     switch (bpp) {
  153.     case 8:
  154.         avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? AV_PIX_FMT_GRAY8 : AV_PIX_FMT_PAL8;
  155.         break;
  156.     case 15:
  157.     case 16:
  158.         avctx->pix_fmt = AV_PIX_FMT_RGB555LE;
  159.         break;
  160.     case 24:
  161.         avctx->pix_fmt = AV_PIX_FMT_BGR24;
  162.         break;
  163.     case 32:
  164.         avctx->pix_fmt = AV_PIX_FMT_BGRA;
  165.         break;
  166.     default:
  167.         av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", bpp);
  168.         return AVERROR_INVALIDDATA;
  169.     }
  170.  
  171.     if (colors && (colors + first_clr) > 256) {
  172.         av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr);
  173.         return AVERROR_INVALIDDATA;
  174.     }
  175.  
  176.     if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)
  177.         return ret;
  178.     if (w != avctx->width || h != avctx->height)
  179.         avcodec_set_dimensions(avctx, w, h);
  180.     if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
  181.         return ret;
  182.     p->pict_type = AV_PICTURE_TYPE_I;
  183.  
  184.     if (flags & TGA_TOPTOBOTTOM) {
  185.         dst = p->data[0];
  186.         stride = p->linesize[0];
  187.     } else { //image is upside-down
  188.         dst = p->data[0] + p->linesize[0] * (h - 1);
  189.         stride = -p->linesize[0];
  190.     }
  191.  
  192.     interleave = flags & TGA_INTERLEAVE2 ? 2 :
  193.                  flags & TGA_INTERLEAVE4 ? 4 : 1;
  194.  
  195.     if (colors) {
  196.         int pal_size, pal_sample_size;
  197.  
  198.         switch (csize) {
  199.         case 32: pal_sample_size = 4; break;
  200.         case 24: pal_sample_size = 3; break;
  201.         case 16:
  202.         case 15: pal_sample_size = 2; break;
  203.         default:
  204.             av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize);
  205.             return AVERROR_INVALIDDATA;
  206.         }
  207.         pal_size = colors * pal_sample_size;
  208.         if (avctx->pix_fmt != AV_PIX_FMT_PAL8) //should not occur but skip palette anyway
  209.             bytestream2_skip(&s->gb, pal_size);
  210.         else {
  211.             int t;
  212.             uint32_t *pal = ((uint32_t *)p->data[1]) + first_clr;
  213.  
  214.             if (bytestream2_get_bytes_left(&s->gb) < pal_size) {
  215.                 av_log(avctx, AV_LOG_ERROR,
  216.                        "Not enough data to read palette\n");
  217.                 return AVERROR_INVALIDDATA;
  218.             }
  219.             switch (pal_sample_size) {
  220.             case 4:
  221.                 for (t = 0; t < colors; t++)
  222.                     *pal++ = bytestream2_get_le32u(&s->gb);
  223.                 break;
  224.             case 3:
  225.                 /* RGB24 */
  226.                 for (t = 0; t < colors; t++)
  227.                     *pal++ = (0xffU<<24) | bytestream2_get_le24u(&s->gb);
  228.                 break;
  229.             case 2:
  230.                 /* RGB555 */
  231.                 for (t = 0; t < colors; t++) {
  232.                     uint32_t v = bytestream2_get_le16u(&s->gb);
  233.                     v = ((v & 0x7C00) <<  9) |
  234.                         ((v & 0x03E0) <<  6) |
  235.                         ((v & 0x001F) <<  3);
  236.                     /* left bit replication */
  237.                     v |= (v & 0xE0E0E0U) >> 5;
  238.                     *pal++ = (0xffU<<24) | v;
  239.                 }
  240.                 break;
  241.             }
  242.             p->palette_has_changed = 1;
  243.         }
  244.     }
  245.  
  246.     if ((compr & (~TGA_RLE)) == TGA_NODATA) {
  247.         memset(p->data[0], 0, p->linesize[0] * h);
  248.     } else {
  249.         if (compr & TGA_RLE) {
  250.             int res = targa_decode_rle(avctx, s, dst, w, h, stride, bpp, interleave);
  251.             if (res < 0)
  252.                 return res;
  253.         } else {
  254.             size_t img_size = w * ((bpp + 1) >> 3);
  255.             uint8_t *line;
  256.             if (bytestream2_get_bytes_left(&s->gb) < img_size * h) {
  257.                 av_log(avctx, AV_LOG_ERROR,
  258.                        "Not enough data available for image\n");
  259.                 return AVERROR_INVALIDDATA;
  260.             }
  261.  
  262.             line = dst;
  263.             y = 0;
  264.             do {
  265.                 bytestream2_get_buffer(&s->gb, line, img_size);
  266.                 line = advance_line(dst, line, stride, &y, h, interleave);
  267.             } while (line);
  268.         }
  269.     }
  270.  
  271.     if (flags & TGA_RIGHTTOLEFT) { // right-to-left, needs horizontal flip
  272.         int x;
  273.         for (y = 0; y < h; y++) {
  274.             void *line = &p->data[0][y * p->linesize[0]];
  275.             for (x = 0; x < w >> 1; x++) {
  276.                 switch (bpp) {
  277.                 case 32:
  278.                     FFSWAP(uint32_t, ((uint32_t *)line)[x], ((uint32_t *)line)[w - x - 1]);
  279.                     break;
  280.                 case 24:
  281.                     FFSWAP(uint8_t, ((uint8_t *)line)[3 * x    ], ((uint8_t *)line)[3 * w - 3 * x - 3]);
  282.                     FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 1], ((uint8_t *)line)[3 * w - 3 * x - 2]);
  283.                     FFSWAP(uint8_t, ((uint8_t *)line)[3 * x + 2], ((uint8_t *)line)[3 * w - 3 * x - 1]);
  284.                     break;
  285.                 case 16:
  286.                     FFSWAP(uint16_t, ((uint16_t *)line)[x], ((uint16_t *)line)[w - x - 1]);
  287.                     break;
  288.                 case 8:
  289.                     FFSWAP(uint8_t, ((uint8_t *)line)[x], ((uint8_t *)line)[w - x - 1]);
  290.                 }
  291.             }
  292.         }
  293.     }
  294.  
  295.     *got_frame = 1;
  296.  
  297.     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   = CODEC_CAP_DR1,
  308. };
  309.