From: Fiona Glaser Date: Wed, 17 Sep 2008 07:33:37 +0000 (-0700) Subject: Use low-resolution lookahead motion vectors as an extra predictor X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c4f3dabecde673fabcefa832fff490af9d738641;p=libx264 Use low-resolution lookahead motion vectors as an extra predictor Improves quality considerably (0-5%) in 1pass/CRF mode, especially with lower --me values and complex motion. Reverses the order of lowres lookahead search to improve the usefulness of the extra predictors. --- diff --git a/common/macroblock.c b/common/macroblock.c index 0806ea7e..883b515e 100644 --- a/common/macroblock.c +++ b/common/macroblock.c @@ -416,7 +416,7 @@ void x264_mb_load_mv_direct8x8( x264_t *h, int idx ) } /* This just improves encoder performance, it's not part of the spec */ -void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[8][2], int *i_mvc ) +void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[9][2], int *i_mvc ) { int16_t (*mvr)[2] = h->mb.mvr[i_list][i_ref]; int i = 0; @@ -433,6 +433,13 @@ void x264_mb_predict_mv_ref16x16( x264_t *h, int i_list, int i_ref, int16_t mvc[ SET_MVP( h->mb.cache.mv[i_list][x264_scan8[12]] ); } + if( i_ref == 0 && h->frames.b_have_lowres ) + { + int16_t (*lowres_mv)[2] = i_list ? h->fenc->lowres_mvs[1][h->fref1[0]->i_frame-h->fenc->i_frame-1] + : h->fenc->lowres_mvs[0][h->fenc->i_frame-h->fref0[0]->i_frame-1]; + if( lowres_mv[0][0] != 0x7fff ) *(uint32_t*)mvc[i++] = (*(uint32_t*)lowres_mv[h->mb.i_mb_xy]*2)&0xfffeffff; + } + /* spatial predictors */ if( h->mb.i_neighbour & MB_LEFT ) { diff --git a/encoder/analyse.c b/encoder/analyse.c index 2a294ff2..ecbaf4ec 100644 --- a/encoder/analyse.c +++ b/encoder/analyse.c @@ -1016,7 +1016,7 @@ static void x264_mb_analyse_inter_p16x16( x264_t *h, x264_mb_analysis_t *a ) { x264_me_t m; int i_ref, i_mvc; - DECLARE_ALIGNED_4( int16_t mvc[7][2] ); + DECLARE_ALIGNED_4( int16_t mvc[8][2] ); int i_halfpel_thresh = INT_MAX; int *p_halfpel_thresh = h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : NULL; @@ -1493,7 +1493,7 @@ static void x264_mb_analyse_inter_b16x16( x264_t *h, x264_mb_analysis_t *a ) x264_me_t m; int i_ref, i_mvc; - DECLARE_ALIGNED_4( int16_t mvc[8][2] ); + DECLARE_ALIGNED_4( int16_t mvc[9][2] ); int i_halfpel_thresh = INT_MAX; int *p_halfpel_thresh = h->mb.pic.i_fref[0]>1 ? &i_halfpel_thresh : NULL; diff --git a/encoder/slicetype.c b/encoder/slicetype.c index fd06d413..04034f19 100644 --- a/encoder/slicetype.c +++ b/encoder/slicetype.c @@ -150,16 +150,17 @@ static int x264_slicetype_mb_cost( x264_t *h, x264_mb_analysis_t *a, if( do_search[l] ) { + /* Reverse-order MV prediction. */ #define MVC(mv) { *(uint32_t*)mvc[i_mvc] = *(uint32_t*)mv; i_mvc++; } - if( i_mb_x > 0 ) - MVC(fenc_mv[-1]); - if( i_mb_y > 0 ) + if( i_mb_x < h->sps->i_mb_width - 1 ) + MVC(fenc_mv[1]); + if( i_mb_y < h->sps->i_mb_height - 1 ) { - MVC(fenc_mv[-i_mb_stride]); - if( i_mb_x < h->sps->i_mb_width - 1 ) - MVC(fenc_mv[-i_mb_stride+1]); + MVC(fenc_mv[i_mb_stride]); if( i_mb_x > 0 ) - MVC(fenc_mv[-i_mb_stride-1]); + MVC(fenc_mv[i_mb_stride-1]); + if( i_mb_x < h->sps->i_mb_width - 1 ) + MVC(fenc_mv[i_mb_stride+1]); } #undef MVC x264_median_mv( m[l].mvp, mvc[0], mvc[1], mvc[2] ); @@ -288,20 +289,22 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, if( p1 != p0 ) dist_scale_factor = ( ((b-p0) << 8) + ((p1-p0) >> 1) ) / (p1-p0); + /* Lowres lookahead goes backwards because the MVs are used as predictors in the main encode. */ + /* This considerably improves MV prediction overall. */ if( h->sps->i_mb_width <= 2 || h->sps->i_mb_height <= 2 ) { - for( h->mb.i_mb_y = 0; h->mb.i_mb_y < h->sps->i_mb_height; h->mb.i_mb_y++ ) - for( h->mb.i_mb_x = 0; h->mb.i_mb_x < h->sps->i_mb_width; h->mb.i_mb_x++ ) + for( h->mb.i_mb_y = h->sps->i_mb_height - 1; h->mb.i_mb_y >= 0 ; h->mb.i_mb_y-- ) + for( h->mb.i_mb_x = h->sps->i_mb_width - 1; h->mb.i_mb_x >= 0 ; h->mb.i_mb_x-- ) i_score += x264_slicetype_mb_cost( h, a, frames, p0, p1, b, dist_scale_factor, do_search ); } /* the edge mbs seem to reduce the predictive quality of the * whole frame's score, but are needed for a spatial distribution. */ else if( h->param.rc.i_vbv_buffer_size ) { - for( h->mb.i_mb_y = 0; h->mb.i_mb_y < h->sps->i_mb_height; h->mb.i_mb_y++ ) + for( h->mb.i_mb_y = h->sps->i_mb_height - 1; h->mb.i_mb_y >= 0; h->mb.i_mb_y-- ) { row_satd[ h->mb.i_mb_y ] = 0; - for( h->mb.i_mb_x = 0; h->mb.i_mb_x < h->sps->i_mb_width; h->mb.i_mb_x++ ) + for( h->mb.i_mb_x = h->sps->i_mb_width - 1; h->mb.i_mb_x >= 0; h->mb.i_mb_x-- ) { int i_mb_cost = x264_slicetype_mb_cost( h, a, frames, p0, p1, b, dist_scale_factor, do_search ); int i_mb_cost_aq = i_mb_cost; @@ -323,8 +326,8 @@ static int x264_slicetype_frame_cost( x264_t *h, x264_mb_analysis_t *a, } else { - for( h->mb.i_mb_y = 1; h->mb.i_mb_y < h->sps->i_mb_height - 1; h->mb.i_mb_y++ ) - for( h->mb.i_mb_x = 1; h->mb.i_mb_x < h->sps->i_mb_width - 1; h->mb.i_mb_x++ ) + for( h->mb.i_mb_y = h->sps->i_mb_height - 2; h->mb.i_mb_y > 0; h->mb.i_mb_y-- ) + for( h->mb.i_mb_x = h->sps->i_mb_width - 2; h->mb.i_mb_x > 0; h->mb.i_mb_x-- ) { int i_mb_cost = x264_slicetype_mb_cost( h, a, frames, p0, p1, b, dist_scale_factor, do_search ); int i_mb_cost_aq = i_mb_cost;