From 68f3ccd1ebecfa09579e770a49782770e3ef0960 Mon Sep 17 00:00:00 2001 From: Yunqing Wang Date: Tue, 23 May 2017 14:43:54 -0700 Subject: [PATCH] Add MV refining search in warped motion experiment Implemented a MV refining search after the warped motion parameters were found. Only 4 or 8 positions were checked so there was almost no impact on encoder speed. Borg test result: avg_psnr ovr_psnr ssim cam_lowres: -0.543% -0.574% -0.670% lowres : -0.222% -0.230% -0.285% Change-Id: Ic2f6c1fe548b089d50e9c33bb365e6b128aabc93 --- av1/encoder/mcomp.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++ av1/encoder/mcomp.h | 10 ++++++ av1/encoder/rdopt.c | 53 +++++++++++++++++++++++++++-- 3 files changed, 156 insertions(+), 3 deletions(-) diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c index 6d561f3fd7..52080ca0d4 100644 --- a/av1/encoder/mcomp.c +++ b/av1/encoder/mcomp.c @@ -967,6 +967,102 @@ int av1_find_best_sub_pixel_tree( #undef PRE #undef CHECK_BETTER +#if CONFIG_WARPED_MOTION +unsigned int av1_compute_motion_cost(const AV1_COMP *cpi, MACROBLOCK *const x, + BLOCK_SIZE bsize, int mi_row, int mi_col, + const MV *this_mv) { + const AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + MODE_INFO *mi = xd->mi[0]; + MB_MODE_INFO *mbmi = &mi->mbmi; + const uint8_t *const src = x->plane[0].src.buf; + const int src_stride = x->plane[0].src.stride; + uint8_t *const dst = xd->plane[0].dst.buf; + const int dst_stride = xd->plane[0].dst.stride; + const aom_variance_fn_ptr_t *vfp = &cpi->fn_ptr[bsize]; + const MV ref_mv = x->mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0].as_mv; + unsigned int mse; + unsigned int sse; + + av1_build_inter_predictors_sby(cm, xd, mi_row, mi_col, NULL, bsize); + mse = vfp->vf(dst, dst_stride, src, src_stride, &sse); + mse += + mv_err_cost(this_mv, &ref_mv, x->nmvjointcost, x->mvcost, x->errorperbit); + return mse; +} + +// Refine MV in a small range +unsigned int av1_refine_warped_mv(const AV1_COMP *cpi, MACROBLOCK *const x, + BLOCK_SIZE bsize, int mi_row, int mi_col, + int *pts, int *pts_inref) { + const AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *xd = &x->e_mbd; + MODE_INFO *mi = xd->mi[0]; + MB_MODE_INFO *mbmi = &mi->mbmi; + const MV neighbors[8] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }, + { 0, -2 }, { 2, 0 }, { 0, 2 }, { -2, 0 } }; + const MV ref_mv = x->mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0].as_mv; + int16_t br = mbmi->mv[0].as_mv.row; + int16_t bc = mbmi->mv[0].as_mv.col; + int16_t *tr = &mbmi->mv[0].as_mv.row; + int16_t *tc = &mbmi->mv[0].as_mv.col; + WarpedMotionParams best_wm_params = mbmi->wm_params[0]; + unsigned int bestmse; + int minc, maxc, minr, maxr; + const int start = cm->allow_high_precision_mv ? 0 : 4; + int ite; + + av1_set_subpel_mv_search_range(&x->mv_limits, &minc, &maxc, &minr, &maxr, + &ref_mv); + + // Calculate the center position's error + assert(bc >= minc && bc <= maxc && br >= minr && br <= maxr); + bestmse = av1_compute_motion_cost(cpi, x, bsize, mi_row, mi_col, + &mbmi->mv[0].as_mv); + + // MV search + for (ite = 0; ite < 2; ++ite) { + int best_idx = -1; + int idx; + + for (idx = start; idx < start + 4; ++idx) { + unsigned int thismse; + + *tr = br + neighbors[idx].row; + *tc = bc + neighbors[idx].col; + + if (*tc >= minc && *tc <= maxc && *tr >= minr && *tr <= maxr) { + MV this_mv = { *tr, *tc }; + if (!find_projection(mbmi->num_proj_ref[0], pts, pts_inref, bsize, *tr, + *tc, &mbmi->wm_params[0], mi_row, mi_col)) { + thismse = + av1_compute_motion_cost(cpi, x, bsize, mi_row, mi_col, &this_mv); + + if (thismse < bestmse) { + best_idx = idx; + best_wm_params = mbmi->wm_params[0]; + bestmse = thismse; + } + } + } + } + + if (best_idx == -1) break; + + if (best_idx >= 0) { + br += neighbors[best_idx].row; + bc += neighbors[best_idx].col; + } + } + + *tr = br; + *tc = bc; + mbmi->wm_params[0] = best_wm_params; + + return bestmse; +} +#endif // CONFIG_WARPED_MOTION + static INLINE int check_bounds(const MvLimits *mv_limits, int row, int col, int range) { return ((row - range) >= mv_limits->row_min) & diff --git a/av1/encoder/mcomp.h b/av1/encoder/mcomp.h index 9ed0817b3c..7e8b4b29d5 100644 --- a/av1/encoder/mcomp.h +++ b/av1/encoder/mcomp.h @@ -153,4 +153,14 @@ int av1_find_best_obmc_sub_pixel_tree_up( } // extern "C" #endif +#if CONFIG_WARPED_MOTION +unsigned int av1_compute_motion_cost(const struct AV1_COMP *cpi, + MACROBLOCK *const x, BLOCK_SIZE bsize, + int mi_row, int mi_col, const MV *this_mv); +unsigned int av1_refine_warped_mv(const struct AV1_COMP *cpi, + MACROBLOCK *const x, BLOCK_SIZE bsize, + int mi_row, int mi_col, int *pts, + int *pts_inref); +#endif // CONFIG_WARPED_MOTION + #endif // AV1_ENCODER_MCOMP_H_ diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index caf17b5ebf..d94a8c61fa 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c @@ -7063,6 +7063,7 @@ static int64_t motion_mode_rd( int mi_col, HandleInterModeArgs *const args, const int64_t ref_best_rd, const int *refs, int rate_mv, #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION + int_mv *const single_newmv, #if CONFIG_EXT_INTER int rate2_bmc_nocoeff, MB_MODE_INFO *best_bmc_mbmi, #if CONFIG_MOTION_VAR @@ -7200,9 +7201,54 @@ static int64_t motion_mode_rd( : cm->interp_filter; #endif // CONFIG_DUAL_FILTER - if (find_projection(mbmi->num_proj_ref[0], pts, pts_inref, bsize, - mbmi->mv[0].as_mv.row, mbmi->mv[0].as_mv.col, - &mbmi->wm_params[0], mi_row, mi_col) == 0) { + if (!find_projection(mbmi->num_proj_ref[0], pts, pts_inref, bsize, + mbmi->mv[0].as_mv.row, mbmi->mv[0].as_mv.col, + &mbmi->wm_params[0], mi_row, mi_col)) { + // Refine MV for NEWMV mode + if (!is_comp_pred && have_newmv_in_inter_mode(this_mode)) { + int tmp_rate_mv = 0; + const int_mv mv0 = mbmi->mv[0]; + WarpedMotionParams wm_params0 = mbmi->wm_params[0]; + + // Refine MV in a small range. + av1_refine_warped_mv(cpi, x, bsize, mi_row, mi_col, pts, pts_inref); + + // Keep the refined MV and WM parameters. + if (mv0.as_int != mbmi->mv[0].as_int) { + const int ref = refs[0]; + const MV ref_mv = x->mbmi_ext->ref_mvs[ref][0].as_mv; + + tmp_rate_mv = + av1_mv_bit_cost(&mbmi->mv[0].as_mv, &ref_mv, x->nmvjointcost, + x->mvcost, MV_COST_WEIGHT); + + if (cpi->sf.adaptive_motion_search) + x->pred_mv[ref] = mbmi->mv[0].as_mv; + + single_newmv[ref] = mbmi->mv[0]; + + if (discount_newmv_test(cpi, this_mode, mbmi->mv[0], mode_mv, + refs[0])) { + tmp_rate_mv = AOMMAX((tmp_rate_mv / NEW_MV_DISCOUNT_FACTOR), 1); + } +#if CONFIG_EXT_INTER + tmp_rate2 = rate2_bmc_nocoeff - rate_mv_bmc + tmp_rate_mv; +#else + tmp_rate2 = rate2_nocoeff - rate_mv + tmp_rate_mv; +#endif // CONFIG_EXT_INTER +#if CONFIG_DUAL_FILTER + if (!has_subpel_mv_component(xd->mi[0], xd, 0)) + mbmi->interp_filter[0] = EIGHTTAP_REGULAR; + if (!has_subpel_mv_component(xd->mi[0], xd, 1)) + mbmi->interp_filter[1] = EIGHTTAP_REGULAR; +#endif // CONFIG_DUAL_FILTER + } else { + // Restore the old MV and WM parameters. + mbmi->mv[0] = mv0; + mbmi->wm_params[0] = wm_params0; + } + } + av1_build_inter_predictors_sb(cm, xd, mi_row, mi_col, NULL, bsize); model_rd_for_sb(cpi, bsize, x, xd, 0, MAX_MB_PLANE - 1, &tmp_rate, &tmp_dist, skip_txfm_sb, skip_sse_sb); @@ -8040,6 +8086,7 @@ static int64_t handle_inter_mode( disable_skip, mode_mv, mi_row, mi_col, args, ref_best_rd, refs, rate_mv, #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION + single_newmv, #if CONFIG_EXT_INTER rate2_bmc_nocoeff, &best_bmc_mbmi, #if CONFIG_MOTION_VAR -- 2.11.4.GIT