From 3689cf16497109974777194e6ca18316c758d963 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 11 Oct 2006 04:15:04 +0000 Subject: [PATCH] Targa image decoder Originally committed as revision 6640 to svn://svn.ffmpeg.org/ffmpeg/trunk --- Changelog | 1 + MAINTAINERS | 1 + doc/ffmpeg-doc.texi | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 3 + libavcodec/avcodec.h | 6 +- libavcodec/targa.c | 244 +++++++++++++++++++++++++++++++++++++++++ libavformat/mov.c | 1 + 8 files changed, 256 insertions(+), 2 deletions(-) create mode 100644 libavcodec/targa.c diff --git a/Changelog b/Changelog index 1bcfe36ea4..82f7b221f6 100644 --- a/Changelog +++ b/Changelog @@ -59,6 +59,7 @@ version - VP5 video decoder - VP6 video decoder - WavPack lossless audio decoder +- Targa (.TGA) picture decoder version 0.4.9-pre1: diff --git a/MAINTAINERS b/MAINTAINERS index d73d55d42f..4d833247a5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -155,6 +155,7 @@ Codecs: snow.c Michael Niedermayer, Loren Merritt sonic.c Alex Beregszaszi svq3.c Michael Niedermayer + targa.c Kostya Shishkov truemotion1* Mike Melanson truemotion2* Kostya Shishkov truespeech.c Kostya Shishkov diff --git a/doc/ffmpeg-doc.texi b/doc/ffmpeg-doc.texi index c41807db1a..b4333be577 100644 --- a/doc/ffmpeg-doc.texi +++ b/doc/ffmpeg-doc.texi @@ -753,6 +753,7 @@ following image formats are supported: @item .Y.U.V @tab X @tab X @tab one raw file per component @item animated GIF @tab X @tab X @tab Only uncompressed GIFs are generated. @item PNG @tab X @tab X @tab 2 bit and 4 bit/pixel not supported yet. +@item Targa @tab @tab X @tab Targa (.TGA) image format. @item SGI @tab X @tab X @tab SGI RGB image format @end multitable diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ac1c88bd29..da5236ea99 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -131,6 +131,7 @@ OBJS-$(CONFIG_SONIC_LS_DECODER) += sonic.o OBJS-$(CONFIG_SVQ1_DECODER) += svq1.o OBJS-$(CONFIG_SVQ1_ENCODER) += svq1.o OBJS-$(CONFIG_SVQ3_DECODER) += h264.o +OBJS-$(CONFIG_TARGA_DECODER) += targa.o OBJS-$(CONFIG_THEORA_DECODER) += vp3.o OBJS-$(CONFIG_TRUEMOTION1_DECODER) += truemotion1.o OBJS-$(CONFIG_TRUEMOTION2_DECODER) += truemotion2.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 83074578db..8cd25426b5 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -545,6 +545,9 @@ void avcodec_register_all(void) #ifdef CONFIG_WAVPACK_DECODER register_avcodec(&wavpack_decoder); #endif //CONFIG_WAVPACK_DECODER +#ifdef CONFIG_TARGA_DECODER + register_avcodec(&targa_decoder); +#endif //CONFIG_TARGA_DECODER #if defined(CONFIG_AMR_NB) || defined(CONFIG_AMR_NB_FIXED) #ifdef CONFIG_AMR_NB_DECODER diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 5123732484..933c461afd 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -37,8 +37,8 @@ extern "C" { #define AV_STRINGIFY(s) AV_TOSTRING(s) #define AV_TOSTRING(s) #s -#define LIBAVCODEC_VERSION_INT ((51<<16)+(16<<8)+0) -#define LIBAVCODEC_VERSION 51.16.0 +#define LIBAVCODEC_VERSION_INT ((51<<16)+(17<<8)+0) +#define LIBAVCODEC_VERSION 51.17.0 #define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT #define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) @@ -144,6 +144,7 @@ enum CodecID { CODEC_ID_VP5, CODEC_ID_VP6, CODEC_ID_VP6F, + CODEC_ID_TARGA, /* various pcm "codecs" */ CODEC_ID_PCM_S16LE= 0x10000, @@ -2292,6 +2293,7 @@ extern AVCodec flashsv_decoder; extern AVCodec cavs_decoder; extern AVCodec vmnc_decoder; extern AVCodec wavpack_decoder; +extern AVCodec targa_decoder; /* pcm codecs */ #define PCM_CODEC(id, name) \ diff --git a/libavcodec/targa.c b/libavcodec/targa.c new file mode 100644 index 0000000000..4f83bb61b2 --- /dev/null +++ b/libavcodec/targa.c @@ -0,0 +1,244 @@ +/* + * Targa (.tga) image decoder + * Copyright (c) 2006 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * 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. + * + * 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "avcodec.h" + +enum TargaCompr{ + TGA_NODATA = 0, // no image data + TGA_PAL = 1, // palettized + TGA_RGB = 2, // true-color + TGA_BW = 3, // black & white or grayscale + TGA_RLE = 8, // flag pointing that data is RLE-coded +}; + +typedef struct TargaContext { + AVFrame picture; + + int width, height; + int bpp; + int color_type; + int compression_type; +} TargaContext; + +static void targa_decode_rle(AVCodecContext *avctx, TargaContext *s, uint8_t *src, uint8_t *dst, int w, int h, int stride, int bpp) +{ + int i, x, y; + int depth = (bpp + 1) >> 3; + int type, count; + int diff; + + diff = stride - w * depth; + x = y = 0; + while(y < h){ + type = *src++; + count = (type & 0x7F) + 1; + type &= 0x80; + if((x + count > w) && (x + count + 1 > (h - y) * w)){ + av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds: position (%i,%i) size %i\n", x, y, count); + return; + } + for(i = 0; i < count; i++){ + switch(depth){ + case 1: + *dst = *src; + break; + case 2: + *((uint16_t*)dst) = LE_16(src); + break; + case 3: + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + break; + } + dst += depth; + if(!type) + src += depth; + + x++; + if(x == w){ + x = 0; + y++; + dst += diff; + } + } + if(type) + src += depth; + } +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + TargaContext * const s = avctx->priv_data; + AVFrame *picture = data; + AVFrame * const p= (AVFrame*)&s->picture; + uint8_t *dst; + int stride; + int idlen, pal, compr, x, y, w, h, bpp, flags; + int first_clr, colors, csize; + + /* parse image header */ + idlen = *buf++; + pal = *buf++; + compr = *buf++; + first_clr = LE_16(buf); buf += 2; + colors = LE_16(buf); buf += 2; + csize = *buf++; + x = LE_16(buf); buf += 2; + y = LE_16(buf); buf += 2; + w = LE_16(buf); buf += 2; + h = LE_16(buf); buf += 2; + bpp = *buf++; + flags = *buf++; + //skip identifier if any + buf += idlen; + s->bpp = bpp; + s->width = w; + s->height = h; + switch(s->bpp){ + case 8: + avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? PIX_FMT_GRAY8 : PIX_FMT_PAL8; + break; + case 15: + avctx->pix_fmt = PIX_FMT_RGB555; + break; + case 16: + avctx->pix_fmt = PIX_FMT_RGB555; + break; + case 24: + avctx->pix_fmt = PIX_FMT_BGR24; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", avctx->bits_per_sample); + return -1; + } + + if(s->picture.data[0]) + avctx->release_buffer(avctx, &s->picture); + + if(avcodec_check_dimensions(avctx, w, h)) + return -1; + if(w != avctx->width || h != avctx->height) + avcodec_set_dimensions(avctx, w, h); + if(avctx->get_buffer(avctx, p) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + if(flags & 0x20){ + dst = p->data[0]; + stride = p->linesize[0]; + }else{ //image is upside-down + dst = p->data[0] + p->linesize[0] * (h - 1); + stride = -p->linesize[0]; + } + + if(avctx->pix_fmt == PIX_FMT_PAL8 && avctx->palctrl){ + memcpy(p->data[1], avctx->palctrl->palette, AVPALETTE_SIZE); + if(avctx->palctrl->palette_changed){ + p->palette_has_changed = 1; + avctx->palctrl->palette_changed = 0; + } + } + if(colors){ + if((colors + first_clr) > 256){ + av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); + return -1; + } + if(csize != 24){ + av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); + return -1; + } + if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway + buf += colors * ((csize + 1) >> 3); + else{ + int r, g, b, t; + int32_t *pal = ((int32_t*)p->data[1]) + first_clr; + for(t = 0; t < colors; t++){ + r = *buf++; + g = *buf++; + b = *buf++; + *pal++ = (b << 16) | (g << 8) | r; + } + p->palette_has_changed = 1; + avctx->palctrl->palette_changed = 0; + } + } + if((compr & (~TGA_RLE)) == TGA_NODATA) + memset(p->data[0], 0, p->linesize[0] * s->height); + else{ + if(compr & TGA_RLE) + targa_decode_rle(avctx, s, buf, dst, avctx->width, avctx->height, stride, bpp); + else{ + for(y = 0; y < s->height; y++){ +#ifdef WORDS_BIGENDIAN + if((s->bpp + 1) >> 3 == 2){ + uint16_t *dst16 = (uint16_t*)dst; + for(x = 0; x < s->width; x++) + dst16[x] = LE_16(buf + x * 2); + }else +#endif + memcpy(dst, buf, s->width * ((s->bpp + 1) >> 3)); + + dst += stride; + buf += s->width * ((s->bpp + 1) >> 3); + } + } + } + + *picture= *(AVFrame*)&s->picture; + *data_size = sizeof(AVPicture); + + return buf_size; +} + +static int targa_init(AVCodecContext *avctx){ + TargaContext *s = avctx->priv_data; + + avcodec_get_frame_defaults((AVFrame*)&s->picture); + avctx->coded_frame= (AVFrame*)&s->picture; + s->picture.data[0] = NULL; + + return 0; +} + +static int targa_end(AVCodecContext *avctx){ + TargaContext *s = avctx->priv_data; + + if(s->picture.data[0]) + avctx->release_buffer(avctx, &s->picture); + + return 0; +} + +AVCodec targa_decoder = { + "targa", + CODEC_TYPE_VIDEO, + CODEC_ID_TARGA, + sizeof(TargaContext), + targa_init, + NULL, + targa_end, + decode_frame, + 0, + NULL +}; diff --git a/libavformat/mov.c b/libavformat/mov.c index 18e1ab91dd..edeaa9f9f0 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -117,6 +117,7 @@ static const CodecTag mov_video_tags[] = { { CODEC_ID_DVVIDEO, MKTAG('d', 'v', '5', 'n') }, /* DVCPRO50 NTSC produced by FCP */ { CODEC_ID_DVVIDEO, MKTAG('A', 'V', 'd', 'v') }, /* AVID DV */ //{ CODEC_ID_JPEG2000, MKTAG('m', 'j', 'p', '2') }, /* JPEG 2000 produced by FCP */ + { CODEC_ID_TARGA, MKTAG('t', 'g', 'a', ' ') }, /* Truevision Targa */ { CODEC_ID_RAWVIDEO, MKTAG('2', 'v', 'u', 'y') }, /* UNCOMPRESSED 8BIT 4:2:2 */ { CODEC_ID_NONE, 0 }, };