/*
* SVQ1 Encoder
* Copyright ( C ) 2004 Mike Melanson < melanson @ pcisys . net >
*
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* FFmpeg is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/**
* @ file
* Sorenson Vector Quantizer # 1 ( SVQ1 ) video codec .
* For more information of the SVQ1 algorithm , visit :
* http : //www.pcisys.net/~melanson/codecs/
*/
# include "avcodec.h"
# include "dsputil.h"
# include "mpegvideo.h"
# include "h263.h"
# include "internal.h"
# include "svq1.h"
# include "svq1enc_cb.h"
# undef NDEBUG
# include <assert.h>
typedef struct SVQ1Context {
MpegEncContext m ; // needed for motion estimation, should not be used for anything else, the idea is to make the motion estimation eventually independent of MpegEncContext, so this will be removed then (FIXME/XXX)
AVCodecContext * avctx ;
DSPContext dsp ;
AVFrame picture ;
AVFrame current_picture ;
AVFrame last_picture ;
PutBitContext pb ;
GetBitContext gb ;
PutBitContext reorder_pb [ 6 ] ; //why ooh why this sick breadth first order, everything is slower and more complex
int frame_width ;
int frame_height ;
/* Y plane block dimensions */
int y_block_width ;
int y_block_height ;
/* U & V plane (C planes) block dimensions */
int c_block_width ;
int c_block_height ;
uint16_t * mb_type ;
uint32_t * dummy ;
int16_t ( * motion_val8 [ 3 ] ) [ 2 ] ;
int16_t ( * motion_val16 [ 3 ] ) [ 2 ] ;
int64_t rd_total ;
uint8_t * scratchbuf ;
} SVQ1Context ;
static void svq1_write_header ( SVQ1Context * s , int frame_type )
{
int i ;
/* frame code */
put_bits ( & s - > pb , 22 , 0x20 ) ;
/* temporal reference (sure hope this is a "don't care") */
put_bits ( & s - > pb , 8 , 0x00 ) ;
/* frame type */
put_bits ( & s - > pb , 2 , frame_type - 1 ) ;
if ( frame_type = = AV_PICTURE_TYPE_I ) {
/* no checksum since frame code is 0x20 */
/* no embedded string either */
/* output 5 unknown bits (2 + 2 + 1) */
put_bits ( & s - > pb , 5 , 2 ) ; /* 2 needed by quicktime decoder */
i = ff_match_2uint16 ( ff_svq1_frame_size_table , FF_ARRAY_ELEMS ( ff_svq1_frame_size_table ) , s - > frame_width , s - > frame_height ) ;
put_bits ( & s - > pb , 3 , i ) ;
if ( i = = 7 )
{
put_bits ( & s - > pb , 12 , s - > frame_width ) ;
put_bits ( & s - > pb , 12 , s - > frame_height ) ;
}
}
/* no checksum or extra data (next 2 bits get 0) */
put_bits ( & s - > pb , 2 , 0 ) ;
}
# define QUALITY_THRESHOLD 100
# define THRESHOLD_MULTIPLIER 0.6
static int encode_block ( SVQ1Context * s , uint8_t * src , uint8_t * ref , uint8_t * decoded , int stride , int level , int threshold , int lambda , int intra ) {
int count , y , x , i , j , split , best_mean , best_score , best_count ;
int best_vector [ 6 ] ;
int block_sum [ 7 ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
int w = 2 < < ( ( level + 2 ) > > 1 ) ;
int h = 2 < < ( ( level + 1 ) > > 1 ) ;
int size = w * h ;
int16_t block [ 7 ] [ 256 ] ;
const int8_t * codebook_sum , * codebook ;
const uint16_t ( * mean_vlc ) [ 2 ] ;
const uint8_t ( * multistage_vlc ) [ 2 ] ;
best_score = 0 ;
//FIXME optimize, this doenst need to be done multiple times
if ( intra ) {
codebook_sum = svq1_intra_codebook_sum [ level ] ;
codebook = ff_svq1_intra_codebooks [ level ] ;
mean_vlc = ff_svq1_intra_mean_vlc ;
multistage_vlc = ff_svq1_intra_multistage_vlc [ level ] ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
int v = src [ x + y * stride ] ;
block [ 0 ] [ x + w * y ] = v ;
best_score + = v * v ;
block_sum [ 0 ] + = v ;
}
}
} else {
codebook_sum = svq1_inter_codebook_sum [ level ] ;
codebook = ff_svq1_inter_codebooks [ level ] ;
mean_vlc = ff_svq1_inter_mean_vlc + 256 ;
multistage_vlc = ff_svq1_inter_multistage_vlc [ level ] ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
int v = src [ x + y * stride ] - ref [ x + y * stride ] ;
block [ 0 ] [ x + w * y ] = v ;
best_score + = v * v ;
block_sum [ 0 ] + = v ;
}
}
}
best_count = 0 ;
best_score - = ( int ) ( ( ( unsigned ) block_sum [ 0 ] * block_sum [ 0 ] ) > > ( level + 3 ) ) ;
best_mean = ( block_sum [ 0 ] + ( size > > 1 ) ) > > ( level + 3 ) ;
if ( level < 4 ) {
for ( count = 1 ; count < 7 ; count + + ) {
int best_vector_score = INT_MAX ;
int best_vector_sum = - 999 , best_vector_mean = - 999 ;
const int stage = count - 1 ;
const int8_t * vector ;
for ( i = 0 ; i < 16 ; i + + ) {
int sum = codebook_sum [ stage * 16 + i ] ;
int sqr , diff , score ;
vector = codebook + stage * size * 16 + i * size ;
sqr = s - > dsp . ssd_int8_vs_int16 ( vector , block [ stage ] , size ) ;
diff = block_sum [ stage ] - sum ;
score = sqr - ( ( diff * ( int64_t ) diff ) > > ( level + 3 ) ) ; //FIXME 64bit slooow
if ( score < best_vector_score ) {
int mean = ( diff + ( size > > 1 ) ) > > ( level + 3 ) ;
assert ( mean > - 300 & & mean < 300 ) ;
mean = av_clip ( mean , intra ? 0 : - 256 , 255 ) ;
best_vector_score = score ;
best_vector [ stage ] = i ;
best_vector_sum = sum ;
best_vector_mean = mean ;
}
}
assert ( best_vector_mean ! = - 999 ) ;
vector = codebook + stage * size * 16 + best_vector [ stage ] * size ;
for ( j = 0 ; j < size ; j + + ) {
block [ stage + 1 ] [ j ] = block [ stage ] [ j ] - vector [ j ] ;
}
block_sum [ stage + 1 ] = block_sum [ stage ] - best_vector_sum ;
best_vector_score + =
lambda * ( + 1 + 4 * count
+ multistage_vlc [ 1 + count ] [ 1 ]
+ mean_vlc [ best_vector_mean ] [ 1 ] ) ;
if ( best_vector_score < best_score ) {
best_score = best_vector_score ;
best_count = count ;
best_mean = best_vector_mean ;
}
}
}
split = 0 ;
if ( best_score > threshold & & level ) {
int score = 0 ;
int offset = ( level & 1 ) ? stride * h / 2 : w / 2 ;
PutBitContext backup [ 6 ] ;
for ( i = level - 1 ; i > = 0 ; i - - ) {
backup [ i ] = s - > reorder_pb [ i ] ;
}
score + = encode_block ( s , src , ref , decoded , stride , level - 1 , threshold > > 1 , lambda , intra ) ;
score + = encode_block ( s , src + offset , ref + offset , decoded + offset , stride , level - 1 , threshold > > 1 , lambda , intra ) ;
score + = lambda ;
if ( score < best_score ) {
best_score = score ;
split = 1 ;
} else {
for ( i = level - 1 ; i > = 0 ; i - - ) {
s - > reorder_pb [ i ] = backup [ i ] ;
}
}
}
if ( level > 0 )
put_bits ( & s - > reorder_pb [ level ] , 1 , split ) ;
if ( ! split ) {
assert ( ( best_mean > = 0 & & best_mean < 256 ) | | ! intra ) ;
assert ( best_mean > = - 256 & & best_mean < 256 ) ;
assert ( best_count > = 0 & & best_count < 7 ) ;
assert ( level < 4 | | best_count = = 0 ) ;
/* output the encoding */
put_bits ( & s - > reorder_pb [ level ] ,
multistage_vlc [ 1 + best_count ] [ 1 ] ,
multistage_vlc [ 1 + best_count ] [ 0 ] ) ;
put_bits ( & s - > reorder_pb [ level ] , mean_vlc [ best_mean ] [ 1 ] ,
mean_vlc [ best_mean ] [ 0 ] ) ;
for ( i = 0 ; i < best_count ; i + + ) {
assert ( best_vector [ i ] > = 0 & & best_vector [ i ] < 16 ) ;
put_bits ( & s - > reorder_pb [ level ] , 4 , best_vector [ i ] ) ;
}
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
decoded [ x + y * stride ] = src [ x + y * stride ] - block [ best_count ] [ x + w * y ] + best_mean ;
}
}
}
return best_score ;
}
static int svq1_encode_plane ( SVQ1Context * s , int plane , unsigned char * src_plane , unsigned char * ref_plane , unsigned char * decoded_plane ,
int width , int height , int src_stride , int stride )
{
int x , y ;
int i ;
int block_width , block_height ;
int level ;
int threshold [ 6 ] ;
uint8_t * src = s - > scratchbuf + stride * 16 ;
const int lambda = ( s - > picture . quality * s - > picture . quality ) > > ( 2 * FF_LAMBDA_SHIFT ) ;
/* figure out the acceptable level thresholds in advance */
threshold [ 5 ] = QUALITY_THRESHOLD ;
for ( level = 4 ; level > = 0 ; level - - )
threshold [ level ] = threshold [ level + 1 ] * THRESHOLD_MULTIPLIER ;
block_width = ( width + 15 ) / 16 ;
block_height = ( height + 15 ) / 16 ;
if ( s - > picture . pict_type = = AV_PICTURE_TYPE_P ) {
s - > m . avctx = s - > avctx ;
s - > m . current_picture_ptr = & s - > m . current_picture ;
s - > m . last_picture_ptr = & s - > m . last_picture ;
s - > m . last_picture . f . data [ 0 ] = ref_plane ;
s - > m . linesize =
s - > m . last_picture . f . linesize [ 0 ] =
s - > m . new_picture . f . linesize [ 0 ] =
s - > m . current_picture . f . linesize [ 0 ] = stride ;
s - > m . width = width ;
s - > m . height = height ;
s - > m . mb_width = block_width ;
s - > m . mb_height = block_height ;
s - > m . mb_stride = s - > m . mb_width + 1 ;
s - > m . b8_stride = 2 * s - > m . mb_width + 1 ;
s - > m . f_code = 1 ;
s - > m . pict_type = s - > picture . pict_type ;
s - > m . me_method = s - > avctx - > me_method ;
s - > m . me . scene_change_score = 0 ;
s - > m . flags = s - > avctx - > flags ;
// s->m.out_format = FMT_H263;
// s->m.unrestricted_mv= 1;
s - > m . lambda = s - > picture . quality ;
s - > m . qscale = ( s - > m . lambda * 139 + FF_LAMBDA_SCALE * 64 ) > > ( FF_LAMBDA_SHIFT + 7 ) ;
s - > m . lambda2 = ( s - > m . lambda * s - > m . lambda + FF_LAMBDA_SCALE / 2 ) > > FF_LAMBDA_SHIFT ;
if ( ! s - > motion_val8 [ plane ] ) {
s - > motion_val8 [ plane ] = av_mallocz ( ( s - > m . b8_stride * block_height * 2 + 2 ) * 2 * sizeof ( int16_t ) ) ;
s - > motion_val16 [ plane ] = av_mallocz ( ( s - > m . mb_stride * ( block_height + 2 ) + 1 ) * 2 * sizeof ( int16_t ) ) ;
}
s - > m . mb_type = s - > mb_type ;
//dummies, to avoid segfaults
s - > m . current_picture . mb_mean = ( uint8_t * ) s - > dummy ;
s - > m . current_picture . mb_var = ( uint16_t * ) s - > dummy ;
s - > m . current_picture . mc_mb_var = ( uint16_t * ) s - > dummy ;
s - > m . current_picture . f . mb_type = s - > dummy ;
s - > m . current_picture . f . motion_val [ 0 ] = s - > motion_val8 [ plane ] + 2 ;
s - > m . p_mv_table = s - > motion_val16 [ plane ] + s - > m . mb_stride + 1 ;
s - > m . dsp = s - > dsp ; //move
ff_init_me ( & s - > m ) ;
s - > m . me . dia_size = s - > avctx - > dia_size ;
s - > m . first_slice_line = 1 ;
for ( y = 0 ; y < block_height ; y + + ) {
s - > m . new_picture . f . data [ 0 ] = src - y * 16 * stride ; //ugly
s - > m . mb_y = y ;
for ( i = 0 ; i < 16 & & i + 16 * y < height ; i + + ) {
memcpy ( & src [ i * stride ] , & src_plane [ ( i + 16 * y ) * src_stride ] , width ) ;
for ( x = width ; x < 16 * block_width ; x + + )
src [ i * stride + x ] = src [ i * stride + x - 1 ] ;
}
for ( ; i < 16 & & i + 16 * y < 16 * block_height ; i + + )
memcpy ( & src [ i * stride ] , & src [ ( i - 1 ) * stride ] , 16 * block_width ) ;
for ( x = 0 ; x < block_width ; x + + ) {
s - > m . mb_x = x ;
ff_init_block_index ( & s - > m ) ;
ff_update_block_index ( & s - > m ) ;
ff_estimate_p_frame_motion ( & s - > m , x , y ) ;
}
s - > m . first_slice_line = 0 ;
}
ff_fix_long_p_mvs ( & s - > m ) ;
ff_fix_long_mvs ( & s - > m , NULL , 0 , s - > m . p_mv_table , s - > m . f_code , CANDIDATE_MB_TYPE_INTER , 0 ) ;
}
s - > m . first_slice_line = 1 ;
for ( y = 0 ; y < block_height ; y + + ) {
for ( i = 0 ; i < 16 & & i + 16 * y < height ; i + + ) {
memcpy ( & src [ i * stride ] , & src_plane [ ( i + 16 * y ) * src_stride ] , width ) ;
for ( x = width ; x < 16 * block_width ; x + + )
src [ i * stride + x ] = src [ i * stride + x - 1 ] ;
}
for ( ; i < 16 & & i + 16 * y < 16 * block_height ; i + + )
memcpy ( & src [ i * stride ] , & src [ ( i - 1 ) * stride ] , 16 * block_width ) ;
s - > m . mb_y = y ;
for ( x = 0 ; x < block_width ; x + + ) {
uint8_t reorder_buffer [ 3 ] [ 6 ] [ 7 * 32 ] ;
int count [ 3 ] [ 6 ] ;
int offset = y * 16 * stride + x * 16 ;
uint8_t * decoded = decoded_plane + offset ;
uint8_t * ref = ref_plane + offset ;
int score [ 4 ] = { 0 , 0 , 0 , 0 } , best ;
uint8_t * temp = s - > scratchbuf ;
if ( s - > pb . buf_end - s - > pb . buf - ( put_bits_count ( & s - > pb ) > > 3 ) < 3000 ) { //FIXME check size
av_log ( s - > avctx , AV_LOG_ERROR , " encoded frame too large \n " ) ;
return - 1 ;
}
s - > m . mb_x = x ;
ff_init_block_index ( & s - > m ) ;
ff_update_block_index ( & s - > m ) ;
if ( s - > picture . pict_type = = AV_PICTURE_TYPE_I | | ( s - > m . mb_type [ x + y * s - > m . mb_stride ] & CANDIDATE_MB_TYPE_INTRA ) ) {
for ( i = 0 ; i < 6 ; i + + ) {
init_put_bits ( & s - > reorder_pb [ i ] , reorder_buffer [ 0 ] [ i ] , 7 * 32 ) ;
}
if ( s - > picture . pict_type = = AV_PICTURE_TYPE_P ) {
const uint8_t * vlc = ff_svq1_block_type_vlc [ SVQ1_BLOCK_INTRA ] ;
put_bits ( & s - > reorder_pb [ 5 ] , vlc [ 1 ] , vlc [ 0 ] ) ;
score [ 0 ] = vlc [ 1 ] * lambda ;
}
score [ 0 ] + = encode_block ( s , src + 16 * x , NULL , temp , stride , 5 , 64 , lambda , 1 ) ;
for ( i = 0 ; i < 6 ; i + + ) {
count [ 0 ] [ i ] = put_bits_count ( & s - > reorder_pb [ i ] ) ;
flush_put_bits ( & s - > reorder_pb [ i ] ) ;
}
} else
score [ 0 ] = INT_MAX ;
best = 0 ;
if ( s - > picture . pict_type = = AV_PICTURE_TYPE_P ) {
const uint8_t * vlc = ff_svq1_block_type_vlc [ SVQ1_BLOCK_INTER ] ;
int mx , my , pred_x , pred_y , dxy ;
int16_t * motion_ptr ;
motion_ptr = h263_pred_motion ( & s - > m , 0 , 0 , & pred_x , & pred_y ) ;
if ( s - > m . mb_type [ x + y * s - > m . mb_stride ] & CANDIDATE_MB_TYPE_INTER ) {
for ( i = 0 ; i < 6 ; i + + )
init_put_bits ( & s - > reorder_pb [ i ] , reorder_buffer [ 1 ] [ i ] , 7 * 32 ) ;
put_bits ( & s - > reorder_pb [ 5 ] , vlc [ 1 ] , vlc [ 0 ] ) ;
s - > m . pb = s - > reorder_pb [ 5 ] ;
mx = motion_ptr [ 0 ] ;
my = motion_ptr [ 1 ] ;
assert ( mx > = - 32 & & mx < = 31 ) ;
assert ( my > = - 32 & & my < = 31 ) ;
assert ( pred_x > = - 32 & & pred_x < = 31 ) ;
assert ( pred_y > = - 32 & & pred_y < = 31 ) ;
ff_h263_encode_motion ( & s - > m , mx - pred_x , 1 ) ;
ff_h263_encode_motion ( & s - > m , my - pred_y , 1 ) ;
s - > reorder_pb [ 5 ] = s - > m . pb ;
score [ 1 ] + = lambda * put_bits_count ( & s - > reorder_pb [ 5 ] ) ;
dxy = ( mx & 1 ) + 2 * ( my & 1 ) ;
s - > dsp . put_pixels_tab [ 0 ] [ dxy ] ( temp + 16 , ref + ( mx > > 1 ) + stride * ( my > > 1 ) , stride , 16 ) ;
score [ 1 ] + = encode_block ( s , src + 16 * x , temp + 16 , decoded , stride , 5 , 64 , lambda , 0 ) ;
best = score [ 1 ] < = score [ 0 ] ;
vlc = ff_svq1_block_type_vlc [ SVQ1_BLOCK_SKIP ] ;
score [ 2 ] = s - > dsp . sse [ 0 ] ( NULL , src + 16 * x , ref , stride , 16 ) ;
score [ 2 ] + = vlc [ 1 ] * lambda ;
if ( score [ 2 ] < score [ best ] & & mx = = 0 & & my = = 0 ) {
best = 2 ;
s - > dsp . put_pixels_tab [ 0 ] [ 0 ] ( decoded , ref , stride , 16 ) ;
for ( i = 0 ; i < 6 ; i + + ) {
count [ 2 ] [ i ] = 0 ;
}
put_bits ( & s - > pb , vlc [ 1 ] , vlc [ 0 ] ) ;
}
}
if ( best = = 1 ) {
for ( i = 0 ; i < 6 ; i + + ) {
count [ 1 ] [ i ] = put_bits_count ( & s - > reorder_pb [ i ] ) ;
flush_put_bits ( & s - > reorder_pb [ i ] ) ;
}
} else {
motion_ptr [ 0 ] = motion_ptr [ 1 ] =
motion_ptr [ 2 ] = motion_ptr [ 3 ] =
motion_ptr [ 0 + 2 * s - > m . b8_stride ] = motion_ptr [ 1 + 2 * s - > m . b8_stride ] =
motion_ptr [ 2 + 2 * s - > m . b8_stride ] = motion_ptr [ 3 + 2 * s - > m . b8_stride ] = 0 ;
}
}
s - > rd_total + = score [ best ] ;
for ( i = 5 ; i > = 0 ; i - - ) {
avpriv_copy_bits ( & s - > pb , reorder_buffer [ best ] [ i ] , count [ best ] [ i ] ) ;
}
if ( best = = 0 ) {
s - > dsp . put_pixels_tab [ 0 ] [ 0 ] ( decoded , temp , stride , 16 ) ;
}
}
s - > m . first_slice_line = 0 ;
}
return 0 ;
}
static av_cold int svq1_encode_init ( AVCodecContext * avctx )
{
SVQ1Context * const s = avctx - > priv_data ;
dsputil_init ( & s - > dsp , avctx ) ;
avctx - > coded_frame = ( AVFrame * ) & s - > picture ;
s - > frame_width = avctx - > width ;
s - > frame_height = avctx - > height ;
s - > y_block_width = ( s - > frame_width + 15 ) / 16 ;
s - > y_block_height = ( s - > frame_height + 15 ) / 16 ;
s - > c_block_width = ( s - > frame_width / 4 + 15 ) / 16 ;
s - > c_block_height = ( s - > frame_height / 4 + 15 ) / 16 ;
s - > avctx = avctx ;
s - > m . avctx = avctx ;
s - > m . me . temp =
s - > m . me . scratchpad = av_mallocz ( ( avctx - > width + 64 ) * 2 * 16 * 2 * sizeof ( uint8_t ) ) ;
s - > m . me . map = av_mallocz ( ME_MAP_SIZE * sizeof ( uint32_t ) ) ;
s - > m . me . score_map = av_mallocz ( ME_MAP_SIZE * sizeof ( uint32_t ) ) ;
s - > mb_type = av_mallocz ( ( s - > y_block_width + 1 ) * s - > y_block_height * sizeof ( int16_t ) ) ;
s - > dummy = av_mallocz ( ( s - > y_block_width + 1 ) * s - > y_block_height * sizeof ( int32_t ) ) ;
h263_encode_init ( & s - > m ) ; //mv_penalty
return 0 ;
}
static int svq1_encode_frame ( AVCodecContext * avctx , unsigned char * buf ,
int buf_size , void * data )
{
SVQ1Context * const s = avctx - > priv_data ;
AVFrame * pict = data ;
AVFrame * const p = ( AVFrame * ) & s - > picture ;
AVFrame temp ;
int i ;
if ( avctx - > pix_fmt ! = PIX_FMT_YUV410P ) {
av_log ( avctx , AV_LOG_ERROR , " unsupported pixel format \n " ) ;
return - 1 ;
}
if ( ! s - > current_picture . data [ 0 ] ) {
avctx - > get_buffer ( avctx , & s - > current_picture ) ;
avctx - > get_buffer ( avctx , & s - > last_picture ) ;
s - > scratchbuf = av_malloc ( s - > current_picture . linesize [ 0 ] * 16 * 2 ) ;
}
temp = s - > current_picture ;
s - > current_picture = s - > last_picture ;
s - > last_picture = temp ;
init_put_bits ( & s - > pb , buf , buf_size ) ;
* p = * pict ;
p - > pict_type = avctx - > gop_size & & avctx - > frame_number % avctx - > gop_size ? AV_PICTURE_TYPE_P : AV_PICTURE_TYPE_I ;
p - > key_frame = p - > pict_type = = AV_PICTURE_TYPE_I ;
svq1_write_header ( s , p - > pict_type ) ;
for ( i = 0 ; i < 3 ; i + + ) {
if ( svq1_encode_plane ( s , i ,
s - > picture . data [ i ] , s - > last_picture . data [ i ] , s - > current_picture . data [ i ] ,
s - > frame_width / ( i ? 4 : 1 ) , s - > frame_height / ( i ? 4 : 1 ) ,
s - > picture . linesize [ i ] , s - > current_picture . linesize [ i ] ) < 0 )
return - 1 ;
}
// avpriv_align_put_bits(&s->pb);
while ( put_bits_count ( & s - > pb ) & 31 )
put_bits ( & s - > pb , 1 , 0 ) ;
flush_put_bits ( & s - > pb ) ;
return put_bits_count ( & s - > pb ) / 8 ;
}
static av_cold int svq1_encode_end ( AVCodecContext * avctx )
{
SVQ1Context * const s = avctx - > priv_data ;
int i ;
av_log ( avctx , AV_LOG_DEBUG , " RD: %f \n " , s - > rd_total / ( double ) ( avctx - > width * avctx - > height * avctx - > frame_number ) ) ;
av_freep ( & s - > m . me . scratchpad ) ;
av_freep ( & s - > m . me . map ) ;
av_freep ( & s - > m . me . score_map ) ;
av_freep ( & s - > mb_type ) ;
av_freep ( & s - > dummy ) ;
av_freep ( & s - > scratchbuf ) ;
for ( i = 0 ; i < 3 ; i + + ) {
av_freep ( & s - > motion_val8 [ i ] ) ;
av_freep ( & s - > motion_val16 [ i ] ) ;
}
return 0 ;
}
AVCodec ff_svq1_encoder = {
. name = " svq1 " ,
. type = AVMEDIA_TYPE_VIDEO ,
. id = CODEC_ID_SVQ1 ,
. priv_data_size = sizeof ( SVQ1Context ) ,
. init = svq1_encode_init ,
. encode = svq1_encode_frame ,
. close = svq1_encode_end ,
. pix_fmts = ( const enum PixelFormat [ ] ) { PIX_FMT_YUV410P , PIX_FMT_NONE } ,
. long_name = NULL_IF_CONFIG_SMALL ( " Sorenson Vector Quantizer 1 / Sorenson Video 1 / SVQ1 " ) ,
} ;