@ -43,22 +43,12 @@ enum SAudFlags {
} ;
typedef struct SmackerContext {
/* Smacker file header */
uint32_t magic ;
uint32_t width , height ;
uint32_t frames ;
int pts_inc ;
uint32_t flags ;
uint32_t audio [ 7 ] ;
uint32_t treesize ;
uint32_t pad ;
/* frame info */
uint32_t * frm_size ;
uint8_t * frm_flags ;
/* internal variables */
int cur_frame ;
int is_ver4 ;
int64_t cur_pts ;
/* current frame for demuxing */
uint8_t pal [ 768 ] ;
int indexes [ 7 ] ;
@ -106,34 +96,36 @@ static int smacker_read_header(AVFormatContext *s)
AVIOContext * pb = s - > pb ;
SmackerContext * smk = s - > priv_data ;
AVStream * st ;
int i , ret ;
uint32_t magic , width , height , flags , treesize ;
int i , ret , pts_inc ;
int tbase ;
/* read and check header */
smk - > magic = avio_rl32 ( pb ) ;
if ( smk - > magic ! = MKTAG ( ' S ' , ' M ' , ' K ' , ' 2 ' ) & & smk - > magic ! = MKTAG ( ' S ' , ' M ' , ' K ' , ' 4 ' ) )
magic = avio_rl32 ( pb ) ;
if ( magic ! = MKTAG ( ' S ' , ' M ' , ' K ' , ' 2 ' ) & & magic ! = MKTAG ( ' S ' , ' M ' , ' K ' , ' 4 ' ) )
return AVERROR_INVALIDDATA ;
smk - > width = avio_rl32 ( pb ) ;
smk - > height = avio_rl32 ( pb ) ;
width = avio_rl32 ( pb ) ;
height = avio_rl32 ( pb ) ;
smk - > frames = avio_rl32 ( pb ) ;
smk - > pts_inc = ( int32_t ) avio_rl32 ( pb ) ;
if ( smk - > pts_inc > INT_MAX / 100 ) {
av_log ( s , AV_LOG_ERROR , " pts_inc %d is too large \n " , smk - > pts_inc ) ;
pts_inc = avio_rl32 ( pb ) ;
if ( pts_inc > INT_MAX / 100 ) {
av_log ( s , AV_LOG_ERROR , " pts_inc %d is too large \n " , pts_inc ) ;
return AVERROR_INVALIDDATA ;
}
smk - > flags = avio_rl32 ( pb ) ;
if ( smk - > flags & SMACKER_FLAG_RING_FRAME )
flags = avio_rl32 ( pb ) ;
if ( flags & SMACKER_FLAG_RING_FRAME )
smk - > frames + + ;
if ( smk - > frames > 0xFFFFFF ) {
av_log ( s , AV_LOG_ERROR , " Too many frames: % " PRIu32 " \n " , smk - > frames ) ;
return AVERROR_INVALIDDATA ;
}
for ( i = 0 ; i < 7 ; i + + )
smk - > audio [ i ] = avio_rl32 ( pb ) ;
smk - > treesize = avio_rl32 ( pb ) ;
if ( smk - > treesize > = UINT_MAX / 4 ) { // smk->treesize + 16 must not overflow (this check is probably redundant)
avio_skip ( pb , 28 ) ; /* Unused audio related data */
treesize = avio_rl32 ( pb ) ;
if ( treesize > = UINT_MAX / 4 ) {
// treesize + 16 must not overflow (this check is probably redundant)
av_log ( s , AV_LOG_ERROR , " treesize too large \n " ) ;
return AVERROR_INVALIDDATA ;
}
@ -142,10 +134,24 @@ static int smacker_read_header(AVFormatContext *s)
if ( ! st )
return AVERROR ( ENOMEM ) ;
if ( ( ret = ff_alloc_extradata ( st - > codecpar , smk - > treesize + 16 ) ) < 0 ) {
/* Smacker uses 100000 as internal timebase */
if ( pts_inc < 0 )
pts_inc = - pts_inc ;
else
pts_inc * = 100 ;
tbase = 100000 ;
av_reduce ( & tbase , & pts_inc , tbase , pts_inc , ( 1UL < < 31 ) - 1 ) ;
avpriv_set_pts_info ( st , 33 , pts_inc , tbase ) ;
/* init video codec */
st - > codecpar - > width = width ;
st - > codecpar - > height = height ;
st - > codecpar - > codec_tag = magic ;
if ( ( ret = ff_alloc_extradata ( st - > codecpar , treesize + 16 ) ) < 0 ) {
av_log ( s , AV_LOG_ERROR ,
" Cannot allocate % " PRIu32 " bytes of extradata \n " ,
smk - > treesize + 16 ) ;
treesize + 16 ) ;
return ret ;
}
if ( ( ret = ffio_read_size ( pb , st - > codecpar - > extradata , 16 ) ) < 0 )
@ -191,7 +197,7 @@ static int smacker_read_header(AVFormatContext *s)
* ast - > codecpar - > channels * ast - > codecpar - > bits_per_coded_sample / 8 ) ;
}
}
smk - > pad = avio_rl32 ( pb ) ;
avio_rl32 ( pb ) ; /* padding */
/* setup data */
smk - > frm_size = av_malloc_array ( smk - > frames , sizeof ( * smk - > frm_size ) ) ;
smk - > frm_flags = av_malloc ( smk - > frames ) ;
@ -201,8 +207,6 @@ static int smacker_read_header(AVFormatContext *s)
return AVERROR ( ENOMEM ) ;
}
smk - > is_ver4 = ( smk - > magic ! = MKTAG ( ' S ' , ' M ' , ' K ' , ' 2 ' ) ) ;
/* read frame info */
for ( i = 0 ; i < smk - > frames ; i + + ) {
smk - > frm_size [ i ] = avio_rl32 ( pb ) ;
@ -211,22 +215,10 @@ static int smacker_read_header(AVFormatContext *s)
smk - > frm_flags [ i ] = avio_r8 ( pb ) ;
}
/* init video codec */
smk - > videoindex = st - > index ;
st - > codecpar - > width = smk - > width ;
st - > codecpar - > height = smk - > height ;
st - > codecpar - > format = AV_PIX_FMT_PAL8 ;
st - > codecpar - > codec_type = AVMEDIA_TYPE_VIDEO ;
st - > codecpar - > codec_id = AV_CODEC_ID_SMACKVIDEO ;
st - > codecpar - > codec_tag = smk - > magic ;
/* Smacker uses 100000 as internal timebase */
if ( smk - > pts_inc < 0 )
smk - > pts_inc = - smk - > pts_inc ;
else
smk - > pts_inc * = 100 ;
tbase = 100000 ;
av_reduce ( & tbase , & smk - > pts_inc , tbase , smk - > pts_inc , ( 1UL < < 31 ) - 1 ) ;
avpriv_set_pts_info ( st , 33 , smk - > pts_inc , tbase ) ;
st - > duration = smk - > frames ;
/* load trees to extradata, they will be unpacked by decoder */