@ -69,28 +69,29 @@ typedef struct FlashSVContext {
AVFrame frame ;
AVFrame frame ;
int image_width , image_height ;
int image_width , image_height ;
int block_width , block_height ;
int block_width , block_height ;
uint8_t * tmpblock ;
uint8_t * tmpblock ;
uint8_t * encbuffer ;
uint8_t * encbuffer ;
int block_size ;
int block_size ;
z_stream zstream ;
z_stream zstream ;
int last_key_frame ;
int last_key_frame ;
} FlashSVContext ;
} FlashSVContext ;
static int copy_region_enc ( uint8_t * sptr , uint8_t * dptr ,
static int copy_region_enc ( uint8_t * sptr , uint8_t * dptr , int dx , int dy ,
int dx , int dy , int h , int w , int stride , uint8_t * pfptr ) {
int h , int w , int stride , uint8_t * pfptr )
int i , j ;
{
int i , j ;
uint8_t * nsptr ;
uint8_t * nsptr ;
uint8_t * npfptr ;
uint8_t * npfptr ;
int diff = 0 ;
int diff = 0 ;
for ( i = dx + h ; i > dx ; i - - ) {
for ( i = dx + h ; i > dx ; i - - ) {
nsptr = sptr + ( i * stride ) + dy * 3 ;
nsptr = sptr + ( i * stride ) + dy * 3 ;
npfptr = pfptr + ( i * stride ) + dy * 3 ;
npfptr = pfptr + ( i * stride ) + dy * 3 ;
for ( j = 0 ; j < w * 3 ; j + + ) {
for ( j = 0 ; j < w * 3 ; j + + ) {
diff | = npfptr [ j ] ^ nsptr [ j ] ;
diff | = npfptr [ j ] ^ nsptr [ j ] ;
dptr [ j ] = nsptr [ j ] ;
dptr [ j ] = nsptr [ j ] ;
}
}
dptr + = w * 3 ;
dptr + = w * 3 ;
}
}
if ( diff )
if ( diff )
return 1 ;
return 1 ;
@ -105,45 +106,47 @@ static av_cold int flashsv_encode_init(AVCodecContext *avctx)
if ( ( avctx - > width > 4095 ) | | ( avctx - > height > 4095 ) ) {
if ( ( avctx - > width > 4095 ) | | ( avctx - > height > 4095 ) ) {
av_log ( avctx , AV_LOG_ERROR , " Input dimensions too large, input must be max 4096x4096 ! \n " ) ;
av_log ( avctx , AV_LOG_ERROR , " Input dimensions too large, input must be max 4096x4096 ! \n " ) ;
return - 1 ;
return AVERROR_INVALIDDATA ;
}
}
// Needed if zlib unused or init aborted before deflateInit
// Needed if zlib unused or init aborted before deflateInit
memset ( & ( s - > zstream ) , 0 , sizeof ( z_stream ) ) ;
memset ( & ( s - > zstream ) , 0 , sizeof ( z_stream ) ) ;
s - > last_key_frame = 0 ;
s - > last_key_frame = 0 ;
s - > image_width = avctx - > width ;
s - > image_width = avctx - > width ;
s - > image_height = avctx - > height ;
s - > image_height = avctx - > height ;
s - > tmpblock = av_mallocz ( 3 * 256 * 256 ) ;
s - > tmpblock = av_mallocz ( 3 * 256 * 256 ) ;
s - > encbuffer = av_mallocz ( s - > image_width * s - > image_height * 3 ) ;
s - > encbuffer = av_mallocz ( s - > image_width * s - > image_height * 3 ) ;
if ( ! s - > tmpblock | | ! s - > encbuffer ) {
if ( ! s - > tmpblock | | ! s - > encbuffer ) {
av_log ( avctx , AV_LOG_ERROR , " Memory allocation failed. \n " ) ;
av_log ( avctx , AV_LOG_ERROR , " Memory allocation failed. \n " ) ;
return - 1 ;
return AVERROR ( ENOMEM ) ;
}
}
return 0 ;
return 0 ;
}
}
static int encode_bitstream ( FlashSVContext * s , AVFrame * p , uint8_t * buf , int buf_size ,
static int encode_bitstream ( FlashSVContext * s , AVFrame * p , uint8_t * buf ,
int block_width , int block_height , uint8_t * previous_frame , int * I_frame ) {
int buf_size , int block_width , int block_height ,
uint8_t * previous_frame , int * I_frame )
{
PutBitContext pb ;
PutBitContext pb ;
int h_blocks , v_blocks , h_part , v_part , i , j ;
int h_blocks , v_blocks , h_part , v_part , i , j ;
int buf_pos , res ;
int buf_pos , res ;
int pred_blocks = 0 ;
int pred_blocks = 0 ;
init_put_bits ( & pb , buf , buf_size * 8 ) ;
init_put_bits ( & pb , buf , buf_size * 8 ) ;
put_bits ( & pb , 4 , ( block_width / 16 ) - 1 ) ;
put_bits ( & pb , 4 , ( block_width / 16 ) - 1 ) ;
put_bits ( & pb , 12 , s - > image_width ) ;
put_bits ( & pb , 12 , s - > image_width ) ;
put_bits ( & pb , 4 , ( block_height / 16 ) - 1 ) ;
put_bits ( & pb , 4 , ( block_height / 16 ) - 1 ) ;
put_bits ( & pb , 12 , s - > image_height ) ;
put_bits ( & pb , 12 , s - > image_height ) ;
flush_put_bits ( & pb ) ;
flush_put_bits ( & pb ) ;
buf_pos = 4 ;
buf_pos = 4 ;
h_blocks = s - > image_width / block_width ;
h_blocks = s - > image_width / block_width ;
h_part = s - > image_width % block_width ;
h_part = s - > image_width % block_width ;
@ -151,41 +154,42 @@ static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf, int buf
v_part = s - > image_height % block_height ;
v_part = s - > image_height % block_height ;
/* loop over all block columns */
/* loop over all block columns */
for ( j = 0 ; j < v_blocks + ( v_part ? 1 : 0 ) ; j + + )
for ( j = 0 ; j < v_blocks + ( v_part ? 1 : 0 ) ; j + + ) {
{
int hp = j * block_height ; // horiz position in frame
int hp = j * block_height ; // horiz position in frame
int hs = ( j < v_blocks ) ? block_height : v_part ; // size of block
int hs = ( j < v_blocks ) ? block_height : v_part ; // size of block
/* loop over all block rows */
/* loop over all block rows */
for ( i = 0 ; i < h_blocks + ( h_part ? 1 : 0 ) ; i + + )
for ( i = 0 ; i < h_blocks + ( h_part ? 1 : 0 ) ; i + + ) {
{
int wp = i * block_width ; // vert position in frame
int wp = i * block_width ; // vert position in frame
int ws = ( i < h_blocks ) ? block_width : h_part ; // size of block
int ws = ( i < h_blocks ) ? block_width : h_part ; // size of block
int ret = Z_OK ;
int ret = Z_OK ;
uint8_t * ptr ;
uint8_t * ptr ;
ptr = buf + buf_pos ;
ptr = buf + buf_pos ;
//copy the block to the temp buffer before compression (if it differs from the previous frame's block)
/* copy the block to the temp buffer before compression
res = copy_region_enc ( p - > data [ 0 ] , s - > tmpblock , s - > image_height - ( hp + hs + 1 ) , wp , hs , ws , p - > linesize [ 0 ] , previous_frame ) ;
* ( if it differs from the previous frame ' s block ) */
res = copy_region_enc ( p - > data [ 0 ] , s - > tmpblock ,
s - > image_height - ( hp + hs + 1 ) ,
wp , hs , ws , p - > linesize [ 0 ] , previous_frame ) ;
if ( res | | * I_frame ) {
if ( res | | * I_frame ) {
unsigned long zsize ;
unsigned long zsize ;
zsize = 3 * block_width * block_height ;
zsize = 3 * block_width * block_height ;
ret = compress2 ( ptr + 2 , & zsize , s - > tmpblock , 3 * ws * hs , 9 ) ;
ret = compress2 ( ptr + 2 , & zsize , s - > tmpblock , 3 * ws * hs , 9 ) ;
//ret = deflateReset(&(s->zstream));
//ret = deflateReset(&(s->zstream));
if ( ret ! = Z_OK )
if ( ret ! = Z_OK )
av_log ( s - > avctx , AV_LOG_ERROR , " error while compressing block %dx%d \n " , i , j ) ;
av_log ( s - > avctx , AV_LOG_ERROR , " error while compressing block %dx%d \n " , i , j ) ;
bytestream_put_be16 ( & ptr , ( unsigned int ) zsize ) ;
bytestream_put_be16 ( & ptr , ( unsigned int ) zsize ) ;
buf_pos + = zsize + 2 ;
buf_pos + = zsize + 2 ;
//av_log(avctx, AV_LOG_ERROR, "buf_pos = %d\n", buf_pos);
//av_log(avctx, AV_LOG_ERROR, "buf_pos = %d\n", buf_pos);
} else {
} else {
pred_blocks + + ;
pred_blocks + + ;
bytestream_put_be16 ( & ptr , 0 ) ;
bytestream_put_be16 ( & ptr , 0 ) ;
buf_pos + = 2 ;
buf_pos + = 2 ;
}
}
}
}
@ -200,7 +204,8 @@ static int encode_bitstream(FlashSVContext *s, AVFrame *p, uint8_t *buf, int buf
}
}
static int flashsv_encode_frame ( AVCodecContext * avctx , uint8_t * buf , int buf_size , void * data )
static int flashsv_encode_frame ( AVCodecContext * avctx , uint8_t * buf ,
int buf_size , void * data )
{
{
FlashSVContext * const s = avctx - > priv_data ;
FlashSVContext * const s = avctx - > priv_data ;
AVFrame * pict = data ;
AVFrame * pict = data ;
@ -214,16 +219,16 @@ static int flashsv_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_siz
/* First frame needs to be a keyframe */
/* First frame needs to be a keyframe */
if ( avctx - > frame_number = = 0 ) {
if ( avctx - > frame_number = = 0 ) {
s - > previous_frame = av_mallocz ( FFABS ( p - > linesize [ 0 ] ) * s - > image_height ) ;
s - > previous_frame = av_mallocz ( FFABS ( p - > linesize [ 0 ] ) * s - > image_height ) ;
if ( ! s - > previous_frame ) {
if ( ! s - > previous_frame ) {
av_log ( avctx , AV_LOG_ERROR , " Memory allocation failed. \n " ) ;
av_log ( avctx , AV_LOG_ERROR , " Memory allocation failed. \n " ) ;
return - 1 ;
return AVERROR ( ENOMEM ) ;
}
}
I_frame = 1 ;
I_frame = 1 ;
}
}
if ( p - > linesize [ 0 ] < 0 )
if ( p - > linesize [ 0 ] < 0 )
pfptr = s - > previous_frame - ( ( s - > image_height - 1 ) * p - > linesize [ 0 ] ) ;
pfptr = s - > previous_frame - ( ( s - > image_height - 1 ) * p - > linesize [ 0 ] ) ;
else
else
pfptr = s - > previous_frame ;
pfptr = s - > previous_frame ;
@ -234,29 +239,31 @@ static int flashsv_encode_frame(AVCodecContext *avctx, uint8_t *buf, int buf_siz
}
}
}
}
opt_w = 4 ;
opt_w = 4 ;
opt_h = 4 ;
opt_h = 4 ;
if ( buf_size < s - > image_width * s - > image_height * 3 ) {
if ( buf_size < s - > image_width * s - > image_height * 3 ) {
//Conservative upper bound check for compressed data
//Conservative upper bound check for compressed data
av_log ( avctx , AV_LOG_ERROR , " buf_size %d < %d \n " , buf_size , s - > image_width * s - > image_height * 3 ) ;
av_log ( avctx , AV_LOG_ERROR , " buf_size %d < %d \n " ,
buf_size , s - > image_width * s - > image_height * 3 ) ;
return - 1 ;
return - 1 ;
}
}
res = encode_bitstream ( s , p , buf , buf_size , opt_w * 16 , opt_h * 16 , pfptr , & I_frame ) ;
res = encode_bitstream ( s , p , buf , buf_size , opt_w * 16 , opt_h * 16 , pfptr , & I_frame ) ;
//save the current frame
//save the current frame
if ( p - > linesize [ 0 ] > 0 )
if ( p - > linesize [ 0 ] > 0 )
memcpy ( s - > previous_frame , p - > data [ 0 ] , s - > image_height * p - > linesize [ 0 ] ) ;
memcpy ( s - > previous_frame , p - > data [ 0 ] , s - > image_height * p - > linesize [ 0 ] ) ;
else
else
memcpy ( s - > previous_frame , p - > data [ 0 ] + p - > linesize [ 0 ] * ( s - > image_height - 1 ) , s - > image_height * FFABS ( p - > linesize [ 0 ] ) ) ;
memcpy ( s - > previous_frame , p - > data [ 0 ] + p - > linesize [ 0 ] * ( s - > image_height - 1 ) ,
s - > image_height * FFABS ( p - > linesize [ 0 ] ) ) ;
//mark the frame type so the muxer can mux it correctly
//mark the frame type so the muxer can mux it correctly
if ( I_frame ) {
if ( I_frame ) {
p - > pict_type = FF_I_TYPE ;
p - > pict_type = FF_I_TYPE ;
p - > key_frame = 1 ;
p - > key_frame = 1 ;
s - > last_key_frame = avctx - > frame_number ;
s - > last_key_frame = avctx - > frame_number ;
av_log ( avctx , AV_LOG_DEBUG , " Inserting key frame at frame %d \n " , avctx - > frame_number ) ;
av_log ( avctx , AV_LOG_DEBUG , " Inserting key frame at frame %d \n " , avctx - > frame_number ) ;
} else {
} else {
p - > pict_type = FF_P_TYPE ;
p - > pict_type = FF_P_TYPE ;
p - > key_frame = 0 ;
p - > key_frame = 0 ;
@ -281,13 +288,13 @@ static av_cold int flashsv_encode_end(AVCodecContext *avctx)
}
}
AVCodec ff_flashsv_encoder = {
AVCodec ff_flashsv_encoder = {
" flashsv " ,
. name = " flashsv " ,
AVMEDIA_TYPE_VIDEO ,
. type = AVMEDIA_TYPE_VIDEO ,
CODEC_ID_FLASHSV ,
. id = CODEC_ID_FLASHSV ,
sizeof ( FlashSVContext ) ,
. priv_data_size = sizeof ( FlashSVContext ) ,
flashsv_encode_init ,
. init = flashsv_encode_init ,
flashsv_encode_frame ,
. encode = flashsv_encode_frame ,
flashsv_encode_end ,
. close = flashsv_encode_end ,
. pix_fmts = ( const enum PixelFormat [ ] ) { PIX_FMT_BGR24 , PIX_FMT_NONE } ,
. pix_fmts = ( const enum PixelFormat [ ] ) { PIX_FMT_BGR24 , PIX_FMT_NONE } ,
. long_name = NULL_IF_CONFIG_SMALL ( " Flash Screen Video " ) ,
. long_name = NULL_IF_CONFIG_SMALL ( " Flash Screen Video " ) ,
} ;
} ;