@ -27,83 +27,76 @@
typedef struct TargaContext {
AVFrame picture ;
GetByteContext gb ;
int width , height ;
int bpp ;
int color_type ;
int compression_type ;
} TargaContext ;
# define CHECK_BUFFER_SIZE(buf, buf_end, needed, where) \
if ( needed > buf_end - buf ) { \
av_log ( avctx , AV_LOG_ERROR , " Problem: unexpected end of data while reading " where " \n " ) ; \
return - 1 ; \
} \
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 )
static int targa_decode_rle ( AVCodecContext * avctx , TargaContext * s ,
uint8_t * dst , int w , int h , int stride , int bpp )
{
int i , x , y ;
int x , y ;
int depth = ( bpp + 1 ) > > 3 ;
int type , count ;
int diff ;
const uint8_t * src_end = src + src_size ;
diff = stride - w * depth ;
x = y = 0 ;
while ( y < h ) {
CHECK_BUFFER_SIZE ( src , src_end , 1 , " image type " ) ;
type = * src + + ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < = 0 ) {
av_log ( avctx , AV_LOG_ERROR ,
" Ran ouf of data before end-of-image \n " ) ;
return AVERROR_INVALIDDATA ;
}
type = bytestream2_get_byteu ( & s - > gb ) ;
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 - 1 ;
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 AVERROR_INVALIDDATA ;
}
if ( type ) {
CHECK_BUFFER_SIZE ( src , src_end , depth , " image data " ) ;
} else {
CHECK_BUFFER_SIZE ( src , src_end , count * depth , " image data " ) ;
}
for ( i = 0 ; i < count ; i + + ) {
switch ( depth ) {
case 1 :
* dst = * src ;
break ;
case 2 :
* ( ( uint16_t * ) dst ) = AV_RL16 ( src ) ;
break ;
case 3 :
dst [ 0 ] = src [ 0 ] ;
dst [ 1 ] = src [ 1 ] ;
dst [ 2 ] = src [ 2 ] ;
break ;
case 4 :
* ( ( uint32_t * ) dst ) = AV_RL32 ( src ) ;
break ;
if ( ! type ) {
do {
int n = FFMIN ( count , w - x ) ;
bytestream2_get_buffer ( & s - > gb , dst , n * depth ) ;
count - = n ;
dst + = n * depth ;
x + = n ;
if ( x = = w ) {
x = 0 ;
y + + ;
dst + = diff ;
}
} while ( count > 0 ) ;
} else {
uint8_t tmp [ 4 ] ;
bytestream2_get_buffer ( & s - > gb , tmp , depth ) ;
do {
int n = FFMIN ( count , w - x ) ;
count - = n ;
x + = n ;
do {
memcpy ( dst , tmp , depth ) ;
dst + = depth ;
if ( ! type )
src + = depth ;
x + + ;
} while ( - - n ) ;
if ( x = = w ) {
x = 0 ;
y + + ;
dst + = diff ;
}
} while ( count > 0 ) ;
}
if ( type )
src + = depth ;
}
return src_size ;
return 0 ;
}
static int decode_frame ( AVCodecContext * avctx ,
void * data , int * data_size ,
AVPacket * avpkt )
{
const uint8_t * buf = avpkt - > data ;
const uint8_t * buf_end = avpkt - > data + avpkt - > size ;
TargaContext * const s = avctx - > priv_data ;
AVFrame * picture = data ;
AVFrame * const p = & s - > picture ;
@ -112,44 +105,41 @@ static int decode_frame(AVCodecContext *avctx,
int idlen , compr , y , w , h , bpp , flags ;
int first_clr , colors , csize ;
bytestream2_init ( & s - > gb , avpkt - > data , avpkt - > size ) ;
/* parse image header */
CHECK_BUFFER_SIZE ( buf , buf_end , 18 , " header " ) ;
idlen = * buf + + ;
buf + + ; /* pal */
compr = * buf + + ;
first_clr = AV_RL16 ( buf ) ; buf + = 2 ;
colors = AV_RL16 ( buf ) ; buf + = 2 ;
csize = * buf + + ;
buf + = 2 ; /* x */
y = AV_RL16 ( buf ) ; buf + = 2 ;
w = AV_RL16 ( buf ) ; buf + = 2 ;
h = AV_RL16 ( buf ) ; buf + = 2 ;
bpp = * buf + + ;
flags = * buf + + ;
idlen = bytestream2_get_byte ( & s - > gb ) ;
bytestream2_skip ( & s - > gb , 1 ) ; /* pal */
compr = bytestream2_get_byte ( & s - > gb ) ;
first_clr = bytestream2_get_le16 ( & s - > gb ) ;
colors = bytestream2_get_le16 ( & s - > gb ) ;
csize = bytestream2_get_byte ( & s - > gb ) ;
bytestream2_skip ( & s - > gb , 4 ) ; /* 2: x, 2: y */
w = bytestream2_get_le16 ( & s - > gb ) ;
h = bytestream2_get_le16 ( & s - > gb ) ;
bpp = bytestream2_get_byte ( & s - > gb ) ;
flags = bytestream2_get_byte ( & s - > gb ) ;
// skip identifier if any
CHECK_BUFFER_SIZE ( buf , buf_end , idlen , " identifiers " ) ;
buf + = idlen ;
s - > bpp = bpp ;
s - > width = w ;
s - > height = h ;
switch ( s - > bpp ) {
bytestream2_skip ( & s - > gb , idlen ) ;
switch ( 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 ;
avctx - > pix_fmt = PIX_FMT_RGB555LE ;
break ;
case 16 :
avctx - > pix_fmt = PIX_FMT_RGB555 ;
avctx - > pix_fmt = PIX_FMT_RGB555LE ;
break ;
case 24 :
avctx - > pix_fmt = PIX_FMT_BGR24 ;
break ;
case 32 :
avctx - > pix_fmt = PIX_FMT_RGB32 ;
avctx - > pix_fmt = PIX_FMT_BGRA ;
break ;
default :
av_log ( avctx , AV_LOG_ERROR , " Bit depth %i is not supported \n " , s - > bpp ) ;
av_log ( avctx , AV_LOG_ERROR , " Bit depth %i is not supported \n " , bpp ) ;
return - 1 ;
}
@ -187,23 +177,27 @@ static int decode_frame(AVCodecContext *avctx,
return - 1 ;
}
pal_size = colors * pal_sample_size ;
CHECK_BUFFER_SIZE ( buf , buf_end , pal_size , " color table " ) ;
if ( avctx - > pix_fmt ! = PIX_FMT_PAL8 ) //should not occur but skip palette anyway
buf + = pal_size ;
bytestream2_skip ( & s - > gb , pal_size ) ;
else {
int t ;
uint32_t * pal = ( ( uint32_t * ) p - > data [ 1 ] ) + first_clr ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < pal_size ) {
av_log ( avctx , AV_LOG_ERROR ,
" Not enough data to read palette \n " ) ;
return AVERROR_INVALIDDATA ;
}
switch ( pal_sample_size ) {
case 3 :
/* RGB24 */
for ( t = 0 ; t < colors ; t + + )
* pal + + = bytestream_get_le24 ( & buf ) ;
* pal + + = bytestream2 _get_le24u ( & s - > g b) ;
break ;
case 2 :
/* RGB555 */
for ( t = 0 ; t < colors ; t + + ) {
uint32_t v = bytestream_get_le16 ( & buf ) ;
uint32_t v = bytestream2 _get_le16u ( & s - > g b) ;
v = ( ( v & 0x7C00 ) < < 9 ) |
( ( v & 0x03E0 ) < < 6 ) |
( ( v & 0x001F ) < < 3 ) ;
@ -216,34 +210,23 @@ static int decode_frame(AVCodecContext *avctx,
p - > palette_has_changed = 1 ;
}
}
if ( ( compr & ( ~ TGA_RLE ) ) = = TGA_NODATA )
memset ( p - > data [ 0 ] , 0 , p - > linesize [ 0 ] * s - > height ) ;
else {
if ( ( compr & ( ~ TGA_RLE ) ) = = TGA_NODATA ) {
memset ( p - > data [ 0 ] , 0 , p - > linesize [ 0 ] * h ) ;
} else {
if ( compr & TGA_RLE ) {
int res = targa_decode_rle ( avctx , s , buf , buf_end - buf , dst , avctx - > width , avctx - > height , stride , bpp ) ;
int res = targa_decode_rle ( avctx , s , dst , w , h , stride , bpp ) ;
if ( res < 0 )
return - 1 ;
buf + = res ;
return res ;
} else {
size_t img_size = s - > width * ( ( s - > bpp + 1 ) > > 3 ) ;
CHECK_BUFFER_SIZE ( buf , buf_end , img_size , " image data " ) ;
for ( y = 0 ; y < s - > height ; y + + ) {
# if HAVE_BIGENDIAN
int x ;
if ( ( s - > bpp + 1 ) > > 3 = = 2 ) {
uint16_t * dst16 = ( uint16_t * ) dst ;
for ( x = 0 ; x < s - > width ; x + + )
dst16 [ x ] = AV_RL16 ( buf + x * 2 ) ;
} else if ( ( s - > bpp + 1 ) > > 3 = = 4 ) {
uint32_t * dst32 = ( uint32_t * ) dst ;
for ( x = 0 ; x < s - > width ; x + + )
dst32 [ x ] = AV_RL32 ( buf + x * 4 ) ;
} else
# endif
memcpy ( dst , buf , img_size ) ;
size_t img_size = w * ( ( bpp + 1 ) > > 3 ) ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < img_size * h ) {
av_log ( avctx , AV_LOG_ERROR ,
" Not enough data available for image \n " ) ;
return AVERROR_INVALIDDATA ;
}
for ( y = 0 ; y < h ; y + + ) {
bytestream2_get_bufferu ( & s - > gb , dst , img_size ) ;
dst + = stride ;
buf + = img_size ;
}
}
}