Commit 97732683 authored by Loren Merritt's avatar Loren Merritt

--direct auto

selects direct mode per frame. works best in 2pass (enable in both passes).



git-svn-id: svn://svn.videolan.org/x264/trunk@457 df754926-b1dd-0310-bc7b-ec298dee348c
parent 126ccb33
......@@ -457,6 +457,8 @@ struct x264_t
int i_last_dqp; /* last delta qp */
int b_variable_qp; /* whether qp is allowed to vary per macroblock */
int b_lossless;
int b_direct_auto_read; /* take stats for --direct auto from the 2pass log */
int b_direct_auto_write; /* analyse direct modes, to use and/or save */
/* B_direct and weighted prediction */
int dist_scale_factor[16][16];
......@@ -494,6 +496,8 @@ struct x264_t
/* XXX: both omit the cost of MBs coded as P_SKIP */
int i_intra_cost;
int i_inter_cost;
/* Adaptive direct mv pred */
int i_direct_score[2];
} frame;
/* Cummulated stats */
......@@ -513,6 +517,9 @@ struct x264_t
int64_t i_mb_count_8x8dct[2];
int64_t i_mb_count_size[2][7];
int64_t i_mb_count_ref[2][16];
/* */
int i_direct_score[2];
int i_direct_frames[2];
} stat;
......
......@@ -423,7 +423,7 @@ static int x264_mb_predict_mv_direct16x16_spatial( x264_t *h )
return 1;
}
int x264_mb_predict_mv_direct16x16( x264_t *h )
int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed )
{
int b_available;
if( h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_NONE )
......@@ -433,6 +433,29 @@ int x264_mb_predict_mv_direct16x16( x264_t *h )
else
b_available = x264_mb_predict_mv_direct16x16_temporal( h );
if( b_changed != NULL && b_available )
{
int type_col = h->fref1[0]->mb_type[ h->mb.i_mb_xy ];
if( IS_INTRA(type_col) || type_col == P_SKIP )
{
*b_changed = h->mb.cache.direct_ref[0][0] != h->mb.cache.ref[0][X264_SCAN8_0]
|| h->mb.cache.direct_ref[1][0] != h->mb.cache.ref[1][X264_SCAN8_0]
|| *(uint32_t*)h->mb.cache.direct_mv[0][X264_SCAN8_0] != *(uint32_t*)h->mb.cache.mv[0][X264_SCAN8_0]
|| *(uint32_t*)h->mb.cache.direct_mv[1][X264_SCAN8_0] != *(uint32_t*)h->mb.cache.mv[1][X264_SCAN8_0];
}
else
{
int i, l;
*b_changed = 0;
for( l = 0; l < 2; l++ )
for( i = 0; i < 4; i++ )
*b_changed |= h->mb.cache.direct_ref[l][i] != h->mb.cache.ref[l][x264_scan8[i*4]];
*b_changed = *b_changed || memcmp(h->mb.cache.direct_mv, h->mb.cache.mv, sizeof(h->mb.cache.mv));
}
if( !*b_changed )
return b_available;
}
/* cache ref & mv */
if( b_available )
{
......
......@@ -229,13 +229,15 @@ void x264_mb_predict_mv_pskip( x264_t *h, int mv[2] );
/* x264_mb_predict_mv:
* set mvp with predicted mv for all blocks except SKIP and DIRECT
* h->mb. need valid ref/partition/sub of current block to be valid
* and valid mv/ref from other blocks . */
* and valid mv/ref from other blocks. */
void x264_mb_predict_mv( x264_t *h, int i_list, int idx, int i_width, int mvp[2] );
/* x264_mb_predict_mv_direct16x16:
* set h->mb.cache.mv and h->mb.cache.ref for B_SKIP or B_DIRECT
* h->mb. need only valid values from other blocks
* return 1 on success, 0 on failure */
int x264_mb_predict_mv_direct16x16( x264_t *h );
* h->mb. need only valid values from other blocks.
* return 1 on success, 0 on failure.
* if b_changed != NULL, set it to whether refs or mvs differ from
* before this functioncall. */
int x264_mb_predict_mv_direct16x16( x264_t *h, int *b_changed );
/* x264_mb_load_mv_direct8x8:
* set h->mb.cache.mv and h->mb.cache.ref for B_DIRECT
* must be called only after x264_mb_predict_mv_direct16x16 */
......
......@@ -2051,11 +2051,33 @@ void x264_macroblock_analyse( x264_t *h )
int i_bskip_cost = COST_MAX;
int b_skip = 0;
analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h );
h->mb.i_type = B_SKIP;
if( h->mb.b_direct_auto_write )
{
/* direct=auto heuristic: prefer whichever mode allows more Skip macroblocks */
for( i = 0; i < 2; i++ )
{
int b_changed = 1;
h->sh.b_direct_spatial_mv_pred ^= 1;
analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, i && analysis.b_direct_available ? &b_changed : NULL );
if( analysis.b_direct_available )
{
if( b_changed )
{
x264_mb_mc( h );
b_skip = x264_macroblock_probe_bskip( h );
}
h->stat.frame.i_direct_score[ h->sh.b_direct_spatial_mv_pred ] += b_skip;
}
}
}
else
analysis.b_direct_available = x264_mb_predict_mv_direct16x16( h, NULL );
if( analysis.b_direct_available )
{
h->mb.i_type = B_SKIP;
x264_mb_mc( h );
if( !h->mb.b_direct_auto_write )
x264_mb_mc( h );
if( h->mb.b_lossless )
{
/* chance of skip is too small to bother */
......@@ -2072,7 +2094,7 @@ void x264_macroblock_analyse( x264_t *h )
return;
}
}
else
else if( !h->mb.b_direct_auto_write )
{
/* Conditioning the probe on neighboring block types
* doesn't seem to help speed or quality. */
......
......@@ -147,7 +147,14 @@ static void x264_slice_header_init( x264_t *h, x264_slice_header_t *sh,
sh->i_redundant_pic_cnt = 0;
sh->b_direct_spatial_mv_pred = ( param->analyse.i_direct_mv_pred == X264_DIRECT_PRED_SPATIAL );
if( !h->mb.b_direct_auto_read )
{
if( h->mb.b_direct_auto_write )
sh->b_direct_spatial_mv_pred = ( h->stat.i_direct_score[1] > h->stat.i_direct_score[0] );
else
sh->b_direct_spatial_mv_pred = ( param->analyse.i_direct_mv_pred == X264_DIRECT_PRED_SPATIAL );
}
/* else b_direct_spatial_mv_pred was read from the 2pass statsfile */
sh->b_num_ref_idx_override = 0;
sh->i_num_ref_idx_l0_active = 1;
......@@ -388,6 +395,9 @@ static int x264_validate_parameters( x264_t *h )
h->param.i_bframe_bias = x264_clip3( h->param.i_bframe_bias, -90, 100 );
h->param.b_bframe_pyramid = h->param.b_bframe_pyramid && h->param.i_bframe > 1;
h->param.b_bframe_adaptive = h->param.b_bframe_adaptive && h->param.i_bframe > 0;
h->mb.b_direct_auto_write = h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO
&& h->param.i_bframe
&& ( h->param.rc.b_stat_write || !h->param.rc.b_stat_read );
h->param.i_deblocking_filter_alphac0 = x264_clip3( h->param.i_deblocking_filter_alphac0, -6, 6 );
h->param.i_deblocking_filter_beta = x264_clip3( h->param.i_deblocking_filter_beta, -6, 6 );
......@@ -1527,6 +1537,21 @@ do_encode:
for( i = 0; i < 16; i++ )
h->stat.i_mb_count_ref[h->sh.i_type][i] += h->stat.frame.i_mb_count_ref[i];
}
if( i_slice_type == SLICE_TYPE_B )
{
h->stat.i_direct_frames[ h->sh.b_direct_spatial_mv_pred ] ++;
if( h->mb.b_direct_auto_write )
{
//FIXME somewhat arbitrary time constants
if( h->stat.i_direct_score[0] + h->stat.i_direct_score[1] > h->mb.i_mb_count )
{
for( i = 0; i < 2; i++ )
h->stat.i_direct_score[i] = h->stat.i_direct_score[i] * 9/10;
}
for( i = 0; i < 2; i++ )
h->stat.i_direct_score[i] += h->stat.frame.i_direct_score[i];
}
}
if( h->param.analyse.b_psnr )
{
......@@ -1715,6 +1740,14 @@ void x264_encoder_close ( x264_t *h )
100. * h->stat.i_mb_count_8x8dct[1] / h->stat.i_mb_count_8x8dct[0] );
}
if( h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO
&& h->stat.i_slice_count[SLICE_TYPE_B] )
{
x264_log( h, X264_LOG_INFO, "direct mvs spatial:%.1f%% temporal:%.1f%%\n",
h->stat.i_direct_frames[1] * 100. / h->stat.i_slice_count[SLICE_TYPE_B],
h->stat.i_direct_frames[0] * 100. / h->stat.i_slice_count[SLICE_TYPE_B] );
}
if( h->param.i_frame_reference > 1 )
{
int i_slice;
......
......@@ -69,6 +69,7 @@ typedef struct
int p_count;
int s_count;
float blurred_complexity;
char direct_mode;
} ratecontrol_entry_t;
typedef struct
......@@ -380,10 +381,12 @@ int x264_ratecontrol_new( x264_t *h )
return -1;
}
rce = &rc->entry[frame_number];
rce->direct_mode = 0;
e += sscanf(p, " in:%*d out:%*d type:%c q:%f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d",
e += sscanf(p, " in:%*d out:%*d type:%c q:%f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c",
&pict_type, &qp, &rce->i_tex_bits, &rce->p_tex_bits,
&rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count, &rce->s_count);
&rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count,
&rce->s_count, &rce->direct_mode);
switch(pict_type){
case 'I': rce->kept_as_ref = 1;
......@@ -393,7 +396,7 @@ int x264_ratecontrol_new( x264_t *h )
case 'b': rce->pict_type = SLICE_TYPE_B; break;
default: e = -1; break;
}
if(e != 10){
if(e < 10){
x264_log(h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e);
return -1;
}
......@@ -528,12 +531,27 @@ void x264_ratecontrol_delete( x264_t *h )
void x264_ratecontrol_start( x264_t *h, int i_slice_type, int i_force_qp )
{
x264_ratecontrol_t *rc = h->rc;
ratecontrol_entry_t *rce = NULL;
x264_cpu_restore( h->param.cpu );
rc->qp_force = i_force_qp;
rc->slice_type = i_slice_type;
if( h->param.rc.b_stat_read )
{
int frame = h->fenc->i_frame;
assert( frame >= 0 && frame < rc->num_entries );
rce = h->rc->rce = &h->rc->entry[frame];
if( i_slice_type == SLICE_TYPE_B
&& h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO )
{
h->sh.b_direct_spatial_mv_pred = ( rce->direct_mode == 's' );
h->mb.b_direct_auto_read = ( rce->direct_mode == 's' || rce->direct_mode == 't' );
}
}
if( i_force_qp )
{
rc->qpa = rc->qp = i_force_qp - 1;
......@@ -545,11 +563,6 @@ void x264_ratecontrol_start( x264_t *h, int i_slice_type, int i_force_qp )
}
else if( rc->b_2pass )
{
int frame = h->fenc->i_frame;
ratecontrol_entry_t *rce;
assert( frame >= 0 && frame < rc->num_entries );
rce = h->rc->rce = &h->rc->entry[frame];
rce->new_qscale = rate_estimate_qscale( h, i_slice_type );
rc->qpa = rc->qp = rce->new_qp =
x264_clip3( (int)(qscale2qp(rce->new_qscale) + 0.5), 0, 51 );
......@@ -646,15 +659,22 @@ void x264_ratecontrol_end( x264_t *h, int bits )
char c_type = rc->slice_type==SLICE_TYPE_I ? (h->fenc->i_poc==0 ? 'I' : 'i')
: rc->slice_type==SLICE_TYPE_P ? 'P'
: h->fenc->b_kept_as_ref ? 'B' : 'b';
int dir_frame = h->stat.frame.i_direct_score[1] - h->stat.frame.i_direct_score[0];
int dir_avg = h->stat.i_direct_score[1] - h->stat.i_direct_score[0];
char c_direct = h->mb.b_direct_auto_write ?
( dir_frame>0 ? 's' : dir_frame<0 ? 't' :
dir_avg>0 ? 's' : dir_avg<0 ? 't' : '-' )
: '-';
fprintf( rc->p_stat_file_out,
"in:%d out:%d type:%c q:%.2f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d;\n",
"in:%d out:%d type:%c q:%.2f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c;\n",
h->fenc->i_frame, h->i_frame-1,
c_type, rc->qpa,
h->stat.frame.i_itex_bits, h->stat.frame.i_ptex_bits,
h->stat.frame.i_hdr_bits, h->stat.frame.i_misc_bits,
h->stat.frame.i_mb_count_i,
h->stat.frame.i_mb_count_p,
h->stat.frame.i_mb_count_skip);
h->stat.frame.i_mb_count_skip,
c_direct);
}
if( rc->b_abr )
......
......@@ -246,7 +246,7 @@ static void Help( x264_param_t *defaults )
" - none, all\n"
" (p4x4 requires p8x8. i8x8 requires --8x8dct.)\n"
" --direct <string> Direct MV prediction mode [\"%s\"]\n"
" - none, spatial, temporal\n"
" - none, spatial, temporal, auto\n"
" -w, --weightb Weighted prediction for B-frames\n"
" --me <string> Integer pixel motion estimation method [\"%s\"]\n"
" - dia: diamond search, radius 1 (fast)\n"
......
......@@ -35,7 +35,7 @@
#include <stdarg.h>
#define X264_BUILD 44
#define X264_BUILD 45
/* x264_t:
* opaque handler for decoder and encoder */
......@@ -64,6 +64,7 @@ typedef struct x264_t x264_t;
#define X264_DIRECT_PRED_NONE 0
#define X264_DIRECT_PRED_SPATIAL 1
#define X264_DIRECT_PRED_TEMPORAL 2
#define X264_DIRECT_PRED_AUTO 3
#define X264_ME_DIA 0
#define X264_ME_HEX 1
#define X264_ME_UMH 2
......@@ -72,7 +73,7 @@ typedef struct x264_t x264_t;
#define X264_CQM_JVT 1
#define X264_CQM_CUSTOM 2
static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", 0 };
static const char * const x264_direct_pred_names[] = { "none", "spatial", "temporal", "auto", 0 };
static const char * const x264_motion_est_names[] = { "dia", "hex", "umh", "esa", 0 };
/* Colorspace type
......
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