Commit c1322c31 authored by Fiona Glaser's avatar Fiona Glaser

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!
parent deae6910
......@@ -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 );
......
......@@ -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 )
......
......@@ -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 );
......
......@@ -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
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment