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