From c1322c3198f981adf2e1a4221afdba9cfdc9345c Mon Sep 17 00:00:00 2001 From: Fiona Glaser Date: Sat, 3 Oct 2009 00:59:02 -0700 Subject: [PATCH] Reorder reference frames optimally on second pass About +0.1-0.2% compression at normal bitrates, up to +1% at very low bitrates. Only works if the first pass uses the same number of refs as the second (i.e. not with fast first pass). Thus, only worthwhile at insanely slow speeds: as such, enable slow-firstpass by default with preset placebo. Note that this changes the stats file format! --- encoder/encoder.c | 75 +++++++++++++++++++++++-------------------- encoder/ratecontrol.c | 62 +++++++++++++++++++++++++++++++++-- encoder/ratecontrol.h | 1 + x264.c | 1 + 4 files changed, 102 insertions(+), 37 deletions(-) diff --git a/encoder/encoder.c b/encoder/encoder.c index 080a259e..549887db 100644 --- a/encoder/encoder.c +++ b/encoder/encoder.c @@ -1138,20 +1138,6 @@ static inline void x264_reference_build_list( x264_t *h, int i_poc ) } } while( !b_ok ); - /* In the standard, a P-frame's ref list is sorted by frame_num. - * We use POC, but check whether explicit reordering is needed */ - h->b_ref_reorder[0] = - h->b_ref_reorder[1] = 0; - if( h->sh.i_type == SLICE_TYPE_P ) - { - for( i = 0; i < h->i_ref0 - 1; i++ ) - if( h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num ) - { - h->b_ref_reorder[0] = 1; - break; - } - } - h->i_ref1 = X264_MIN( h->i_ref1, h->frames.i_max_ref1 ); h->i_ref0 = X264_MIN( h->i_ref0, h->frames.i_max_ref0 ); h->i_ref0 = X264_MIN( h->i_ref0, h->param.i_frame_reference ); // if reconfig() has lowered the limit @@ -1446,24 +1432,26 @@ static int x264_slice_write( x264_t *h ) /* accumulate mb stats */ h->stat.frame.i_mb_count[h->mb.i_type]++; - if( h->param.i_log_level >= X264_LOG_INFO ) + + if( !IS_INTRA(h->mb.i_type) && !IS_SKIP(h->mb.i_type) && !IS_DIRECT(h->mb.i_type) ) { - if( !IS_SKIP(h->mb.i_type) && !IS_INTRA(h->mb.i_type) && !IS_DIRECT(h->mb.i_type) ) - { - if( h->mb.i_partition != D_8x8 ) + if( h->mb.i_partition != D_8x8 ) h->stat.frame.i_mb_partition[h->mb.i_partition] += 4; else for( i = 0; i < 4; i++ ) h->stat.frame.i_mb_partition[h->mb.i_sub_partition[i]] ++; - if( h->param.i_frame_reference > 1 ) - for( i_list = 0; i_list <= (h->sh.i_type == SLICE_TYPE_B); i_list++ ) - for( i = 0; i < 4; i++ ) - { - i_ref = h->mb.cache.ref[i_list][ x264_scan8[4*i] ]; - if( i_ref >= 0 ) - h->stat.frame.i_mb_count_ref[i_list][i_ref] ++; - } - } + if( h->param.i_frame_reference > 1 ) + for( i_list = 0; i_list <= (h->sh.i_type == SLICE_TYPE_B); i_list++ ) + for( i = 0; i < 4; i++ ) + { + i_ref = h->mb.cache.ref[i_list][ x264_scan8[4*i] ]; + if( i_ref >= 0 ) + h->stat.frame.i_mb_count_ref[i_list][i_ref] ++; + } + } + + if( h->param.i_log_level >= X264_LOG_INFO ) + { if( h->mb.i_cbp_luma || h->mb.i_cbp_chroma ) { int cbpsum = (h->mb.i_cbp_luma&1) + ((h->mb.i_cbp_luma>>1)&1) @@ -1632,7 +1620,7 @@ int x264_encoder_encode( x264_t *h, x264_picture_t *pic_out ) { x264_t *thread_current, *thread_prev, *thread_oldest; - int i_nal_type; + int i_nal_type, i; int i_nal_ref_idc; int i_global_qp; @@ -1790,21 +1778,22 @@ int x264_encoder_encode( x264_t *h, h->out.i_nal = 0; bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream ); - if(h->param.b_aud){ + if( h->param.b_aud ) + { int pic_type; - if(h->sh.i_type == SLICE_TYPE_I) + if( h->sh.i_type == SLICE_TYPE_I ) pic_type = 0; - else if(h->sh.i_type == SLICE_TYPE_P) + else if( h->sh.i_type == SLICE_TYPE_P ) pic_type = 1; - else if(h->sh.i_type == SLICE_TYPE_B) + else if( h->sh.i_type == SLICE_TYPE_B ) pic_type = 2; else pic_type = 7; - x264_nal_start(h, NAL_AUD, NAL_PRIORITY_DISPOSABLE); - bs_write(&h->out.bs, 3, pic_type); - bs_rbsp_trailing(&h->out.bs); + x264_nal_start( h, NAL_AUD, NAL_PRIORITY_DISPOSABLE ); + bs_write( &h->out.bs, 3, pic_type ); + bs_rbsp_trailing( &h->out.bs ); if( x264_nal_end( h ) ) return -1; } @@ -1851,6 +1840,22 @@ int x264_encoder_encode( x264_t *h, pic_out->i_qpplus1 = h->fdec->i_qpplus1 = i_global_qp + 1; + if( h->param.rc.b_stat_read && h->sh.i_type != SLICE_TYPE_I ) + x264_reference_build_list_optimal( h ); + + /* Check to see whether we have chosen a reference list ordering different + * from the standard's default. */ + h->b_ref_reorder[0] = + h->b_ref_reorder[1] = 0; + for( i = 0; i < h->i_ref0 - 1; i++ ) + /* P and B-frames use different default orders. */ + if( h->sh.i_type == SLICE_TYPE_P ? h->fref0[i]->i_frame_num < h->fref0[i+1]->i_frame_num + : h->fref0[i]->i_poc < h->fref0[i+1]->i_poc ) + { + h->b_ref_reorder[0] = 1; + break; + } + /* ------------------------ Create slice header ----------------------- */ x264_slice_init( h, i_nal_type, i_global_qp ); diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c index 5bc3f618..a5df9d4c 100644 --- a/encoder/ratecontrol.c +++ b/encoder/ratecontrol.c @@ -31,6 +31,7 @@ #include "common/common.h" #include "common/cpu.h" #include "ratecontrol.h" +#include "me.h" typedef struct { @@ -49,6 +50,8 @@ typedef struct int s_count; float blurred_complexity; char direct_mode; + int refcount[16]; + int refs; } ratecontrol_entry_t; typedef struct @@ -301,6 +304,33 @@ fail: return -1; } +int x264_reference_build_list_optimal( x264_t *h ) +{ + ratecontrol_entry_t *rce = h->rc->rce; + x264_frame_t *frames[16]; + int ref, i; + + if( rce->refs != h->i_ref0 ) + return -1; + + memcpy( frames, h->fref0, sizeof(frames) ); + + /* For now don't reorder ref 0; it seems to lower quality + in most cases due to skips. */ + for( ref = 1; ref < h->i_ref0; ref++ ) + { + int max = -1; + int bestref = 1; + for( i = 1; i < h->i_ref0; i++ ) + /* Favor lower POC as a tiebreaker. */ + COPY2_IF_GT( max, rce->refcount[i], bestref, i ); + rce->refcount[bestref] = -1; + h->fref0[ref] = frames[bestref]; + } + + return 0; +} + static char *x264_strcat_filename( char *input, char *suffix ) { char *output = x264_malloc( strlen( input ) + strlen( suffix ) + 1 ); @@ -581,6 +611,7 @@ int x264_ratecontrol_new( x264_t *h ) int e; char *next; float qp; + int ref; next= strchr(p, ';'); if(next) @@ -603,6 +634,20 @@ int x264_ratecontrol_new( x264_t *h ) &rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, &rce->s_count, &rce->direct_mode); + p = strstr( p, "ref:" ); + if( !p ) + goto parse_error; + p += 4; + for( ref = 0; ref < 16; ref++ ) + { + if( sscanf( p, " %d", &rce->refcount[ref] ) != 1 ) + break; + p = strchr( p+1, ' ' ); + if( !p ) + goto parse_error; + } + rce->refs = ref; + switch(pict_type) { case 'I': rce->kept_as_ref = 1; @@ -614,6 +659,7 @@ int x264_ratecontrol_new( x264_t *h ) } if(e < 10) { +parse_error: x264_log(h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e); return -1; } @@ -1222,7 +1268,7 @@ int x264_ratecontrol_end( x264_t *h, int bits ) dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' ) : '-'; if( fprintf( rc->p_stat_file_out, - "in:%d out:%d type:%c q:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c;\n", + "in:%d out:%d type:%c q:%.2f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c ref:", h->fenc->i_frame, h->i_frame, c_type, rc->qpa_rc, h->stat.frame.i_tex_bits, @@ -1232,7 +1278,19 @@ int x264_ratecontrol_end( x264_t *h, int bits ) h->stat.frame.i_mb_count_p, h->stat.frame.i_mb_count_skip, c_direct) < 0 ) - goto fail; + goto fail; + + for( i = 0; i < h->i_ref0; i++ ) + { + int refcount = h->param.b_interlaced ? h->stat.frame.i_mb_count_ref[0][i*2] + + h->stat.frame.i_mb_count_ref[0][i*2+1] : + h->stat.frame.i_mb_count_ref[0][i]; + if( fprintf( rc->p_stat_file_out, "%d ", refcount ) < 0 ) + goto fail; + } + + if( fprintf( rc->p_stat_file_out, ";\n" ) < 0 ) + goto fail; /* Don't re-write the data in multi-pass mode. */ if( h->param.rc.b_mb_tree && h->fenc->b_kept_as_ref && !h->param.rc.b_stat_read ) diff --git a/encoder/ratecontrol.h b/encoder/ratecontrol.h index 36a174dd..d3b9becb 100644 --- a/encoder/ratecontrol.h +++ b/encoder/ratecontrol.h @@ -30,6 +30,7 @@ void x264_ratecontrol_delete( x264_t * ); void x264_adaptive_quant_frame( x264_t *h, x264_frame_t *frame ); void x264_adaptive_quant( x264_t * ); int x264_macroblock_tree_read( x264_t *h, x264_frame_t *frame ); +int x264_reference_build_list_optimal( x264_t *h ); void x264_thread_sync_ratecontrol( x264_t *cur, x264_t *prev, x264_t *next ); void x264_ratecontrol_start( x264_t *, int i_force_qp, int overhead ); int x264_ratecontrol_slice_type( x264_t *, int i_frame ); diff --git a/x264.c b/x264.c index 9c5a928c..87eef2e4 100644 --- a/x264.c +++ b/x264.c @@ -660,6 +660,7 @@ static int Parse( int argc, char **argv, param->analyse.i_trellis = 2; param->i_bframe = 16; param->rc.i_lookahead = 60; + b_turbo = 0; } else { -- 2.39.5