@ -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 > ( 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 ( type ) {
CHECK_BUFFER_SIZE ( src , src_end , depth , " image data " ) ;
} else {
CHECK_BUFFER_SIZE ( src , src_end , count * depth , " image data " ) ;
av_log ( avctx , AV_LOG_ERROR ,
" Packet went out of bounds: position (%i,%i) size %i \n " ,
x , y , count ) ;
return AVERROR_INVALIDDATA ;
}
for ( i = 0 ; i < count ; i + + ) {
switch ( depth ) {
case 1 :
* dst = * src ;
break ;
case 2 :
AV_WN16A ( dst , AV_RN16A ( src ) ) ;
break ;
case 3 :
dst [ 0 ] = src [ 0 ] ;
dst [ 1 ] = src [ 1 ] ;
dst [ 2 ] = src [ 2 ] ;
break ;
case 4 :
AV_WN32A ( dst , AV_RN32A ( 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,32 +105,38 @@ static int decode_frame(AVCodecContext *avctx,
int idlen , pal , 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 + + ;
pal = * buf + + ;
compr = * buf + + ;
first_clr = bytestream_get_le16 ( & buf ) ;
colors = bytestream_get_le16 ( & buf ) ;
csize = * buf + + ;
idlen = bytestream2_get_byte ( & s - > gb ) ;
pal = bytestream2_get_byte ( & s - > gb ) ;
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 ) ;
if ( bytestream2_get_bytes_left ( & s - > gb ) < = idlen ) {
av_log ( avctx , AV_LOG_ERROR ,
" Not enough data to read header \n " ) ;
return AVERROR_INVALIDDATA ;
}
flags = bytestream2_get_byte ( & s - > gb ) ;
if ( ! pal & & ( first_clr | | colors | | csize ) ) {
av_log ( avctx , AV_LOG_WARNING , " File without colormap has colormap information set. \n " ) ;
// specification says we should ignore those value in this case
first_clr = colors = csize = 0 ;
}
buf + = 2 ; /* x */
y = bytestream_get_le16 ( & buf ) ;
w = bytestream_get_le16 ( & buf ) ;
h = bytestream_get_le16 ( & buf ) ;
bpp = * buf + + ;
flags = * buf + + ;
// 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 ;
@ -152,7 +151,7 @@ static int decode_frame(AVCodecContext *avctx,
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 ;
}
@ -190,23 +189,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 + + = ( 0xffU < < 24 ) | bytestream_get_le24 ( & buf ) ;
* pal + + = ( 0xffU < < 24 ) | 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 ) ;
@ -219,44 +222,45 @@ 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 * s - > height , " image data " ) ;
for ( y = 0 ; y < s - > height ; y + + ) {
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 ;
}
}
}
if ( flags & 0x10 ) { // right-to-left, needs horizontal flip
int x ;
for ( y = 0 ; y < s - > height ; y + + ) {
for ( y = 0 ; y < h ; y + + ) {
void * line = & p - > data [ 0 ] [ y * p - > linesize [ 0 ] ] ;
for ( x = 0 ; x < s - > width > > 1 ; x + + ) {
switch ( s - > bpp ) {
for ( x = 0 ; x < w > > 1 ; x + + ) {
switch ( bpp ) {
case 32 :
FFSWAP ( uint32_t , ( ( uint32_t * ) line ) [ x ] , ( ( uint32_t * ) line ) [ s - > width - x - 1 ] ) ;
FFSWAP ( uint32_t , ( ( uint32_t * ) line ) [ x ] , ( ( uint32_t * ) line ) [ w - x - 1 ] ) ;
break ;
case 24 :
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ 3 * x ] , ( ( uint8_t * ) line ) [ 3 * s - > width - 3 * x - 3 ] ) ;
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ 3 * x + 1 ] , ( ( uint8_t * ) line ) [ 3 * s - > width - 3 * x - 2 ] ) ;
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ 3 * x + 2 ] , ( ( uint8_t * ) line ) [ 3 * s - > width - 3 * x - 1 ] ) ;
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ 3 * x ] , ( ( uint8_t * ) line ) [ 3 * w - 3 * x - 3 ] ) ;
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ 3 * x + 1 ] , ( ( uint8_t * ) line ) [ 3 * w - 3 * x - 2 ] ) ;
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ 3 * x + 2 ] , ( ( uint8_t * ) line ) [ 3 * w - 3 * x - 1 ] ) ;
break ;
case 16 :
FFSWAP ( uint16_t , ( ( uint16_t * ) line ) [ x ] , ( ( uint16_t * ) line ) [ s - > width - x - 1 ] ) ;
FFSWAP ( uint16_t , ( ( uint16_t * ) line ) [ x ] , ( ( uint16_t * ) line ) [ w - x - 1 ] ) ;
break ;
case 8 :
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ x ] , ( ( uint8_t * ) line ) [ s - > width - x - 1 ] ) ;
FFSWAP ( uint8_t , ( ( uint8_t * ) line ) [ x ] , ( ( uint8_t * ) line ) [ w - x - 1 ] ) ;
}
}
}