Libav
|
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 AVPacket *avpkt) 00095 { 00096 const uint8_t *buf = avpkt->data; 00097 int buf_size = avpkt->size; 00098 TargaContext * const s = avctx->priv_data; 00099 AVFrame *picture = data; 00100 AVFrame * const p= (AVFrame*)&s->picture; 00101 uint8_t *dst; 00102 int stride; 00103 int idlen, pal, compr, x, y, w, h, bpp, flags; 00104 int first_clr, colors, csize; 00105 00106 /* parse image header */ 00107 idlen = *buf++; 00108 pal = *buf++; 00109 compr = *buf++; 00110 first_clr = AV_RL16(buf); buf += 2; 00111 colors = AV_RL16(buf); buf += 2; 00112 csize = *buf++; 00113 x = AV_RL16(buf); buf += 2; 00114 y = AV_RL16(buf); buf += 2; 00115 w = AV_RL16(buf); buf += 2; 00116 h = AV_RL16(buf); buf += 2; 00117 bpp = *buf++; 00118 flags = *buf++; 00119 //skip identifier if any 00120 buf += idlen; 00121 s->bpp = bpp; 00122 s->width = w; 00123 s->height = h; 00124 switch(s->bpp){ 00125 case 8: 00126 avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? PIX_FMT_GRAY8 : PIX_FMT_PAL8; 00127 break; 00128 case 15: 00129 avctx->pix_fmt = PIX_FMT_RGB555; 00130 break; 00131 case 16: 00132 avctx->pix_fmt = PIX_FMT_RGB555; 00133 break; 00134 case 24: 00135 avctx->pix_fmt = PIX_FMT_BGR24; 00136 break; 00137 case 32: 00138 avctx->pix_fmt = PIX_FMT_RGB32; 00139 break; 00140 default: 00141 av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", s->bpp); 00142 return -1; 00143 } 00144 00145 if(s->picture.data[0]) 00146 avctx->release_buffer(avctx, &s->picture); 00147 00148 if(avcodec_check_dimensions(avctx, w, h)) 00149 return -1; 00150 if(w != avctx->width || h != avctx->height) 00151 avcodec_set_dimensions(avctx, w, h); 00152 if(avctx->get_buffer(avctx, p) < 0){ 00153 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00154 return -1; 00155 } 00156 if(flags & 0x20){ 00157 dst = p->data[0]; 00158 stride = p->linesize[0]; 00159 }else{ //image is upside-down 00160 dst = p->data[0] + p->linesize[0] * (h - 1); 00161 stride = -p->linesize[0]; 00162 } 00163 00164 if(avctx->pix_fmt == PIX_FMT_PAL8 && avctx->palctrl){ 00165 memcpy(p->data[1], avctx->palctrl->palette, AVPALETTE_SIZE); 00166 if(avctx->palctrl->palette_changed){ 00167 p->palette_has_changed = 1; 00168 avctx->palctrl->palette_changed = 0; 00169 } 00170 } 00171 if(colors){ 00172 if((colors + first_clr) > 256){ 00173 av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); 00174 return -1; 00175 } 00176 if(csize != 24){ 00177 av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); 00178 return -1; 00179 } 00180 if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway 00181 buf += colors * ((csize + 1) >> 3); 00182 else{ 00183 int r, g, b, t; 00184 int32_t *pal = ((int32_t*)p->data[1]) + first_clr; 00185 for(t = 0; t < colors; t++){ 00186 r = *buf++; 00187 g = *buf++; 00188 b = *buf++; 00189 *pal++ = (b << 16) | (g << 8) | r; 00190 } 00191 p->palette_has_changed = 1; 00192 } 00193 } 00194 if((compr & (~TGA_RLE)) == TGA_NODATA) 00195 memset(p->data[0], 0, p->linesize[0] * s->height); 00196 else{ 00197 if(compr & TGA_RLE) 00198 targa_decode_rle(avctx, s, buf, dst, avctx->width, avctx->height, stride, bpp); 00199 else{ 00200 for(y = 0; y < s->height; y++){ 00201 #if HAVE_BIGENDIAN 00202 if((s->bpp + 1) >> 3 == 2){ 00203 uint16_t *dst16 = (uint16_t*)dst; 00204 for(x = 0; x < s->width; x++) 00205 dst16[x] = AV_RL16(buf + x * 2); 00206 }else if((s->bpp + 1) >> 3 == 4){ 00207 uint32_t *dst32 = (uint32_t*)dst; 00208 for(x = 0; x < s->width; x++) 00209 dst32[x] = AV_RL32(buf + x * 4); 00210 }else 00211 #endif 00212 memcpy(dst, buf, s->width * ((s->bpp + 1) >> 3)); 00213 00214 dst += stride; 00215 buf += s->width * ((s->bpp + 1) >> 3); 00216 } 00217 } 00218 } 00219 00220 *picture= *(AVFrame*)&s->picture; 00221 *data_size = sizeof(AVPicture); 00222 00223 return buf_size; 00224 } 00225 00226 static av_cold int targa_init(AVCodecContext *avctx){ 00227 TargaContext *s = avctx->priv_data; 00228 00229 avcodec_get_frame_defaults((AVFrame*)&s->picture); 00230 avctx->coded_frame= (AVFrame*)&s->picture; 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 AVMEDIA_TYPE_VIDEO, 00247 CODEC_ID_TARGA, 00248 sizeof(TargaContext), 00249 targa_init, 00250 NULL, 00251 targa_end, 00252 decode_frame, 00253 CODEC_CAP_DR1, 00254 NULL, 00255 .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), 00256 };