@ -25,25 +25,17 @@
# include "decode.h"
# include "sgi.h"
typedef struct SgiState {
AVCodecContext * avctx ;
unsigned int width ;
int height ;
unsigned int depth ;
unsigned int bytes_per_channel ;
int linesize ;
GetByteContext g ;
} SgiState ;
/**
* Expand an RLE row into a channel .
* @ param s the current image state
* @ param logctx a logcontext
* @ param out_buf Points to one line after the output buffer .
* @ param g GetByteContext used to read input from
* @ param len length of out_buf in bytes
* @ param pixelstride pixel stride of input buffer
* @ return size of output in bytes , else return error code .
*/
static int expand_rle_row8 ( SgiState * s , uint8_t * out_buf ,
static int expand_rle_row8 ( void * logctx , uint8_t * out_buf ,
GetByteContext * g ,
int len , int pixelstride )
{
unsigned char pixel , count ;
@ -51,26 +43,26 @@ static int expand_rle_row8(SgiState *s, uint8_t *out_buf,
uint8_t * out_end = out_buf + len ;
while ( out_buf < out_end ) {
if ( bytestream2_get_bytes_left ( & s - > g ) < 1 )
if ( bytestream2_get_bytes_left ( g ) < 1 )
return AVERROR_INVALIDDATA ;
pixel = bytestream2_get_byteu ( & s - > g ) ;
pixel = bytestream2_get_byteu ( g ) ;
if ( ! ( count = ( pixel & 0x7f ) ) ) {
break ;
}
/* Check for buffer overflow. */
if ( out_end - out_buf < = pixelstride * ( count - 1 ) ) {
av_log ( s - > av ctx, AV_LOG_ERROR , " Invalid pixel count. \n " ) ;
av_log ( log ctx, AV_LOG_ERROR , " Invalid pixel count. \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( pixel & 0x80 ) {
while ( count - - ) {
* out_buf = bytestream2_get_byte ( & s - > g ) ;
* out_buf = bytestream2_get_byte ( g ) ;
out_buf + = pixelstride ;
}
} else {
pixel = bytestream2_get_byte ( & s - > g ) ;
pixel = bytestream2_get_byte ( g ) ;
while ( count - - ) {
* out_buf = pixel ;
@ -81,7 +73,8 @@ static int expand_rle_row8(SgiState *s, uint8_t *out_buf,
return ( out_buf - orig ) / pixelstride ;
}
static int expand_rle_row16 ( SgiState * s , uint16_t * out_buf ,
static int expand_rle_row16 ( void * logctx , uint16_t * out_buf ,
GetByteContext * g ,
int len , int pixelstride )
{
unsigned short pixel ;
@ -90,26 +83,26 @@ static int expand_rle_row16(SgiState *s, uint16_t *out_buf,
uint16_t * out_end = out_buf + len ;
while ( out_buf < out_end ) {
if ( bytestream2_get_bytes_left ( & s - > g ) < 2 )
if ( bytestream2_get_bytes_left ( g ) < 2 )
return AVERROR_INVALIDDATA ;
pixel = bytestream2_get_be16u ( & s - > g ) ;
pixel = bytestream2_get_be16u ( g ) ;
if ( ! ( count = ( pixel & 0x7f ) ) )
break ;
/* Check for buffer overflow. */
if ( out_end - out_buf < = pixelstride * ( count - 1 ) ) {
av_log ( s - > av ctx, AV_LOG_ERROR , " Invalid pixel count. \n " ) ;
av_log ( log ctx, AV_LOG_ERROR , " Invalid pixel count. \n " ) ;
return AVERROR_INVALIDDATA ;
}
if ( pixel & 0x80 ) {
while ( count - - ) {
pixel = bytestream2_get_ne16 ( & s - > g ) ;
pixel = bytestream2_get_ne16 ( g ) ;
AV_WN16A ( out_buf , pixel ) ;
out_buf + = pixelstride ;
}
} else {
pixel = bytestream2_get_ne16 ( & s - > g ) ;
pixel = bytestream2_get_ne16 ( g ) ;
while ( count - - ) {
AV_WN16A ( out_buf , pixel ) ;
@ -127,34 +120,38 @@ static int expand_rle_row16(SgiState *s, uint16_t *out_buf,
* @ param s the current image state
* @ return 0 if no error , else return error code .
*/
static int read_rle_sgi ( uint8_t * last_line , SgiState * s )
static int read_rle_sgi ( void * logctx , uint8_t * last_line , GetByteContext * g ,
ptrdiff_t stride , unsigned width , unsigned height ,
unsigned nb_components , unsigned bytes_per_channel )
{
uint8_t * dest_row ;
unsigned int len = s - > height * s - > depth * 4 ;
GetByteContext g_table = s - > g ;
unsigned int len = height * nb_components * 4 ;
GetByteContext g_table = * g ;
unsigned int start_offset ;
int linesize , ret ;
/* size of RLE offset and length tables */
if ( len * 2 > bytestream2_get_bytes_left ( & s - > g ) ) {
if ( len * 2 > bytestream2_get_bytes_left ( g ) ) {
return AVERROR_INVALIDDATA ;
}
for ( unsigned z = 0 ; z < s - > depth ; z + + ) {
for ( unsigned z = 0 ; z < nb_components ; z + + ) {
dest_row = last_line ;
for ( int remaining_lines = s - > height ; ; ) {
linesize = s - > width * s - > depth ;
for ( unsigned remaining_lines = height ; ; ) {
linesize = width * nb_components ;
start_offset = bytestream2_get_be32 ( & g_table ) ;
bytestream2_seek ( & s - > g , start_offset , SEEK_SET ) ;
if ( s - > bytes_per_channel = = 1 )
ret = expand_rle_row8 ( s , dest_row + z , linesize , s - > depth ) ;
bytestream2_seek ( g , start_offset , SEEK_SET ) ;
if ( bytes_per_channel = = 1 )
ret = expand_rle_row8 ( logctx , dest_row + z , g ,
linesize , nb_components ) ;
else
ret = expand_rle_row16 ( s , ( uint16_t * ) dest_row + z , linesize , s - > depth ) ;
if ( ret ! = s - > width )
ret = expand_rle_row16 ( logctx , ( uint16_t * ) dest_row + z , g ,
linesize , nb_components ) ;
if ( ret ! = width )
return AVERROR_INVALIDDATA ;
if ( - - remaining_lines = = 0 )
break ;
dest_row - = s - > linesiz e;
dest_row - = strid e ;
}
}
return 0 ;
@ -166,33 +163,34 @@ static int read_rle_sgi(uint8_t *last_line, SgiState *s)
* @ param s the current image state
* @ return 0 if read success , else return error code .
*/
static int read_uncompressed_sgi ( unsigned char * out_buf , SgiState * s )
static int read_uncompressed_sgi ( unsigned char * out_buf , GetByteContext * g ,
ptrdiff_t stride , unsigned width , unsigned height ,
unsigned nb_components , unsigned bytes_per_channel )
{
int x , y , z ;
unsigned int offset = s - > height * s - > width * s - > bytes_per_channel ;
unsigned int offset = height * width * bytes_per_channel ;
GetByteContext gp [ 4 ] ;
uint8_t * out_end ;
/* Test buffer size. */
if ( offset * s - > depth > bytestream2_get_bytes_left ( & s - > g ) )
if ( offset * nb_components > bytestream2_get_bytes_left ( g ) )
return AVERROR_INVALIDDATA ;
/* Create a reader for each plane */
for ( z = 0 ; z < s - > depth ; z + + ) {
gp [ z ] = s - > g ;
for ( unsigned z = 0 ; z < nb_components ; z + + ) {
gp [ z ] = * g ;
bytestream2_skip ( & gp [ z ] , z * offset ) ;
}
for ( y = s - > height - 1 ; y > = 0 ; y - - ) {
out_end = out_buf + ( y * s - > linesize ) ;
if ( s - > bytes_per_channel = = 1 ) {
for ( x = s - > width ; x > 0 ; x - - )
for ( z = 0 ; z < s - > depth ; z + + )
for ( int y = height - 1 ; y > = 0 ; y - - ) {
out_end = out_buf + y * stride ;
if ( bytes_per_channel = = 1 ) {
for ( unsigned x = width ; x > 0 ; x - - )
for ( unsigned z = 0 ; z < nb_components ; z + + )
* out_end + + = bytestream2_get_byteu ( & gp [ z ] ) ;
} else {
uint16_t * out16 = ( uint16_t * ) out_end ;
for ( x = s - > width ; x > 0 ; x - - )
for ( z = 0 ; z < s - > depth ; z + + )
for ( unsigned x = width ; x > 0 ; x - - )
for ( unsigned z = 0 ; z < nb_components ; z + + )
* out16 + + = bytestream2_get_ne16u ( & gp [ z ] ) ;
}
}
@ -202,31 +200,32 @@ static int read_uncompressed_sgi(unsigned char *out_buf, SgiState *s)
static int decode_frame ( AVCodecContext * avctx , AVFrame * p ,
int * got_frame , AVPacket * avpkt )
{
SgiState * s = avctx - > priv_data ;
unsigned int dimension , rle ;
GetByteContext g ;
unsigned int bytes_per_channel , nb_components , dimension , rle , width ;
int height ;
int ret = 0 ;
uint8_t * out_buf , * last_line ;
bytestream2_init ( & s - > g , avpkt - > data , avpkt - > size ) ;
if ( bytestream2_get_bytes_left ( & s - > g ) < SGI_HEADER_SIZE ) {
bytestream2_init ( & g , avpkt - > data , avpkt - > size ) ;
if ( bytestream2_get_bytes_left ( & g ) < SGI_HEADER_SIZE ) {
av_log ( avctx , AV_LOG_ERROR , " buf_size too small (%d) \n " , avpkt - > size ) ;
return AVERROR_INVALIDDATA ;
}
/* Test for SGI magic. */
if ( bytestream2_get_be16u ( & s - > g ) ! = SGI_MAGIC ) {
if ( bytestream2_get_be16u ( & g ) ! = SGI_MAGIC ) {
av_log ( avctx , AV_LOG_ERROR , " bad magic number \n " ) ;
return AVERROR_INVALIDDATA ;
}
rle = bytestream2_get_byteu ( & s - > g ) ;
s - > bytes_per_channel = bytestream2_get_byteu ( & s - > g ) ;
dimension = bytestream2_get_be16u ( & s - > g ) ;
s - > width = bytestream2_get_be16u ( & s - > g ) ;
s - > height = bytestream2_get_be16u ( & s - > g ) ;
s - > depth = bytestream2_get_be16u ( & s - > g ) ;
rle = bytestream2_get_byteu ( & g ) ;
bytes_per_channel = bytestream2_get_byteu ( & g ) ;
dimension = bytestream2_get_be16u ( & g ) ;
width = bytestream2_get_be16u ( & g ) ;
height = bytestream2_get_be16u ( & g ) ;
nb_components = bytestream2_get_be16u ( & g ) ;
if ( s - > bytes_per_channel ! = 1 & & s - > bytes_per_channel ! = 2 ) {
if ( bytes_per_channel ! = 1 & & bytes_per_channel ! = 2 ) {
av_log ( avctx , AV_LOG_ERROR , " wrong channel number \n " ) ;
return AVERROR_INVALIDDATA ;
}
@ -237,18 +236,18 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
return AVERROR_INVALIDDATA ;
}
if ( s - > depth = = SGI_GRAYSCALE ) {
avctx - > pix_fmt = s - > bytes_per_channel = = 2 ? AV_PIX_FMT_GRAY16BE : AV_PIX_FMT_GRAY8 ;
} else if ( s - > depth = = SGI_RGB ) {
avctx - > pix_fmt = s - > bytes_per_channel = = 2 ? AV_PIX_FMT_RGB48BE : AV_PIX_FMT_RGB24 ;
} else if ( s - > depth = = SGI_RGBA ) {
avctx - > pix_fmt = s - > bytes_per_channel = = 2 ? AV_PIX_FMT_RGBA64BE : AV_PIX_FMT_RGBA ;
if ( nb_components = = SGI_GRAYSCALE ) {
avctx - > pix_fmt = bytes_per_channel = = 2 ? AV_PIX_FMT_GRAY16BE : AV_PIX_FMT_GRAY8 ;
} else if ( nb_components = = SGI_RGB ) {
avctx - > pix_fmt = bytes_per_channel = = 2 ? AV_PIX_FMT_RGB48BE : AV_PIX_FMT_RGB24 ;
} else if ( nb_components = = SGI_RGBA ) {
avctx - > pix_fmt = bytes_per_channel = = 2 ? AV_PIX_FMT_RGBA64BE : AV_PIX_FMT_RGBA ;
} else {
av_log ( avctx , AV_LOG_ERROR , " wrong picture format \n " ) ;
return AVERROR_INVALIDDATA ;
}
ret = ff_set_dimensions ( avctx , s - > width , s - > height ) ;
ret = ff_set_dimensions ( avctx , width , height ) ;
if ( ret < 0 )
return ret ;
@ -259,16 +258,16 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
p - > key_frame = 1 ;
out_buf = p - > data [ 0 ] ;
last_line = out_buf + p - > linesize [ 0 ] * ( s - > height - 1 ) ;
s - > linesize = p - > linesize [ 0 ] ;
last_line = out_buf + p - > linesize [ 0 ] * ( height - 1 ) ;
/* Skip header. */
bytestream2_seek ( & s - > g , SGI_HEADER_SIZE , SEEK_SET ) ;
bytestream2_seek ( & g , SGI_HEADER_SIZE , SEEK_SET ) ;
if ( rle ) {
ret = read_rle_sgi ( last_line , s ) ;
ret = read_rle_sgi ( avctx , last_line , & g , p - > linesize [ 0 ] ,
width , height , nb_components , bytes_per_channel ) ;
} else {
ret = read_uncompressed_sgi ( out_buf , s ) ;
ret = read_uncompressed_sgi ( out_buf , & g , p - > linesize [ 0 ] ,
width , height , nb_components , bytes_per_channel ) ;
}
if ( ret )
return ret ;
@ -277,22 +276,11 @@ static int decode_frame(AVCodecContext *avctx, AVFrame *p,
return avpkt - > size ;
}
static av_cold int sgi_decode_init ( AVCodecContext * avctx )
{
SgiState * s = avctx - > priv_data ;
s - > avctx = avctx ;
return 0 ;
}
const FFCodec ff_sgi_decoder = {
. p . name = " sgi " ,
CODEC_LONG_NAME ( " SGI image " ) ,
. p . type = AVMEDIA_TYPE_VIDEO ,
. p . id = AV_CODEC_ID_SGI ,
. priv_data_size = sizeof ( SgiState ) ,
FF_CODEC_DECODE_CB ( decode_frame ) ,
. init = sgi_decode_init ,
. p . capabilities = AV_CODEC_CAP_DR1 ,
} ;