00001 /* 00002 * Targa (.tga) image decoder 00003 * Copyright (c) 2006 Konstantin Shishkov 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00022 #include "libavutil/intreadwrite.h" 00023 #include "avcodec.h" 00024 00025 enum TargaCompr{ 00026 TGA_NODATA = 0, // no image data 00027 TGA_PAL = 1, // palettized 00028 TGA_RGB = 2, // true-color 00029 TGA_BW = 3, // black & white or grayscale 00030 TGA_RLE = 8, // flag pointing that data is RLE-coded 00031 }; 00032 00033 typedef struct TargaContext { 00034 AVFrame picture; 00035 00036 int width, height; 00037 int bpp; 00038 int color_type; 00039 int compression_type; 00040 } TargaContext; 00041 00042 static void targa_decode_rle(AVCodecContext *avctx, TargaContext *s, const uint8_t *src, uint8_t *dst, int w, int h, int stride, int bpp) 00043 { 00044 int i, x, y; 00045 int depth = (bpp + 1) >> 3; 00046 int type, count; 00047 int diff; 00048 00049 diff = stride - w * depth; 00050 x = y = 0; 00051 while(y < h){ 00052 type = *src++; 00053 count = (type & 0x7F) + 1; 00054 type &= 0x80; 00055 if((x + count > w) && (x + count + 1 > (h - y) * w)){ 00056 av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds: position (%i,%i) size %i\n", x, y, count); 00057 return; 00058 } 00059 for(i = 0; i < count; i++){ 00060 switch(depth){ 00061 case 1: 00062 *dst = *src; 00063 break; 00064 case 2: 00065 *((uint16_t*)dst) = AV_RL16(src); 00066 break; 00067 case 3: 00068 dst[0] = src[0]; 00069 dst[1] = src[1]; 00070 dst[2] = src[2]; 00071 break; 00072 case 4: 00073 *((uint32_t*)dst) = AV_RL32(src); 00074 break; 00075 } 00076 dst += depth; 00077 if(!type) 00078 src += depth; 00079 00080 x++; 00081 if(x == w){ 00082 x = 0; 00083 y++; 00084 dst += diff; 00085 } 00086 } 00087 if(type) 00088 src += depth; 00089 } 00090 } 00091 00092 static int decode_frame(AVCodecContext *avctx, 00093 void *data, int *data_size, 00094 const uint8_t *buf, int buf_size) 00095 { 00096 TargaContext * const s = avctx->priv_data; 00097 AVFrame *picture = data; 00098 AVFrame * const p= (AVFrame*)&s->picture; 00099 uint8_t *dst; 00100 int stride; 00101 int idlen, pal, compr, x, y, w, h, bpp, flags; 00102 int first_clr, colors, csize; 00103 00104 /* parse image header */ 00105 idlen = *buf++; 00106 pal = *buf++; 00107 compr = *buf++; 00108 first_clr = AV_RL16(buf); buf += 2; 00109 colors = AV_RL16(buf); buf += 2; 00110 csize = *buf++; 00111 x = AV_RL16(buf); buf += 2; 00112 y = AV_RL16(buf); buf += 2; 00113 w = AV_RL16(buf); buf += 2; 00114 h = AV_RL16(buf); buf += 2; 00115 bpp = *buf++; 00116 flags = *buf++; 00117 //skip identifier if any 00118 buf += idlen; 00119 s->bpp = bpp; 00120 s->width = w; 00121 s->height = h; 00122 switch(s->bpp){ 00123 case 8: 00124 avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? PIX_FMT_GRAY8 : PIX_FMT_PAL8; 00125 break; 00126 case 15: 00127 avctx->pix_fmt = PIX_FMT_RGB555; 00128 break; 00129 case 16: 00130 avctx->pix_fmt = PIX_FMT_RGB555; 00131 break; 00132 case 24: 00133 avctx->pix_fmt = PIX_FMT_BGR24; 00134 break; 00135 case 32: 00136 avctx->pix_fmt = PIX_FMT_RGB32; 00137 break; 00138 default: 00139 av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", s->bpp); 00140 return -1; 00141 } 00142 00143 if(s->picture.data[0]) 00144 avctx->release_buffer(avctx, &s->picture); 00145 00146 if(avcodec_check_dimensions(avctx, w, h)) 00147 return -1; 00148 if(w != avctx->width || h != avctx->height) 00149 avcodec_set_dimensions(avctx, w, h); 00150 if(avctx->get_buffer(avctx, p) < 0){ 00151 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00152 return -1; 00153 } 00154 if(flags & 0x20){ 00155 dst = p->data[0]; 00156 stride = p->linesize[0]; 00157 }else{ //image is upside-down 00158 dst = p->data[0] + p->linesize[0] * (h - 1); 00159 stride = -p->linesize[0]; 00160 } 00161 00162 if(avctx->pix_fmt == PIX_FMT_PAL8 && avctx->palctrl){ 00163 memcpy(p->data[1], avctx->palctrl->palette, AVPALETTE_SIZE); 00164 if(avctx->palctrl->palette_changed){ 00165 p->palette_has_changed = 1; 00166 avctx->palctrl->palette_changed = 0; 00167 } 00168 } 00169 if(colors){ 00170 if((colors + first_clr) > 256){ 00171 av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); 00172 return -1; 00173 } 00174 if(csize != 24){ 00175 av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); 00176 return -1; 00177 } 00178 if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway 00179 buf += colors * ((csize + 1) >> 3); 00180 else{ 00181 int r, g, b, t; 00182 int32_t *pal = ((int32_t*)p->data[1]) + first_clr; 00183 for(t = 0; t < colors; t++){ 00184 r = *buf++; 00185 g = *buf++; 00186 b = *buf++; 00187 *pal++ = (b << 16) | (g << 8) | r; 00188 } 00189 p->palette_has_changed = 1; 00190 avctx->palctrl->palette_changed = 0; 00191 } 00192 } 00193 if((compr & (~TGA_RLE)) == TGA_NODATA) 00194 memset(p->data[0], 0, p->linesize[0] * s->height); 00195 else{ 00196 if(compr & TGA_RLE) 00197 targa_decode_rle(avctx, s, buf, dst, avctx->width, avctx->height, stride, bpp); 00198 else{ 00199 for(y = 0; y < s->height; y++){ 00200 #ifdef WORDS_BIGENDIAN 00201 if((s->bpp + 1) >> 3 == 2){ 00202 uint16_t *dst16 = (uint16_t*)dst; 00203 for(x = 0; x < s->width; x++) 00204 dst16[x] = AV_RL16(buf + x * 2); 00205 }else if((s->bpp + 1) >> 3 == 4){ 00206 uint32_t *dst32 = (uint32_t*)dst; 00207 for(x = 0; x < s->width; x++) 00208 dst32[x] = AV_RL32(buf + x * 4); 00209 }else 00210 #endif 00211 memcpy(dst, buf, s->width * ((s->bpp + 1) >> 3)); 00212 00213 dst += stride; 00214 buf += s->width * ((s->bpp + 1) >> 3); 00215 } 00216 } 00217 } 00218 00219 *picture= *(AVFrame*)&s->picture; 00220 *data_size = sizeof(AVPicture); 00221 00222 return buf_size; 00223 } 00224 00225 static av_cold int targa_init(AVCodecContext *avctx){ 00226 TargaContext *s = avctx->priv_data; 00227 00228 avcodec_get_frame_defaults((AVFrame*)&s->picture); 00229 avctx->coded_frame= (AVFrame*)&s->picture; 00230 s->picture.data[0] = NULL; 00231 00232 return 0; 00233 } 00234 00235 static av_cold int targa_end(AVCodecContext *avctx){ 00236 TargaContext *s = avctx->priv_data; 00237 00238 if(s->picture.data[0]) 00239 avctx->release_buffer(avctx, &s->picture); 00240 00241 return 0; 00242 } 00243 00244 AVCodec targa_decoder = { 00245 "targa", 00246 CODEC_TYPE_VIDEO, 00247 CODEC_ID_TARGA, 00248 sizeof(TargaContext), 00249 targa_init, 00250 NULL, 00251 targa_end, 00252 decode_frame, 00253 0, 00254 NULL, 00255 .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), 00256 };