Libav 0.7.1
|
00001 /* 00002 * Targa (.tga) image decoder 00003 * Copyright (c) 2006 Konstantin Shishkov 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav 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 * Libav 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 Libav; 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 "libavutil/imgutils.h" 00024 #include "avcodec.h" 00025 #include "targa.h" 00026 00027 typedef struct TargaContext { 00028 AVFrame picture; 00029 00030 int width, height; 00031 int bpp; 00032 int color_type; 00033 int compression_type; 00034 } TargaContext; 00035 00036 #define CHECK_BUFFER_SIZE(buf, buf_end, needed, where) \ 00037 if(needed > buf_end - buf){ \ 00038 av_log(avctx, AV_LOG_ERROR, "Problem: unexpected end of data while reading " where "\n"); \ 00039 return -1; \ 00040 } \ 00041 00042 static int targa_decode_rle(AVCodecContext *avctx, TargaContext *s, const uint8_t *src, int src_size, 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 const uint8_t *src_end = src + src_size; 00049 00050 diff = stride - w * depth; 00051 x = y = 0; 00052 while(y < h){ 00053 CHECK_BUFFER_SIZE(src, src_end, 1, "image type"); 00054 type = *src++; 00055 count = (type & 0x7F) + 1; 00056 type &= 0x80; 00057 if((x + count > w) && (x + count + 1 > (h - y) * w)){ 00058 av_log(avctx, AV_LOG_ERROR, "Packet went out of bounds: position (%i,%i) size %i\n", x, y, count); 00059 return -1; 00060 } 00061 if(type){ 00062 CHECK_BUFFER_SIZE(src, src_end, depth, "image data"); 00063 }else{ 00064 CHECK_BUFFER_SIZE(src, src_end, count * depth, "image data"); 00065 } 00066 for(i = 0; i < count; i++){ 00067 switch(depth){ 00068 case 1: 00069 *dst = *src; 00070 break; 00071 case 2: 00072 *((uint16_t*)dst) = AV_RL16(src); 00073 break; 00074 case 3: 00075 dst[0] = src[0]; 00076 dst[1] = src[1]; 00077 dst[2] = src[2]; 00078 break; 00079 case 4: 00080 *((uint32_t*)dst) = AV_RL32(src); 00081 break; 00082 } 00083 dst += depth; 00084 if(!type) 00085 src += depth; 00086 00087 x++; 00088 if(x == w){ 00089 x = 0; 00090 y++; 00091 dst += diff; 00092 } 00093 } 00094 if(type) 00095 src += depth; 00096 } 00097 return src_size; 00098 } 00099 00100 static int decode_frame(AVCodecContext *avctx, 00101 void *data, int *data_size, 00102 AVPacket *avpkt) 00103 { 00104 const uint8_t *buf = avpkt->data; 00105 const uint8_t *buf_end = avpkt->data + avpkt->size; 00106 TargaContext * const s = avctx->priv_data; 00107 AVFrame *picture = data; 00108 AVFrame * const p= (AVFrame*)&s->picture; 00109 uint8_t *dst; 00110 int stride; 00111 int idlen, compr, y, w, h, bpp, flags; 00112 int first_clr, colors, csize; 00113 00114 /* parse image header */ 00115 CHECK_BUFFER_SIZE(buf, buf_end, 18, "header"); 00116 idlen = *buf++; 00117 buf++; /* pal */ 00118 compr = *buf++; 00119 first_clr = AV_RL16(buf); buf += 2; 00120 colors = AV_RL16(buf); buf += 2; 00121 csize = *buf++; 00122 buf += 2; /* x */ 00123 y = AV_RL16(buf); buf += 2; 00124 w = AV_RL16(buf); buf += 2; 00125 h = AV_RL16(buf); buf += 2; 00126 bpp = *buf++; 00127 flags = *buf++; 00128 //skip identifier if any 00129 CHECK_BUFFER_SIZE(buf, buf_end, idlen, "identifiers"); 00130 buf += idlen; 00131 s->bpp = bpp; 00132 s->width = w; 00133 s->height = h; 00134 switch(s->bpp){ 00135 case 8: 00136 avctx->pix_fmt = ((compr & (~TGA_RLE)) == TGA_BW) ? PIX_FMT_GRAY8 : PIX_FMT_PAL8; 00137 break; 00138 case 15: 00139 avctx->pix_fmt = PIX_FMT_RGB555; 00140 break; 00141 case 16: 00142 avctx->pix_fmt = PIX_FMT_RGB555; 00143 break; 00144 case 24: 00145 avctx->pix_fmt = PIX_FMT_BGR24; 00146 break; 00147 case 32: 00148 avctx->pix_fmt = PIX_FMT_RGB32; 00149 break; 00150 default: 00151 av_log(avctx, AV_LOG_ERROR, "Bit depth %i is not supported\n", s->bpp); 00152 return -1; 00153 } 00154 00155 if(s->picture.data[0]) 00156 avctx->release_buffer(avctx, &s->picture); 00157 00158 if(av_image_check_size(w, h, 0, avctx)) 00159 return -1; 00160 if(w != avctx->width || h != avctx->height) 00161 avcodec_set_dimensions(avctx, w, h); 00162 if(avctx->get_buffer(avctx, p) < 0){ 00163 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00164 return -1; 00165 } 00166 if(flags & 0x20){ 00167 dst = p->data[0]; 00168 stride = p->linesize[0]; 00169 }else{ //image is upside-down 00170 dst = p->data[0] + p->linesize[0] * (h - 1); 00171 stride = -p->linesize[0]; 00172 } 00173 00174 if(colors){ 00175 size_t pal_size; 00176 if((colors + first_clr) > 256){ 00177 av_log(avctx, AV_LOG_ERROR, "Incorrect palette: %i colors with offset %i\n", colors, first_clr); 00178 return -1; 00179 } 00180 if(csize != 24){ 00181 av_log(avctx, AV_LOG_ERROR, "Palette entry size %i bits is not supported\n", csize); 00182 return -1; 00183 } 00184 pal_size = colors * ((csize + 1) >> 3); 00185 CHECK_BUFFER_SIZE(buf, buf_end, pal_size, "color table"); 00186 if(avctx->pix_fmt != PIX_FMT_PAL8)//should not occur but skip palette anyway 00187 buf += pal_size; 00188 else{ 00189 int r, g, b, t; 00190 int32_t *pal = ((int32_t*)p->data[1]) + first_clr; 00191 for(t = 0; t < colors; t++){ 00192 r = *buf++; 00193 g = *buf++; 00194 b = *buf++; 00195 *pal++ = (b << 16) | (g << 8) | r; 00196 } 00197 p->palette_has_changed = 1; 00198 } 00199 } 00200 if((compr & (~TGA_RLE)) == TGA_NODATA) 00201 memset(p->data[0], 0, p->linesize[0] * s->height); 00202 else{ 00203 if(compr & TGA_RLE){ 00204 int res = targa_decode_rle(avctx, s, buf, buf_end - buf, dst, avctx->width, avctx->height, stride, bpp); 00205 if (res < 0) 00206 return -1; 00207 buf += res; 00208 }else{ 00209 size_t img_size = s->width * ((s->bpp + 1) >> 3); 00210 CHECK_BUFFER_SIZE(buf, buf_end, img_size, "image data"); 00211 for(y = 0; y < s->height; y++){ 00212 #if HAVE_BIGENDIAN 00213 int x; 00214 if((s->bpp + 1) >> 3 == 2){ 00215 uint16_t *dst16 = (uint16_t*)dst; 00216 for(x = 0; x < s->width; x++) 00217 dst16[x] = AV_RL16(buf + x * 2); 00218 }else if((s->bpp + 1) >> 3 == 4){ 00219 uint32_t *dst32 = (uint32_t*)dst; 00220 for(x = 0; x < s->width; x++) 00221 dst32[x] = AV_RL32(buf + x * 4); 00222 }else 00223 #endif 00224 memcpy(dst, buf, img_size); 00225 00226 dst += stride; 00227 buf += img_size; 00228 } 00229 } 00230 } 00231 00232 *picture= *(AVFrame*)&s->picture; 00233 *data_size = sizeof(AVPicture); 00234 00235 return avpkt->size; 00236 } 00237 00238 static av_cold int targa_init(AVCodecContext *avctx){ 00239 TargaContext *s = avctx->priv_data; 00240 00241 avcodec_get_frame_defaults((AVFrame*)&s->picture); 00242 avctx->coded_frame= (AVFrame*)&s->picture; 00243 00244 return 0; 00245 } 00246 00247 static av_cold int targa_end(AVCodecContext *avctx){ 00248 TargaContext *s = avctx->priv_data; 00249 00250 if(s->picture.data[0]) 00251 avctx->release_buffer(avctx, &s->picture); 00252 00253 return 0; 00254 } 00255 00256 AVCodec ff_targa_decoder = { 00257 "targa", 00258 AVMEDIA_TYPE_VIDEO, 00259 CODEC_ID_TARGA, 00260 sizeof(TargaContext), 00261 targa_init, 00262 NULL, 00263 targa_end, 00264 decode_frame, 00265 CODEC_CAP_DR1, 00266 NULL, 00267 .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), 00268 };