From 85b66463a2ceb895c7842350f7a992082c64b523 Mon Sep 17 00:00:00 2001 From: Zoe Liu Date: Thu, 20 Apr 2017 14:28:19 -0700 Subject: [PATCH] Add encoder/decoder pipeline to support single ref comp modes Now the single ref comp mode should work with WEDGE and COMPOUND_SEGMENT. For motion_var, the OBMC_CAUSAL mode uses the 2nd predictor if the neighboring block is single ref comp mode predicted. This patch removes the mode of SR_NEAREST_NEWMV and leaves four single ref comp modes in total: SR_NEAREST_NEARMV SR_NEAR_NEWMV SR_ZERO_NEWMV SR_NEW_NEWMV Change-Id: If6140455771f0f1a3b947766eccf82f23cc6b67a --- av1/common/av1_loopfilter.c | 5 + av1/common/blockd.h | 37 +- av1/common/entropymode.c | 23 +- av1/common/enums.h | 2 +- av1/common/mvref_common.h | 2 +- av1/common/pred_common.c | 35 +- av1/common/reconinter.c | 76 +++- av1/common/reconinter.h | 17 +- av1/decoder/decodeframe.c | 56 ++- av1/decoder/decodemv.c | 254 +++++++++++++- av1/encoder/bitstream.c | 205 +++++++++-- av1/encoder/encodeframe.c | 78 ++++- av1/encoder/encodemv.c | 23 +- av1/encoder/encoder.h | 4 + av1/encoder/mcomp.c | 6 + av1/encoder/rd.c | 54 +++ av1/encoder/rd.h | 48 +++ av1/encoder/rdopt.c | 663 +++++++++++++++++++++++++++++++---- av1/encoder/speed_features.h | 7 +- configure | 1 + 20 files changed, 1436 insertions(+), 160 deletions(-) diff --git a/av1/common/av1_loopfilter.c b/av1/common/av1_loopfilter.c index 4b27ae93b..e08aef9ee 100644 --- a/av1/common/av1_loopfilter.c +++ b/av1/common/av1_loopfilter.c @@ -273,6 +273,11 @@ static const int mode_lf_lut[] = { #endif // CONFIG_ALT_INTRA 1, 1, 0, 1, // INTER_MODES (ZEROMV == 0) #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + // 1, 1, 1, 1, 1, // INTER_SINGLEREF_COMP_MODES + // NOTE(zoeliu): Remove SR_NEAREST_NEWMV + 1, 1, 1, 1, // INTER_SINGLEREF_COMP_MODES +#endif // CONFIG_COMPOUND_SINGLEREF 1, 1, 1, 1, 1, 1, 0, 1 // INTER_COMPOUND_MODES (ZERO_ZEROMV == 0) #endif // CONFIG_EXT_INTER }; diff --git a/av1/common/blockd.h b/av1/common/blockd.h index e134548fa..a7a633204 100644 --- a/av1/common/blockd.h +++ b/av1/common/blockd.h @@ -119,14 +119,17 @@ typedef struct { static INLINE int is_inter_singleref_mode(PREDICTION_MODE mode) { return mode >= NEARESTMV && mode <= NEWMV; } +static INLINE int is_inter_compound_mode(PREDICTION_MODE mode) { + return mode >= NEAREST_NEARESTMV && mode <= NEW_NEWMV; +} #if CONFIG_COMPOUND_SINGLEREF static INLINE int is_inter_singleref_comp_mode(PREDICTION_MODE mode) { return mode >= SR_NEAREST_NEARMV && mode <= SR_NEW_NEWMV; } -#endif // CONFIG_COMPOUND_SINGLEREF -static INLINE int is_inter_compound_mode(PREDICTION_MODE mode) { - return mode >= NEAREST_NEARESTMV && mode <= NEW_NEWMV; +static INLINE int is_inter_anyref_comp_mode(PREDICTION_MODE mode) { + return is_inter_compound_mode(mode) || is_inter_singleref_comp_mode(mode); } +#endif // CONFIG_COMPOUND_SINGLEREF static INLINE PREDICTION_MODE compound_ref0_mode(PREDICTION_MODE mode) { static PREDICTION_MODE lut[] = { @@ -153,7 +156,7 @@ static INLINE PREDICTION_MODE compound_ref0_mode(PREDICTION_MODE mode) { MB_MODE_COUNT, // NEWMV #if CONFIG_COMPOUND_SINGLEREF NEARESTMV, // SR_NEAREST_NEARMV - NEARESTMV, // SR_NEAREST_NEWMV + // NEARESTMV, // SR_NEAREST_NEWMV NEARMV, // SR_NEAR_NEWMV ZEROMV, // SR_ZERO_NEWMV NEWMV, // SR_NEW_NEWMV @@ -168,7 +171,11 @@ static INLINE PREDICTION_MODE compound_ref0_mode(PREDICTION_MODE mode) { NEWMV, // NEW_NEWMV }; assert(NELEMENTS(lut) == MB_MODE_COUNT); +#if CONFIG_COMPOUND_SINGLEREF + assert(is_inter_anyref_comp_mode(mode)); +#else // !CONFIG_COMPOUND_SINGLEREF assert(is_inter_compound_mode(mode)); +#endif // CONFIG_COMPOUND_SINGLEREF return lut[mode]; } @@ -196,8 +203,8 @@ static INLINE PREDICTION_MODE compound_ref1_mode(PREDICTION_MODE mode) { MB_MODE_COUNT, // ZEROMV MB_MODE_COUNT, // NEWMV #if CONFIG_COMPOUND_SINGLEREF - NEARMV, // SR_NEAREST_NEARMV - NEWMV, // SR_NEAREST_NEWMV + NEARMV, // SR_NEAREST_NEARMV + // NEWMV, // SR_NEAREST_NEWMV NEWMV, // SR_NEAR_NEWMV NEWMV, // SR_ZERO_NEWMV NEWMV, // SR_NEW_NEWMV @@ -212,17 +219,28 @@ static INLINE PREDICTION_MODE compound_ref1_mode(PREDICTION_MODE mode) { NEWMV, // NEW_NEWMV }; assert(NELEMENTS(lut) == MB_MODE_COUNT); +#if CONFIG_COMPOUND_SINGLEREF + assert(is_inter_anyref_comp_mode(mode)); +#else // !CONFIG_COMPOUND_SINGLEREF assert(is_inter_compound_mode(mode)); +#endif // CONFIG_COMPOUND_SINGLEREF return lut[mode]; } static INLINE int have_nearmv_in_inter_mode(PREDICTION_MODE mode) { return (mode == NEARMV || mode == NEAR_NEARMV || mode == NEAR_NEWMV || +#if CONFIG_COMPOUND_SINGLEREF + mode == SR_NEAREST_NEARMV || mode == SR_NEAR_NEWMV || +#endif // CONFIG_COMPOUND_SINGLEREF mode == NEW_NEARMV); } static INLINE int have_newmv_in_inter_mode(PREDICTION_MODE mode) { return (mode == NEWMV || mode == NEW_NEWMV || mode == NEAREST_NEWMV || +#if CONFIG_COMPOUND_SINGLEREF + /* mode == SR_NEAREST_NEWMV || */ mode == SR_NEAR_NEWMV || + mode == SR_ZERO_NEWMV || mode == SR_NEW_NEWMV || +#endif // CONFIG_COMPOUND_SINGLEREF mode == NEW_NEARESTMV || mode == NEAR_NEWMV || mode == NEW_NEARMV); } @@ -246,7 +264,8 @@ static INLINE int is_masked_compound_type(COMPOUND_TYPE type) { (void)type; return 0; } -#else + +#else // !CONFIG_EXT_INTER static INLINE int have_nearmv_in_inter_mode(PREDICTION_MODE mode) { return (mode == NEARMV); @@ -1256,7 +1275,11 @@ static INLINE int is_motion_variation_allowed_bsize(BLOCK_SIZE bsize) { static INLINE int is_motion_variation_allowed_compound( const MB_MODE_INFO *mbmi) { +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi) && !is_inter_singleref_comp_mode(mbmi->mode)) +#else if (!has_second_ref(mbmi)) +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF return 1; else return 0; diff --git a/av1/common/entropymode.c b/av1/common/entropymode.c index 3d8bf11fc..34842dc1e 100644 --- a/av1/common/entropymode.c +++ b/av1/common/entropymode.c @@ -1027,6 +1027,7 @@ static const aom_prob default_inter_compound_mode_probs #if CONFIG_COMPOUND_SINGLEREF // TODO(zoeliu): Default values to be further adjusted based on the collected // stats. +/* static const aom_prob default_inter_singleref_comp_mode_probs [INTER_MODE_CONTEXTS][INTER_SINGLEREF_COMP_MODES - 1] = { { 2, 173, 68, 180 }, // 0 = both zero mv @@ -1036,6 +1037,16 @@ static const aom_prob default_inter_singleref_comp_mode_probs { 8, 64, 64, 180 }, // 4 = two new mvs { 17, 81, 52, 180 }, // 5 = one intra neighbour { 25, 29, 50, 180 }, // 6 = two intra neighbours + };*/ +static const aom_prob default_inter_singleref_comp_mode_probs + [INTER_MODE_CONTEXTS][INTER_SINGLEREF_COMP_MODES - 1] = { + { 2, 173, 68 }, // 0 = both zero mv + { 7, 145, 160 }, // 1 = 1 zero + 1 predicted + { 7, 166, 126 }, // 2 = two predicted mvs + { 7, 94, 132 }, // 3 = 1 pred/zero, 1 new + { 8, 64, 64 }, // 4 = two new mvs + { 17, 81, 52 }, // 5 = one intra neighbour + { 25, 29, 50 }, // 6 = two intra neighbours }; #endif // CONFIG_COMPOUND_SINGLEREF @@ -1280,6 +1291,8 @@ const aom_tree_index av1_inter_compound_mode_tree }; #if CONFIG_COMPOUND_SINGLEREF +// TODO(zoeliu): To redesign the tree structure once the number of mode changes. +/* const aom_tree_index av1_inter_singleref_comp_mode_tree [TREE_SIZE(INTER_SINGLEREF_COMP_MODES)] = { -INTER_SINGLEREF_COMP_OFFSET(SR_ZERO_NEWMV), 2, @@ -1287,6 +1300,14 @@ const aom_tree_index av1_inter_singleref_comp_mode_tree 6, -INTER_SINGLEREF_COMP_OFFSET(SR_NEW_NEWMV), -INTER_SINGLEREF_COMP_OFFSET(SR_NEAREST_NEWMV), -INTER_SINGLEREF_COMP_OFFSET(SR_NEAR_NEWMV) +};*/ + +const aom_tree_index av1_inter_singleref_comp_mode_tree + [TREE_SIZE(INTER_SINGLEREF_COMP_MODES)] = { + -INTER_SINGLEREF_COMP_OFFSET(SR_ZERO_NEWMV), 2, + -INTER_SINGLEREF_COMP_OFFSET(SR_NEAREST_NEARMV), 4, + -INTER_SINGLEREF_COMP_OFFSET(SR_NEAR_NEWMV), + -INTER_SINGLEREF_COMP_OFFSET(SR_NEW_NEWMV) }; #endif // CONFIG_COMPOUND_SINGLEREF @@ -1368,7 +1389,7 @@ static const aom_prob default_single_ref_p[REF_CONTEXTS][SINGLE_REFS - 1] = { // TODO(zoeliu): Default values to be further adjusted based on the collected // stats. static const aom_prob default_comp_inter_mode_p[COMP_INTER_MODE_CONTEXTS] = { - 41, 119, 187, 225 + 40, 110, 160, 220 }; #endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF diff --git a/av1/common/enums.h b/av1/common/enums.h index 3f905deaa..d105f9435 100644 --- a/av1/common/enums.h +++ b/av1/common/enums.h @@ -346,7 +346,7 @@ typedef enum ATTRIBUTE_PACKED { #if CONFIG_COMPOUND_SINGLEREF // Single ref compound modes SR_NEAREST_NEARMV, - SR_NEAREST_NEWMV, + // SR_NEAREST_NEWMV, SR_NEAR_NEWMV, SR_ZERO_NEWMV, SR_NEW_NEWMV, diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h index ec5edeeab..209a63612 100644 --- a/av1/common/mvref_common.h +++ b/av1/common/mvref_common.h @@ -66,7 +66,7 @@ static const int mode_2_counter[] = { #if CONFIG_EXT_INTER #if CONFIG_COMPOUND_SINGLEREF 0, // SR_NEAREST_NEARMV - 1, // SR_NEAREST_NEWMV + // 1, // SR_NEAREST_NEWMV 1, // SR_NEAR_NEWMV 3, // SR_ZERO_NEWMV 1, // SR_NEW_NEWMV diff --git a/av1/common/pred_common.c b/av1/common/pred_common.c index 51c343d19..bda1fc541 100644 --- a/av1/common/pred_common.c +++ b/av1/common/pred_common.c @@ -223,27 +223,34 @@ int av1_get_intra_inter_context(const MACROBLOCKD *xd) { // The compound/single mode info data structure has one element border above and // to the left of the entries corresponding to real macroblocks. // The prediction flags in these dummy entries are initialized to 0. -// 0 - single/single -// 1 - single/--, --/single, --/-- -// 2 - single/comp, comp/single -// 3 - comp/comp, comp/--, --/comp int av1_get_inter_mode_context(const MACROBLOCKD *xd) { const MB_MODE_INFO *const above_mbmi = xd->above_mbmi; const MB_MODE_INFO *const left_mbmi = xd->left_mbmi; const int has_above = xd->up_available; const int has_left = xd->left_available; - if (has_above && has_left) { // both edges available (0/2/3) - const int above_inter_comp_mode = is_inter_compound_mode(above_mbmi->mode); - const int left_inter_comp_mode = is_inter_compound_mode(left_mbmi->mode); - return (above_inter_comp_mode && left_inter_comp_mode) - ? 3 - : (above_inter_comp_mode || left_inter_comp_mode) * 2; - } else if (has_above || has_left) { // one edge available (1/3) + if (has_above && has_left) { // both edges available + const int above_inter_comp_mode = + is_inter_anyref_comp_mode(above_mbmi->mode); + const int left_inter_comp_mode = is_inter_anyref_comp_mode(left_mbmi->mode); + if (above_inter_comp_mode && left_inter_comp_mode) + return 0; + else if (above_inter_comp_mode || left_inter_comp_mode) + return 1; + else if (!is_inter_block(above_mbmi) && !is_inter_block(left_mbmi)) + return 2; + else + return 3; + } else if (has_above || has_left) { // one edge available const MB_MODE_INFO *const edge_mbmi = has_above ? above_mbmi : left_mbmi; - return is_inter_compound_mode(edge_mbmi->mode) ? 3 : 1; - } else { // no edge available (1) - return 1; + if (is_inter_anyref_comp_mode(edge_mbmi->mode)) + return 1; + else if (!is_inter_block(edge_mbmi)) + return 2; + else + return 3; + } else { // no edge available + return 2; } } #endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c index a0d1b63ab..8ca06c0b4 100644 --- a/av1/common/reconinter.c +++ b/av1/common/reconinter.c @@ -710,7 +710,8 @@ void av1_make_masked_inter_predictor(const uint8_t *pre, int pre_stride, int p_col, int p_row, int ref, #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION MACROBLOCKD *xd) { - MODE_INFO *mi = xd->mi[0]; + const MODE_INFO *mi = xd->mi[0]; + const INTERINTER_COMPOUND_DATA comp_data = { #if CONFIG_WEDGE mi->mbmi.wedge_index, @@ -903,6 +904,10 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, const MODE_INFO *mi = xd->mi[0]; #endif // CONFIG_MOTION_VAR int is_compound = has_second_ref(&mi->mbmi); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int is_comp_mode_pred = + is_compound || is_inter_singleref_comp_mode(mi->mbmi.mode); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF int ref; #if CONFIG_INTRABC const int is_intrabc = is_intrabc_block(&mi->mbmi); @@ -914,6 +919,9 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, WarpedMotionParams *const wm = &xd->global_motion[mi->mbmi.ref_frame[ref]]; is_global[ref] = is_global_mv_block(mi, block, wm->wmtype); } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!is_compound && is_comp_mode_pred) is_global[1] = is_global[0]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_GLOBAL_MOTION #if CONFIG_CB4X4 @@ -968,7 +976,8 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, for (idx = 0; idx < b8_w; idx += b4_w) { MB_MODE_INFO *this_mbmi = &xd->mi[row * xd->mi_stride + col]->mbmi; is_compound = has_second_ref(this_mbmi); - + // TODO(zoeliu): If single ref comp modes are considered here, a + // mismatch was caused. Need a further investigation. for (ref = 0; ref < 1 + is_compound; ++ref) { struct buf_2d *const dst_buf = &pd->dst; @@ -1065,7 +1074,7 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION #if CONFIG_MOTION_VAR mi_col_offset, mi_row_offset, -#endif +#endif // CONFIG_MOTION_VAR xs, ys, xd); } ++col; @@ -1091,7 +1100,11 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, av1_zero(tmp_dst); #endif // CONFIG_CONVOLVE_ROUND +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + is_comp_mode_pred; ++ref) { +#else for (ref = 0; ref < 1 + is_compound; ++ref) { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #if CONFIG_INTRABC const struct scale_factors *const sf = is_intrabc ? &xd->sf_identity : &xd->block_refs[ref]->sf; @@ -1149,7 +1162,12 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, #else ConvolveParams conv_params = get_conv_params(ref, ref, plane); #endif // CONFIG_CONVOLVE_ROUND + +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + is_comp_mode_pred; ++ref) { +#else for (ref = 0; ref < 1 + is_compound; ++ref) { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #if CONFIG_INTRABC const struct scale_factors *const sf = is_intrabc ? &xd->sf_identity : &xd->block_refs[ref]->sf; @@ -1197,7 +1215,7 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION #if CONFIG_MOTION_VAR mi_col_offset, mi_row_offset, -#endif +#endif // CONFIG_MOTION_VAR subpel_params[ref].xs, subpel_params[ref].ys, xd); } @@ -1213,9 +1231,15 @@ void build_inter_predictors(const AV1_COMMON *cm, MACROBLOCKD *xd, int plane, xd->bd); else #endif // CONFIG_HIGHBITDEPTH +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF av1_convolve_rounding(tmp_dst, MAX_SB_SIZE, dst, dst_buf->stride, w, h, - FILTER_BITS * 2 + is_compound - + FILTER_BITS * 2 + is_comp_mode_pred - conv_params.round_0 - conv_params.round_1); +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) + av1_convolve_rounding(tmp_dst, MAX_SB_SIZE, dst, dst_buf->stride, w, h, + FILTER_BITS * 2 + is_compound - + conv_params.round_0 - conv_params.round_1); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } #endif // CONFIG_CONVOLVE_ROUND } @@ -1962,6 +1986,14 @@ void modify_neighbor_predictor_for_obmc(MB_MODE_INFO *mbmi) { is_masked_compound_type(mbmi->interinter_compound_type)) { mbmi->interinter_compound_type = COMPOUND_AVERAGE; mbmi->ref_frame[1] = NONE_FRAME; +#if CONFIG_COMPOUND_SINGLEREF + } else if (!has_second_ref(mbmi) && + is_inter_singleref_comp_mode(mbmi->mode)) { + // mbmi->mode = compound_ref0_mode(mbmi->mode); + mbmi->mode = compound_ref1_mode(mbmi->mode); + assert(is_inter_singleref_mode(mbmi->mode)); + mbmi->mv[0].as_int = mbmi->mv[1].as_int; +#endif // CONFIG_COMPOUND_SINGLEREF } #endif // CONFIG_EXT_INTER if (has_second_ref(mbmi)) mbmi->ref_frame[1] = NONE_FRAME; @@ -2018,8 +2050,16 @@ void av1_build_prediction_by_above_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, tmp_height[j], tmp_stride[j], 0, i, NULL, pd->subsampling_x, pd->subsampling_y); } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(above_mbmi->mode)); + ++ref) { + const MV_REFERENCE_FRAME frame = has_second_ref(above_mbmi) + ? above_mbmi->ref_frame[ref] + : above_mbmi->ref_frame[0]; +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) for (ref = 0; ref < 1 + has_second_ref(above_mbmi); ++ref) { const MV_REFERENCE_FRAME frame = above_mbmi->ref_frame[ref]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME]; xd->block_refs[ref] = ref_buf; @@ -2107,8 +2147,16 @@ void av1_build_prediction_by_left_preds(const AV1_COMMON *cm, MACROBLOCKD *xd, tmp_height[j], tmp_stride[j], i, 0, NULL, pd->subsampling_x, pd->subsampling_y); } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + (is_inter_anyref_comp_mode(left_mbmi->mode)); + ++ref) { + const MV_REFERENCE_FRAME frame = has_second_ref(left_mbmi) + ? left_mbmi->ref_frame[ref] + : left_mbmi->ref_frame[0]; +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) for (ref = 0; ref < 1 + has_second_ref(left_mbmi); ++ref) { const MV_REFERENCE_FRAME frame = left_mbmi->ref_frame[ref]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF const RefBuffer *const ref_buf = &cm->frame_refs[frame - LAST_FRAME]; xd->block_refs[ref] = ref_buf; @@ -2561,6 +2609,7 @@ void av1_build_ncobmc_inter_predictors_sb(const AV1_COMMON *cm, MACROBLOCKD *xd, #endif // CONFIG_HIGHBITDEPTH const BLOCK_SIZE bsize = xd->mi[0]->mbmi.sb_type; + // TODO(zoeliu): COMPOUND_SINGLEREF has not worked with NCOBMC yet. av1_build_prediction_by_bottom_preds(cm, xd, mi_row, mi_col, dst_buf1, dst_width1, dst_height1, dst_stride1); av1_build_prediction_by_right_preds(cm, xd, mi_row, mi_col, dst_buf2, @@ -2911,7 +2960,13 @@ static void build_inter_predictors_single_buf(MACROBLOCKD *xd, int plane, #if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION WarpTypesAllowed warp_types; #if CONFIG_GLOBAL_MOTION +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + WarpedMotionParams *const wm = + mi->mbmi.ref_frame[ref] > 0 ? &xd->global_motion[mi->mbmi.ref_frame[ref]] + : &xd->global_motion[mi->mbmi.ref_frame[0]]; +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) WarpedMotionParams *const wm = &xd->global_motion[mi->mbmi.ref_frame[ref]]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF warp_types.global_warp_allowed = is_global_mv_block(mi, block, wm->wmtype); #endif // CONFIG_GLOBAL_MOTION #if CONFIG_WARPED_MOTION @@ -2966,6 +3021,10 @@ void av1_build_inter_predictors_for_planes_single_buf( const int num_4x4_w = num_4x4_blocks_wide_lookup[plane_bsize]; const int num_4x4_h = num_4x4_blocks_high_lookup[plane_bsize]; assert(bsize == BLOCK_8X8); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + assert(has_second_ref(&xd->mi[0]->mbmi) || + !is_inter_singleref_comp_mode(xd->mi[0]->mbmi.mode)); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF for (y = 0; y < num_4x4_h; ++y) for (x = 0; x < num_4x4_w; ++x) build_inter_predictors_single_buf( @@ -3003,7 +3062,12 @@ static void build_wedge_inter_predictor_from_buf( mbmi->interinter_compound_type }; +#if CONFIG_COMPOUND_SINGLEREF + if ((is_compound || is_inter_singleref_comp_mode(mbmi->mode)) && + is_masked_compound_type(mbmi->interinter_compound_type)) { +#else // !CONFIG_COMPOUND_SINGLEREF if (is_compound && is_masked_compound_type(mbmi->interinter_compound_type)) { +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_COMPOUND_SEGMENT if (!plane && comp_data.interinter_compound_type == COMPOUND_SEG) { #if CONFIG_HIGHBITDEPTH @@ -3034,7 +3098,7 @@ static void build_wedge_inter_predictor_from_buf( dst, dst_buf->stride, ext_dst0, ext_dst_stride0, ext_dst1, ext_dst_stride1, &comp_data, mbmi->sb_type, wedge_offset_x, wedge_offset_y, h, w); -#else +#else // !CONFIG_SUPERTX #if CONFIG_HIGHBITDEPTH if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) build_masked_compound_highbd( diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h index 7ea42896f..2977864aa 100644 --- a/av1/common/reconinter.h +++ b/av1/common/reconinter.h @@ -407,14 +407,23 @@ static INLINE void av1_make_inter_predictor( #if CONFIG_WARPED_MOTION || CONFIG_GLOBAL_MOTION WarpedMotionParams final_warp_params; - const int do_warp = allow_warp(mi, warp_types, + const int do_warp = allow_warp( + mi, warp_types, #if CONFIG_GLOBAL_MOTION - &xd->global_motion[mi->mbmi.ref_frame[ref]], +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // TODO(zoeliu): To further check the single + // ref comp mode to work together with + // global motion. + has_second_ref(&mi->mbmi) ? &xd->global_motion[mi->mbmi.ref_frame[ref]] + : &xd->global_motion[mi->mbmi.ref_frame[0]], +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) + &xd->global_motion[mi->mbmi.ref_frame[ref]], +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_GLOBAL_MOTION #if CONFIG_MOTION_VAR - mi_col_offset, mi_row_offset, + mi_col_offset, mi_row_offset, #endif // CONFIG_MOTION_VAR - &final_warp_params); + &final_warp_params); if (do_warp) { const struct macroblockd_plane *const pd = &xd->plane[plane]; const struct buf_2d *const pre_buf = &pd->pre[ref]; diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 5e5db9322..37583d6ff 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c @@ -215,7 +215,23 @@ static void read_inter_compound_mode_probs(FRAME_CONTEXT *fc, aom_reader *r) { } } } + +#if CONFIG_COMPOUND_SINGLEREF +static void read_inter_singleref_comp_mode_probs(FRAME_CONTEXT *fc, + aom_reader *r) { + int i, j; + if (aom_read(r, GROUP_DIFF_UPDATE_PROB, ACCT_STR)) { + for (j = 0; j < INTER_MODE_CONTEXTS; ++j) { + for (i = 0; i < INTER_SINGLEREF_COMP_MODES - 1; ++i) { + av1_diff_update_prob(r, &fc->inter_singleref_comp_mode_probs[j][i], + ACCT_STR); + } + } + } +} +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER + #if !CONFIG_EC_ADAPT #if !CONFIG_EXT_TX static void read_ext_tx_probs(FRAME_CONTEXT *fc, aom_reader *r) { @@ -962,7 +978,13 @@ static void set_param_topblock(AV1_COMMON *const cm, MACROBLOCKD *const xd, static void set_ref(AV1_COMMON *const cm, MACROBLOCKD *const xd, int idx, int mi_row, int mi_col) { MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + RefBuffer *ref_buffer = + has_second_ref(mbmi) ? &cm->frame_refs[mbmi->ref_frame[idx] - LAST_FRAME] + : &cm->frame_refs[mbmi->ref_frame[0] - LAST_FRAME]; +#else RefBuffer *ref_buffer = &cm->frame_refs[mbmi->ref_frame[idx] - LAST_FRAME]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF xd->block_refs[idx] = ref_buffer; if (!av1_is_valid_scale(&ref_buffer->sf)) aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM, @@ -1000,9 +1022,12 @@ static void dec_predict_b_extend( mbmi = set_offsets_extend(cm, xd, tile, bsize_pred, mi_row_pred, mi_col_pred, mi_row_ori, mi_col_ori); set_ref(cm, xd, 0, mi_row_pred, mi_col_pred); - if (has_second_ref(&xd->mi[0]->mbmi)) + if (has_second_ref(&xd->mi[0]->mbmi) +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + || is_inter_singleref_comp_mode(xd->mi[0]->mbmi.mode) +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + ) set_ref(cm, xd, 1, mi_row_pred, mi_col_pred); - if (!bextend) mbmi->tx_size = max_txsize_lookup[bsize_top]; xd->plane[plane].dst.stride = dst_stride; @@ -2014,8 +2039,14 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi, } else { int ref; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + is_inter_anyref_comp_mode(mbmi->mode); ++ref) { + const MV_REFERENCE_FRAME frame = + has_second_ref(mbmi) ? mbmi->ref_frame[ref] : mbmi->ref_frame[0]; +#else for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { const MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF if (frame < LAST_FRAME) { #if CONFIG_INTRABC assert(is_intrabc_block(mbmi)); @@ -4236,7 +4267,11 @@ static void read_compound_tools(AV1_COMMON *cm, } #endif // CONFIG_INTERINTRA #if CONFIG_WEDGE || CONFIG_COMPOUND_SEGMENT +#if CONFIG_COMPOUND_SINGLEREF + if (!frame_is_intra_only(cm)) { +#else // !CONFIG_COMPOUND_SINGLEREF if (!frame_is_intra_only(cm) && cm->reference_mode != SINGLE_REFERENCE) { +#endif // CONFIG_COMPOUND_SINGLEREF cm->allow_masked_compound = aom_rb_read_bit(rb); } else { cm->allow_masked_compound = 0; @@ -4993,6 +5028,10 @@ static int read_compressed_header(AV1Decoder *pbi, const uint8_t *data, #if CONFIG_EXT_INTER read_inter_compound_mode_probs(fc, &r); +#if CONFIG_COMPOUND_SINGLEREF + read_inter_singleref_comp_mode_probs(fc, &r); +#endif // CONFIG_COMPOUND_SINGLEREF + #if CONFIG_INTERINTRA if (cm->reference_mode != COMPOUND_REFERENCE && cm->allow_interintra_compound) { @@ -5015,7 +5054,11 @@ static int read_compressed_header(AV1Decoder *pbi, const uint8_t *data, } #endif // CONFIG_INTERINTRA #if CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE +#if CONFIG_COMPOUND_SINGLEREF + if (cm->allow_masked_compound) { +#else // !CONFIG_COMPOUND_SINGLEREF if (cm->reference_mode != SINGLE_REFERENCE && cm->allow_masked_compound) { +#endif // CONFIG_COMPOUND_SINGLEREF for (i = 0; i < BLOCK_SIZES; i++) { for (j = 0; j < COMPOUND_TYPES - 1; j++) { av1_diff_update_prob(&r, &fc->compound_type_prob[i][j], ACCT_STR); @@ -5043,6 +5086,11 @@ static int read_compressed_header(AV1Decoder *pbi, const uint8_t *data, setup_compound_reference_mode(cm); read_frame_reference_mode_probs(cm, &r); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (i = 0; i < COMP_INTER_MODE_CONTEXTS; i++) + av1_diff_update_prob(&r, &fc->comp_inter_mode_prob[i], ACCT_STR); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if !CONFIG_EC_ADAPT for (j = 0; j < BLOCK_SIZE_GROUPS; j++) { for (i = 0; i < INTRA_MODES - 1; ++i) @@ -5120,6 +5168,10 @@ static void debug_check_frame_counts(const AV1_COMMON *const cm) { #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION assert(!memcmp(cm->counts.intra_inter, zero_counts.intra_inter, sizeof(cm->counts.intra_inter))); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + assert(!memcmp(cm->counts.comp_inter_mode, zero_counts.comp_inter_mode, + sizeof(cm->counts.comp_inter_mode))); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF assert(!memcmp(cm->counts.comp_inter, zero_counts.comp_inter, sizeof(cm->counts.comp_inter))); assert(!memcmp(cm->counts.single_ref, zero_counts.single_ref, diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c index 657eb6e43..a1700ff48 100644 --- a/av1/decoder/decodemv.c +++ b/av1/decoder/decodemv.c @@ -32,6 +32,9 @@ #include "aom_dsp/aom_dsp_common.h" #define ACCT_STR __func__ + +#define COMPOUND_SINGLEREF_DEBUG 0 + #if CONFIG_EXT_INTRA || CONFIG_FILTER_INTRA || CONFIG_PALETTE static INLINE int read_uniform(aom_reader *r, int n) { const int l = get_unsigned_bits(n); @@ -244,10 +247,15 @@ static void read_drl_idx(const AV1_COMMON *cm, MACROBLOCKD *xd, mbmi->ref_mv_idx = 0; #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV || + mbmi->mode == SR_NEW_NEWMV) { +#else // !CONFIG_COMPOUND_SINGLEREF if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV) { -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER if (mbmi->mode == NEWMV) { -#endif +#endif // CONFIG_EXT_INTER int idx; for (idx = 0; idx < 2; ++idx) { if (xd->ref_mv_count[ref_frame_type] > idx + 1) { @@ -329,6 +337,23 @@ static PREDICTION_MODE read_inter_compound_mode(AV1_COMMON *cm, MACROBLOCKD *xd, assert(is_inter_compound_mode(NEAREST_NEARESTMV + mode)); return NEAREST_NEARESTMV + mode; } + +#if CONFIG_COMPOUND_SINGLEREF +static PREDICTION_MODE read_inter_singleref_comp_mode(AV1_COMMON *cm, + MACROBLOCKD *xd, + aom_reader *r, + int16_t ctx) { + const int mode = + aom_read_tree(r, av1_inter_singleref_comp_mode_tree, + cm->fc->inter_singleref_comp_mode_probs[ctx], ACCT_STR); + FRAME_COUNTS *counts = xd->counts; + + if (counts) ++counts->inter_singleref_comp_mode[ctx][mode]; + + assert(is_inter_singleref_comp_mode(SR_NEAREST_NEARMV + mode)); + return SR_NEAREST_NEARMV + mode; +} +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER static int read_segment_id(aom_reader *r, struct segmentation_probs *segp) { @@ -1654,6 +1679,84 @@ static INLINE int assign_mv(AV1_COMMON *cm, MACROBLOCKD *xd, break; } #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + case SR_NEAREST_NEARMV: { + assert(!is_compound); + mv[0].as_int = nearest_mv[0].as_int; + mv[1].as_int = near_mv[0].as_int; + break; + } + /* + case SR_NEAREST_NEWMV: { + assert(!is_compound); + mv[0].as_int = nearest_mv[0].as_int; + + FRAME_COUNTS *counts = xd->counts; + int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame); + int nmv_ctx = av1_nmv_ctx(xd->ref_mv_count[rf_type], + xd->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx); + nmv_context *const nmvc = &ec_ctx->nmvc[nmv_ctx]; + nmv_context_counts *const mv_counts = + counts ? &counts->mv[nmv_ctx] : NULL; + read_mv(r, &mv[1].as_mv, &ref_mv[0].as_mv, nmvc, mv_counts, allow_hp); + ret = ret && is_mv_valid(&mv[1].as_mv); + break; + }*/ + case SR_NEAR_NEWMV: { + assert(!is_compound); + mv[0].as_int = near_mv[0].as_int; + + FRAME_COUNTS *counts = xd->counts; + int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame); + int nmv_ctx = av1_nmv_ctx(xd->ref_mv_count[rf_type], + xd->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx); + nmv_context *const nmvc = &ec_ctx->nmvc[nmv_ctx]; + nmv_context_counts *const mv_counts = + counts ? &counts->mv[nmv_ctx] : NULL; + read_mv(r, &mv[1].as_mv, &ref_mv[0].as_mv, nmvc, mv_counts, allow_hp); + ret = ret && is_mv_valid(&mv[1].as_mv); + break; + } + case SR_ZERO_NEWMV: { + assert(!is_compound); +#if CONFIG_GLOBAL_MOTION + mv[0].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[0]], + cm->allow_high_precision_mv, bsize, + mi_col, mi_row, block) + .as_int; +#else + mv[0].as_int = 0; +#endif // CONFIG_GLOBAL_MOTION + + FRAME_COUNTS *counts = xd->counts; + int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame); + int nmv_ctx = av1_nmv_ctx(xd->ref_mv_count[rf_type], + xd->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx); + nmv_context *const nmvc = &ec_ctx->nmvc[nmv_ctx]; + nmv_context_counts *const mv_counts = + counts ? &counts->mv[nmv_ctx] : NULL; + read_mv(r, &mv[1].as_mv, &ref_mv[0].as_mv, nmvc, mv_counts, allow_hp); + ret = ret && is_mv_valid(&mv[1].as_mv); + break; + } + case SR_NEW_NEWMV: { + assert(!is_compound); + + FRAME_COUNTS *counts = xd->counts; + for (i = 0; i < 2; ++i) { + int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame); + int nmv_ctx = + av1_nmv_ctx(xd->ref_mv_count[rf_type], xd->ref_mv_stack[rf_type], 0, + mbmi->ref_mv_idx); + nmv_context *const nmvc = &ec_ctx->nmvc[nmv_ctx]; + nmv_context_counts *const mv_counts = + counts ? &counts->mv[nmv_ctx] : NULL; + read_mv(r, &mv[i].as_mv, &ref_mv[0].as_mv, nmvc, mv_counts, allow_hp); + ret = ret && is_mv_valid(&mv[i].as_mv); + } + break; + } +#endif // CONFIG_COMPOUND_SINGLEREF case NEW_NEWMV: { FRAME_COUNTS *counts = xd->counts; assert(is_compound); @@ -1775,6 +1878,22 @@ static int read_is_inter_block(AV1_COMMON *const cm, MACROBLOCKD *const xd, } } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF +static int read_is_inter_singleref_comp_mode(AV1_COMMON *const cm, + MACROBLOCKD *const xd, + int segment_id, aom_reader *r) { + if (segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) return 0; + + const int ctx = av1_get_inter_mode_context(xd); + const int is_singleref_comp_mode = + aom_read(r, cm->fc->comp_inter_mode_prob[ctx], ACCT_STR); + FRAME_COUNTS *counts = xd->counts; + + if (counts) ++counts->comp_inter_mode[ctx][is_singleref_comp_mode]; + return is_singleref_comp_mode; +} +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + static void fpm_sync(void *const data, int mi_row) { AV1Decoder *const pbi = (AV1Decoder *)data; av1_frameworker_wait(pbi->frame_worker_owner, pbi->common.prev_frame, @@ -1799,6 +1918,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, int_mv nearestmv[2], nearmv[2]; int_mv ref_mvs[MODE_CTX_REF_FRAMES][MAX_MV_REF_CANDIDATES]; int ref, is_compound; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int is_singleref_comp_mode = 0; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF int16_t inter_mode_ctx[MODE_CTX_REF_FRAMES]; #if CONFIG_EXT_INTER int16_t compound_inter_mode_ctx[MODE_CTX_REF_FRAMES]; @@ -1825,6 +1947,12 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame); is_compound = has_second_ref(mbmi); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!is_compound) + is_singleref_comp_mode = + read_is_inter_singleref_comp_mode(cm, xd, mbmi->segment_id, r); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + is_compound; ++ref) { MV_REFERENCE_FRAME frame = mbmi->ref_frame[ref]; @@ -1876,7 +2004,11 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, } #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (is_compound || is_singleref_comp_mode) +#else // !CONFIG_COMPOUND_SINGLEREF if (is_compound) +#endif // CONFIG_COMPOUND_SINGLEREF mode_ctx = compound_inter_mode_ctx[mbmi->ref_frame[0]]; else #endif // CONFIG_EXT_INTER @@ -1896,15 +2028,22 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, #if CONFIG_EXT_INTER if (is_compound) mbmi->mode = read_inter_compound_mode(cm, xd, r, mode_ctx); +#if CONFIG_COMPOUND_SINGLEREF + else if (is_singleref_comp_mode) + mbmi->mode = read_inter_singleref_comp_mode(cm, xd, r, mode_ctx); +#endif // CONFIG_COMPOUND_SINGLEREF else #endif // CONFIG_EXT_INTER mbmi->mode = read_inter_mode(ec_ctx, xd, r, mode_ctx); #if CONFIG_EXT_INTER if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV || +#if CONFIG_COMPOUND_SINGLEREF + mbmi->mode == SR_NEW_NEWMV || +#endif // CONFIG_COMPOUND_SINGLEREF have_nearmv_in_inter_mode(mbmi->mode)) -#else +#else // !CONFIG_EXT_INTER if (mbmi->mode == NEARMV || mbmi->mode == NEWMV) -#endif +#endif // CONFIG_EXT_INTER read_drl_idx(cm, xd, mbmi, r); } } @@ -1928,9 +2067,14 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, } #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if ((is_compound || is_singleref_comp_mode) && + (bsize >= BLOCK_8X8 || unify_bsize) && mbmi->mode != ZERO_ZEROMV) { +#else // !CONFIG_COMPOUND_SINGLEREF if (is_compound && (bsize >= BLOCK_8X8 || unify_bsize) && mbmi->mode != ZERO_ZEROMV) { -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER if (is_compound && (bsize >= BLOCK_8X8 || unify_bsize) && mbmi->mode != NEWMV && mbmi->mode != ZEROMV) { #endif // CONFIG_EXT_INTER @@ -1949,7 +2093,12 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, lower_mv_precision(&nearestmv[0].as_mv, allow_hp); lower_mv_precision(&nearestmv[1].as_mv, allow_hp); #if CONFIG_EXT_INTER - } else if (mbmi->mode == NEAREST_NEWMV) { + } else if (mbmi->mode == NEAREST_NEWMV +#if CONFIG_COMPOUND_SINGLEREF + || mbmi->mode == SR_NEAREST_NEARMV +// || mbmi->mode == SR_NEAREST_NEWMV +#endif // CONFIG_COMPOUND_SINGLEREF + ) { nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv; lower_mv_precision(&nearestmv[0].as_mv, allow_hp); } else if (mbmi->mode == NEW_NEARESTMV) { @@ -1962,17 +2111,30 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, #if CONFIG_EXT_INTER if (xd->ref_mv_count[ref_frame_type] > 1) { int ref_mv_idx = 1 + mbmi->ref_mv_idx; - if (compound_ref0_mode(mbmi->mode) == NEARMV) { - nearmv[0] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; - lower_mv_precision(&nearmv[0].as_mv, allow_hp); - } +#if CONFIG_COMPOUND_SINGLEREF + if (is_compound) { +#endif // CONFIG_COMPOUND_SINGLEREF + if (compound_ref0_mode(mbmi->mode) == NEARMV) { + nearmv[0] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + lower_mv_precision(&nearmv[0].as_mv, allow_hp); + } - if (compound_ref1_mode(mbmi->mode) == NEARMV) { - nearmv[1] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv; - lower_mv_precision(&nearmv[1].as_mv, allow_hp); + if (compound_ref1_mode(mbmi->mode) == NEARMV) { + nearmv[1] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv; + lower_mv_precision(&nearmv[1].as_mv, allow_hp); + } +#if CONFIG_COMPOUND_SINGLEREF + } else { + assert(is_singleref_comp_mode); + if (compound_ref0_mode(mbmi->mode) == NEARMV || + compound_ref1_mode(mbmi->mode) == NEARMV) { + nearmv[0] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + lower_mv_precision(&nearmv[0].as_mv, allow_hp); + } } +#endif // CONFIG_COMPOUND_SINGLEREF } -#else +#else // !CONFIG_EXT_INTER if (xd->ref_mv_count[ref_frame_type] > 1) { int ref_mv_idx = 1 + mbmi->ref_mv_idx; nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv; @@ -2112,6 +2274,26 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, } nearestmv[1] = ref_mv[1]; } +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_singleref_comp_mode) { + int ref_mv_idx = mbmi->ref_mv_idx; + // Special case: SR_NEAR_NEWMV use 1 + mbmi->ref_mv_idx (like NEARMV) + // instead of mbmi->ref_mv_idx (like NEWMV) + if (mbmi->mode == SR_NEAR_NEWMV) ref_mv_idx = 1 + mbmi->ref_mv_idx; + + if (compound_ref0_mode(mbmi->mode) == NEWMV || + compound_ref1_mode(mbmi->mode) == NEWMV) { + uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); + if (xd->ref_mv_count[ref_frame_type] > 1) { + ref_mv[0] = xd->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + clamp_mv_ref(&ref_mv[0].as_mv, xd->n8_w << MI_SIZE_LOG2, + xd->n8_h << MI_SIZE_LOG2, xd); + } + // TODO(zoeliu): To further investigate why this would not cause a + // mismatch for the mode of SR_NEAREST_NEWMV. + nearestmv[0] = ref_mv[0]; + } +#endif // CONFIG_COMPOUND_SINGLEREF } else { #endif // CONFIG_EXT_INTER if (mbmi->mode == NEWMV) { @@ -2199,6 +2381,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, if (mbmi->ref_frame[1] != INTRA_FRAME) #endif // CONFIG_EXT_INTER mbmi->motion_mode = read_motion_mode(cm, xd, mi, r); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (is_singleref_comp_mode) assert(mbmi->motion_mode == SIMPLE_TRANSLATION); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #if CONFIG_WARPED_MOTION if (mbmi->motion_mode == WARPED_CAUSAL) { mbmi->wm_params[0].wmtype = DEFAULT_WMTYPE; @@ -2216,8 +2401,14 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, #if CONFIG_EXT_INTER mbmi->interinter_compound_type = COMPOUND_AVERAGE; - if (cm->reference_mode != SINGLE_REFERENCE && + if ( +#if CONFIG_COMPOUND_SINGLEREF + (is_inter_compound_mode(mbmi->mode) || + is_inter_singleref_comp_mode(mbmi->mode)) +#else // !CONFIG_COMPOUND_SINGLEREF + cm->reference_mode != SINGLE_REFERENCE && is_inter_compound_mode(mbmi->mode) +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION && mbmi->motion_mode == SIMPLE_TRANSLATION #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION @@ -2253,6 +2444,39 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi, #if CONFIG_DUAL_FILTER || CONFIG_WARPED_MOTION || CONFIG_GLOBAL_MOTION read_mb_interp_filter(cm, xd, mbmi, r); #endif // CONFIG_DUAL_FILTER || CONFIG_WARPED_MOTION + +#if CONFIG_EXT_INTER +#if COMPOUND_SINGLEREF_DEBUG +// NOTE(zoeliu): For debug +#define FRAME_TO_CHECK 1 + if (cm->current_video_frame == FRAME_TO_CHECK && + ((cm->reference_mode != SINGLE_REFERENCE && cm->show_frame == 0) || + cm->show_frame == 1)) { + const PREDICTION_MODE mode = mbmi->mode; + + int_mv mv[2]; +#if CONFIG_COMPOUND_SINGLEREF + int is_comp_pred = + has_second_ref(mbmi) || is_inter_singleref_comp_mode(mbmi->mode); +#else + int is_comp_pred = has_second_ref(mbmi); +#endif // CONFIG_COMPOUND_SINGLEREF + + mv[0].as_int = mbmi->mv[0].as_int; + mv[1].as_int = is_comp_pred ? mbmi->mv[1].as_int : 0; + + printf( + "=== DECODER ===: " + "Frame=%d, (mi_row,mi_col)=(%d,%d), mode=%d, bsize=%d, " + "show_frame=%d, mv[0]=(%d,%d), mv[1]=(%d,%d), ref[0]=%d, ref[1]=%d, " + "motion_mode=%d\n", + cm->current_video_frame, mi_row, mi_col, mode, bsize, cm->show_frame, + mv[0].as_mv.row, mv[0].as_mv.col, mv[1].as_mv.row, mv[1].as_mv.col, + mbmi->ref_frame[0], mbmi->ref_frame[1], mbmi->motion_mode); + } +#endif // COMPOUND_SINGLEREF_DEBUG +#undef COMPOUND_SINGLEREF_DEBUG +#endif // CONFIG_EXT_INTER } static void read_inter_frame_mode_info(AV1Decoder *const pbi, diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index fb8ab949c..a9277fa34 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c @@ -61,6 +61,8 @@ #include "av1/encoder/pvq_encoder.h" #endif +#define COMPOUND_SINGLEREF_DEBUG 0 + static struct av1_token intra_mode_encodings[INTRA_MODES]; static struct av1_token switchable_interp_encodings[SWITCHABLE_FILTERS]; static struct av1_token partition_encodings[PARTITION_TYPES]; @@ -70,6 +72,10 @@ static const struct av1_token { 2, 2 }, { 12, 4 }, { 52, 6 }, { 53, 6 }, { 54, 6 }, { 55, 6 }, { 0, 1 }, { 7, 3 } }; +#if CONFIG_COMPOUND_SINGLEREF +static struct av1_token + inter_singleref_comp_mode_encodings[INTER_SINGLEREF_COMP_MODES]; +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER #if CONFIG_PALETTE static struct av1_token palette_size_encodings[PALETTE_SIZES]; @@ -161,6 +167,10 @@ void av1_encode_token_init(void) { #if CONFIG_INTERINTRA av1_tokens_from_tree(interintra_mode_encodings, av1_interintra_mode_tree); #endif // CONFIG_INTERINTRA +#if CONFIG_COMPOUND_SINGLEREF + av1_tokens_from_tree(inter_singleref_comp_mode_encodings, + av1_inter_singleref_comp_mode_tree); +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE av1_tokens_from_tree(compound_type_encodings, av1_compound_type_tree); #endif // CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE @@ -259,10 +269,15 @@ static void write_drl_idx(const AV1_COMMON *cm, const MB_MODE_INFO *mbmi, assert(mbmi->ref_mv_idx < 3); #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV || + mbmi->mode == SR_NEW_NEWMV) { +#else // !CONFIG_COMPOUND_SINGLEREF if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV) { -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER if (mbmi->mode == NEWMV) { -#endif +#endif // CONFIG_EXT_INTER int idx; for (idx = 0; idx < 2; ++idx) { if (mbmi_ext->ref_mv_count[ref_frame_type] > idx + 1) { @@ -305,6 +320,20 @@ static void write_inter_compound_mode(AV1_COMMON *cm, aom_writer *w, av1_write_token(w, av1_inter_compound_mode_tree, inter_compound_probs, &inter_compound_mode_encodings[INTER_COMPOUND_OFFSET(mode)]); } + +#if CONFIG_COMPOUND_SINGLEREF +static void write_inter_singleref_comp_mode(AV1_COMMON *cm, aom_writer *w, + PREDICTION_MODE mode, + const int16_t mode_ctx) { + assert(is_inter_singleref_comp_mode(mode)); + const aom_prob *const inter_singleref_comp_probs = + cm->fc->inter_singleref_comp_mode_probs[mode_ctx]; + + av1_write_token( + w, av1_inter_singleref_comp_mode_tree, inter_singleref_comp_probs, + &inter_singleref_comp_mode_encodings[INTER_SINGLEREF_COMP_OFFSET(mode)]); +} +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER static void encode_unsigned_max(struct aom_write_bit_buffer *wb, int data, @@ -490,6 +519,34 @@ static void update_inter_compound_mode_probs(AV1_COMMON *cm, int probwt, } } } + +#if CONFIG_COMPOUND_SINGLEREF +static void update_inter_singleref_comp_mode_probs(AV1_COMMON *cm, int probwt, + aom_writer *w) { + const int savings_thresh = av1_cost_one(GROUP_DIFF_UPDATE_PROB) - + av1_cost_zero(GROUP_DIFF_UPDATE_PROB); + int i; + int savings = 0; + int do_update = 0; + for (i = 0; i < INTER_MODE_CONTEXTS; ++i) { + savings += + prob_diff_update_savings(av1_inter_singleref_comp_mode_tree, + cm->fc->inter_singleref_comp_mode_probs[i], + cm->counts.inter_singleref_comp_mode[i], + INTER_SINGLEREF_COMP_MODES, probwt); + } + do_update = savings > savings_thresh; + aom_write(w, do_update, GROUP_DIFF_UPDATE_PROB); + if (do_update) { + for (i = 0; i < INTER_MODE_CONTEXTS; ++i) { + prob_diff_update(av1_inter_singleref_comp_mode_tree, + cm->fc->inter_singleref_comp_mode_probs[i], + cm->counts.inter_singleref_comp_mode[i], + INTER_SINGLEREF_COMP_MODES, probwt, w); + } + } +} +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER static int write_skip(const AV1_COMMON *cm, const MACROBLOCKD *xd, @@ -1891,8 +1948,21 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, int16_t mode_ctx; write_ref_frames(cm, xd, w); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) { + // NOTE: Handle single ref comp mode + if (!is_compound) + aom_write(w, is_inter_singleref_comp_mode(mode), + av1_get_inter_mode_prob(cm, xd)); + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (is_compound || is_inter_singleref_comp_mode(mode)) +#else // !CONFIG_COMPOUND_SINGLEREF if (is_compound) +#endif // CONFIG_COMPOUND_SINGLEREF mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]; else #endif // CONFIG_EXT_INTER @@ -1905,16 +1975,23 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, #if CONFIG_EXT_INTER if (is_inter_compound_mode(mode)) write_inter_compound_mode(cm, w, mode, mode_ctx); +#if CONFIG_COMPOUND_SINGLEREF + else if (is_inter_singleref_comp_mode(mode)) + write_inter_singleref_comp_mode(cm, w, mode, mode_ctx); +#endif // CONFIG_COMPOUND_SINGLEREF else if (is_inter_singleref_mode(mode)) #endif // CONFIG_EXT_INTER write_inter_mode(w, mode, ec_ctx, mode_ctx); #if CONFIG_EXT_INTER if (mode == NEWMV || mode == NEW_NEWMV || +#if CONFIG_COMPOUND_SINGLEREF + mbmi->mode == SR_NEW_NEWMV || +#endif // CONFIG_COMPOUND_SINGLEREF have_nearmv_in_inter_mode(mode)) -#else +#else // !CONFIG_EXT_INTER if (mode == NEARMV || mode == NEWMV) -#endif +#endif // CONFIG_EXT_INTER write_drl_idx(cm, mbmi, mbmi_ext, w); else assert(mbmi->ref_mv_idx == 0); @@ -1926,6 +2003,10 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, #endif // !CONFIG_DUAL_FILTER && !CONFIG_WARPED_MOTION if (bsize < BLOCK_8X8 && !unify_bsize) { +#if CONFIG_COMPOUND_SINGLEREF + /// NOTE: Single ref comp mode does not support sub8x8. + assert(is_compound || !is_inter_singleref_comp_mode(mbmi->mode)); +#endif // CONFIG_COMPOUND_SINGLEREF const int num_4x4_w = num_4x4_blocks_wide_lookup[bsize]; const int num_4x4_h = num_4x4_blocks_high_lookup[bsize]; int idx, idy; @@ -2022,6 +2103,22 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, av1_encode_mv(cpi, w, &mbmi->mv[0].as_mv, &mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0].as_mv, nmvc, allow_hp); +#if CONFIG_COMPOUND_SINGLEREF + } else if ( // mode == SR_NEAREST_NEWMV || + mode == SR_NEAR_NEWMV || mode == SR_ZERO_NEWMV || + mode == SR_NEW_NEWMV) { + int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame); + int nmv_ctx = + av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type], + mbmi_ext->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx); + nmv_context *nmvc = &ec_ctx->nmvc[nmv_ctx]; + int_mv ref_mv = mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0]; + if (mode == SR_NEW_NEWMV) + av1_encode_mv(cpi, w, &mbmi->mv[0].as_mv, &ref_mv.as_mv, nmvc, + allow_hp); + av1_encode_mv(cpi, w, &mbmi->mv[1].as_mv, &ref_mv.as_mv, nmvc, + allow_hp); +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER } } @@ -2062,12 +2159,18 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row, #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION #if CONFIG_EXT_INTER - if (cpi->common.reference_mode != SINGLE_REFERENCE && - is_inter_compound_mode(mbmi->mode) + if ( +#if CONFIG_COMPOUND_SINGLEREF + (is_inter_compound_mode(mbmi->mode) || + is_inter_singleref_comp_mode(mbmi->mode)) && +#else // !CONFIG_COMPOUND_SINGLEREF + cpi->common.reference_mode != SINGLE_REFERENCE && + is_inter_compound_mode(mbmi->mode) && +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_MOTION_VAR - && mbmi->motion_mode == SIMPLE_TRANSLATION + mbmi->motion_mode == SIMPLE_TRANSLATION && #endif // CONFIG_MOTION_VAR - && is_any_masked_compound_used(bsize)) { + is_any_masked_compound_used(bsize)) { #if CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE if (cm->allow_masked_compound) { av1_write_token( @@ -2350,31 +2453,53 @@ static void write_mbmi_b(AV1_COMP *cpi, const TileInfo *const tile, // up if they are scaled. has_subpel_mv_component is in turn needed by // write_switchable_interp_filter, which is called by pack_inter_mode_mvs. set_ref_ptrs(cm, xd, m->mbmi.ref_frame[0], m->mbmi.ref_frame[1]); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(&m->mbmi) && is_inter_singleref_comp_mode(m->mbmi.mode)) + xd->block_refs[1] = xd->block_refs[0]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_DUAL_FILTER -#if 0 + +#if CONFIG_EXT_INTER +#if COMPOUND_SINGLEREF_DEBUG // NOTE(zoeliu): For debug - if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) { - const PREDICTION_MODE mode = m->mbmi.mode; - const int segment_id = m->mbmi.segment_id; - const BLOCK_SIZE bsize = m->mbmi.sb_type; - - // For sub8x8, simply dump out the first sub8x8 block info - const PREDICTION_MODE b_mode = - (bsize < BLOCK_8X8) ? m->bmi[0].as_mode : -1; - const int mv_x = (bsize < BLOCK_8X8) ? - m->bmi[0].as_mv[0].as_mv.row : m->mbmi.mv[0].as_mv.row; - const int mv_y = (bsize < BLOCK_8X8) ? - m->bmi[0].as_mv[0].as_mv.col : m->mbmi.mv[0].as_mv.col; - - printf("Before pack_inter_mode_mvs(): " - "Frame=%d, (mi_row,mi_col)=(%d,%d), " - "mode=%d, segment_id=%d, bsize=%d, b_mode=%d, " - "mv[0]=(%d, %d), ref[0]=%d, ref[1]=%d\n", - cm->current_video_frame, mi_row, mi_col, - mode, segment_id, bsize, b_mode, mv_x, mv_y, - m->mbmi.ref_frame[0], m->mbmi.ref_frame[1]); + if (is_inter_block(&m->mbmi)) { +#define FRAME_TO_CHECK 1 + if (cm->current_video_frame == FRAME_TO_CHECK && + ((cm->reference_mode != SINGLE_REFERENCE && cm->show_frame == 0) || + cm->show_frame == 1)) { + const MB_MODE_INFO *const mbmi = &m->mbmi; + const BLOCK_SIZE bsize = mbmi->sb_type; + + int_mv mv[2]; + int is_comp_ref = has_second_ref(&m->mbmi); + int ref; + + for (ref = 0; ref < 1 + is_comp_ref; ++ref) + mv[ref].as_mv = m->mbmi.mv[ref].as_mv; + + if (!is_comp_ref) { +#if CONFIG_COMPOUND_SINGLEREF + if (is_inter_singleref_comp_mode(m->mbmi.mode)) + mv[1].as_mv = m->mbmi.mv[1].as_mv; + else +#endif // CONFIG_COMPOUND_SINGLEREF + mv[1].as_int = 0; + } + + printf( + "=== ENCODER ===: " + "Frame=%d, (mi_row,mi_col)=(%d,%d), mode=%d, bsize=%d, " + "show_frame=%d, mv[0]=(%d,%d), mv[1]=(%d,%d), ref[0]=%d, " + "ref[1]=%d, motion_mode=%d\n", + cm->current_video_frame, mi_row, mi_col, mbmi->mode, bsize, + cm->show_frame, mv[0].as_mv.row, mv[0].as_mv.col, mv[1].as_mv.row, + mv[1].as_mv.col, mbmi->ref_frame[0], mbmi->ref_frame[1], + mbmi->motion_mode); + } } -#endif // 0 +#endif // COMPOUND_SINGLEREF_DEBUG +#undef COMPOUND_SINGLEREF_DEBUG +#endif // CONFIG_EXT_INTER pack_inter_mode_mvs(cpi, mi_row, mi_col, #if CONFIG_SUPERTX supertx_enabled, @@ -3988,7 +4113,7 @@ static uint32_t write_tiles(AV1_COMP *const cpi, uint8_t *const dst, *max_tile_col_size = AOMMAX(*max_tile_col_size, col_size); } } -#else +#else // !CONFIG_EXT_TILE #if CONFIG_TILE_GROUPS write_uncompressed_header(cpi, wb); @@ -4303,7 +4428,11 @@ static void write_compound_tools(const AV1_COMMON *cm, } #endif // CONFIG_INTERINTRA #if CONFIG_WEDGE || CONFIG_COMPOUND_SEGMENT +#if CONFIG_COMPOUND_SINGLEREF + if (!frame_is_intra_only(cm)) { +#else // !CONFIG_COMPOUND_SINGLEREF if (!frame_is_intra_only(cm) && cm->reference_mode != SINGLE_REFERENCE) { +#endif // CONFIG_COMPOUND_SINGLEREF aom_wb_write_bit(wb, cm->allow_masked_compound); } else { assert(cm->allow_masked_compound == 0); @@ -4790,6 +4919,10 @@ static uint32_t write_compressed_header(AV1_COMP *cpi, uint8_t *data) { update_inter_mode_probs(cm, header_bc, counts); #if CONFIG_EXT_INTER update_inter_compound_mode_probs(cm, probwt, header_bc); +#if CONFIG_COMPOUND_SINGLEREF + update_inter_singleref_comp_mode_probs(cm, probwt, header_bc); +#endif // CONFIG_COMPOUND_SINGLEREF + #if CONFIG_INTERINTRA if (cm->reference_mode != COMPOUND_REFERENCE && cm->allow_interintra_compound) { @@ -4814,7 +4947,11 @@ static uint32_t write_compressed_header(AV1_COMP *cpi, uint8_t *data) { } #endif // CONFIG_INTERINTRA #if CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE +#if CONFIG_COMPOUND_SINGLEREF + if (cm->allow_masked_compound) { +#else // !CONFIG_COMPOUND_SINGLEREF if (cm->reference_mode != SINGLE_REFERENCE && cm->allow_masked_compound) { +#endif // CONFIG_COMPOUND_SINGLEREF for (i = 0; i < BLOCK_SIZES; i++) prob_diff_update(av1_compound_type_tree, fc->compound_type_prob[i], cm->counts.compound_interinter[i], COMPOUND_TYPES, @@ -4873,6 +5010,12 @@ static uint32_t write_compressed_header(AV1_COMP *cpi, uint8_t *data) { } } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (i = 0; i < COMP_INTER_MODE_CONTEXTS; i++) + av1_cond_prob_diff_update(header_bc, &fc->comp_inter_mode_prob[i], + counts->comp_inter_mode[i], probwt); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if !CONFIG_EC_ADAPT for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) { prob_diff_update(av1_intra_mode_tree, cm->fc->y_mode_prob[i], diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index cf98b35e1..5c8744ee1 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c @@ -539,6 +539,21 @@ static void set_ref_and_pred_mvs(MACROBLOCK *const x, int_mv *const mi_pred_mv, mbmi->pred_mv[1] = this_mv; mi_pred_mv[1] = this_mv; } +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(mbmi->mode)) { + // Special case: SR_NEAR_NEWMV uses 1 + mbmi->ref_mv_idx + // (like NEARMV) instead + if (mbmi->mode == SR_NEAR_NEWMV) ref_mv_idx += 1; + + if (compound_ref0_mode(mbmi->mode) == NEWMV || + compound_ref1_mode(mbmi->mode) == NEWMV) { + int_mv this_mv = curr_ref_mv_stack[ref_mv_idx].this_mv; + clamp_mv_ref(&this_mv.as_mv, bw, bh, xd); + mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0] = this_mv; + mbmi->pred_mv[0] = this_mv; + mi_pred_mv[0] = this_mv; + } +#endif // CONFIG_COMPOUND_SINGLEREF } else { #endif // CONFIG_EXT_INTER if (mbmi->mode == NEWMV) { @@ -1619,7 +1634,14 @@ static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, #endif // CONFIG_EXT_REFS } -#if CONFIG_EXT_INTER && CONFIG_INTERINTRA +#if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + counts->comp_inter_mode[av1_get_inter_mode_context(xd)] + [is_inter_singleref_comp_mode(mbmi->mode)]++; +#endif // CONFIG_COMPOUND_SINGLEREF + +#if CONFIG_INTERINTRA if (cm->reference_mode != COMPOUND_REFERENCE && #if CONFIG_SUPERTX !supertx_enabled && @@ -1635,7 +1657,8 @@ static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, counts->interintra[bsize_group][0]++; } } -#endif // CONFIG_EXT_INTER && CONFIG_INTERINTRA +#endif // CONFIG_INTERINTRA +#endif // CONFIG_EXT_INTER #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION const MOTION_MODE motion_allowed = motion_mode_allowed( @@ -1663,8 +1686,13 @@ static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION #if CONFIG_EXT_INTER - if (cm->reference_mode != SINGLE_REFERENCE && + if ( +#if CONFIG_COMPOUND_SINGLEREF + is_inter_anyref_comp_mode(mbmi->mode) +#else // !CONFIG_COMPOUND_SINGLEREF + cm->reference_mode != SINGLE_REFERENCE && is_inter_compound_mode(mbmi->mode) +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION && mbmi->motion_mode == SIMPLE_TRANSLATION #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION @@ -1683,6 +1711,12 @@ static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, if (has_second_ref(mbmi)) { mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]; ++counts->inter_compound_mode[mode_ctx][INTER_COMPOUND_OFFSET(mode)]; +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(mode)) { + mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]; + ++counts->inter_singleref_comp_mode[mode_ctx] + [INTER_SINGLEREF_COMP_OFFSET(mode)]; +#endif // CONFIG_COMPOUND_SINGLEREF } else { #endif // CONFIG_EXT_INTER mode_ctx = av1_mode_context_analyzer(mbmi_ext->mode_context, @@ -1693,10 +1727,15 @@ static void update_stats(const AV1_COMMON *const cm, ThreadData *td, int mi_row, #endif // CONFIG_EXT_INTER #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV || + mbmi->mode == SR_NEW_NEWMV) { +#else // !CONFIG_COMPOUND_SINGLEREF if (mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV) { -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER if (mbmi->mode == NEWMV) { -#endif +#endif // CONFIG_EXT_INTER uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); int idx; @@ -4950,7 +4989,11 @@ static void make_consistent_compound_tools(AV1_COMMON *cm) { cm->allow_interintra_compound = 0; #endif // CONFIG_INTERINTRA #if CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE +#if CONFIG_COMPOUND_SINGLEREF + if (frame_is_intra_only(cm)) +#else // !CONFIG_COMPOUND_SINGLEREF if (frame_is_intra_only(cm) || cm->reference_mode == SINGLE_REFERENCE) +#endif // CONFIG_COMPOUND_SINGLEREF cm->allow_masked_compound = 0; #endif // CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE } @@ -5588,8 +5631,21 @@ static void encode_superblock(const AV1_COMP *const cpi, ThreadData *td, av1_setup_pre_planes(xd, ref, cfg, mi_row, mi_col, &xd->block_refs[ref]->sf); } - av1_build_inter_predictors_sby(cm, xd, mi_row, mi_col, NULL, block_size); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // Single ref compound mode + if (!is_compound && is_inter_singleref_comp_mode(mbmi->mode)) { + xd->block_refs[1] = xd->block_refs[0]; + YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, mbmi->ref_frame[0]); +#if CONFIG_INTRABC + assert(IMPLIES(!is_intrabc_block(mbmi), cfg)); +#else + assert(cfg != NULL); +#endif // !CONFIG_INTRABC + av1_setup_pre_planes(xd, 1, cfg, mi_row, mi_col, &xd->block_refs[1]->sf); + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + av1_build_inter_predictors_sby(cm, xd, mi_row, mi_col, NULL, block_size); av1_build_inter_predictors_sbuv(cm, xd, mi_row, mi_col, NULL, block_size); #if CONFIG_MOTION_VAR if (mbmi->motion_mode == OBMC_CAUSAL) { @@ -5888,6 +5944,16 @@ static void predict_superblock(const AV1_COMP *const cpi, ThreadData *td, &xd->block_refs[ref]->sf); } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // Single ref compound mode + if (!is_compound && is_inter_singleref_comp_mode(mbmi->mode)) { + xd->block_refs[1] = xd->block_refs[0]; + YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, mbmi->ref_frame[0]); + av1_setup_pre_planes(xd, 1, cfg, mi_row_pred, mi_col_pred, + &xd->block_refs[1]->sf); + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!b_sub8x8) av1_build_inter_predictor_sb_extend(cm, xd, #if CONFIG_EXT_INTER diff --git a/av1/encoder/encodemv.c b/av1/encoder/encodemv.c index e1b515b60..8aed52112 100644 --- a/av1/encoder/encodemv.c +++ b/av1/encoder/encodemv.c @@ -295,6 +295,27 @@ static void inc_mvs(const MB_MODE_INFO *mbmi, const MB_MODE_INFO_EXT *mbmi_ext, mbmi_ext->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx); nmv_context_counts *counts = &nmv_counts[nmv_ctx]; av1_inc_mv(&diff, counts, 1); +#if CONFIG_COMPOUND_SINGLEREF + } else { + assert( // mode == SR_NEAREST_NEWMV || + mode == SR_NEAR_NEWMV || mode == SR_ZERO_NEWMV || mode == SR_NEW_NEWMV); + const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0].as_mv; + int8_t rf_type = av1_ref_frame_type(mbmi->ref_frame); + int nmv_ctx = + av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type], + mbmi_ext->ref_mv_stack[rf_type], 0, mbmi->ref_mv_idx); + nmv_context_counts *counts = &nmv_counts[nmv_ctx]; + (void)pred_mvs; + MV diff; + if (mode == SR_NEW_NEWMV) { + diff.row = mvs[0].as_mv.row - ref->row; + diff.col = mvs[0].as_mv.col - ref->col; + av1_inc_mv(&diff, counts, 1); + } + diff.row = mvs[1].as_mv.row - ref->row; + diff.col = mvs[1].as_mv.col - ref->col; + av1_inc_mv(&diff, counts, 1); +#endif // CONFIG_COMPOUND_SINGLEREF } } @@ -339,7 +360,7 @@ static void inc_mvs_sub8x8(const MODE_INFO *mi, int block, const int_mv mvs[2], av1_inc_mv(&diff, counts, 1); } } -#else +#else // !CONFIG_EXT_INTER static void inc_mvs(const MB_MODE_INFO *mbmi, const MB_MODE_INFO_EXT *mbmi_ext, const int_mv mvs[2], const int_mv pred_mvs[2], nmv_context_counts *nmv_counts) { diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index 70de507a9..82c47b8e0 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h @@ -539,6 +539,10 @@ typedef struct AV1_COMP { #if CONFIG_EXT_INTER unsigned int inter_compound_mode_cost[INTER_MODE_CONTEXTS] [INTER_COMPOUND_MODES]; +#if CONFIG_COMPOUND_SINGLEREF + unsigned int inter_singleref_comp_mode_cost[INTER_MODE_CONTEXTS] + [INTER_SINGLEREF_COMP_MODES]; +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_INTERINTRA unsigned int interintra_mode_cost[BLOCK_SIZE_GROUPS][INTERINTRA_MODES]; #endif // CONFIG_INTERINTRA diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c index 52080ca0d..79543c4ab 100644 --- a/av1/encoder/mcomp.c +++ b/av1/encoder/mcomp.c @@ -2763,7 +2763,13 @@ int av1_find_best_obmc_sub_pixel_tree_up( ref_mv); if (use_upsampled_ref) { +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int ref = has_second_ref(&xd->mi[0]->mbmi) + ? xd->mi[0]->mbmi.ref_frame[is_second] + : xd->mi[0]->mbmi.ref_frame[0]; +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) int ref = xd->mi[0]->mbmi.ref_frame[is_second]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF const YV12_BUFFER_CONFIG *upsampled_ref = get_upsampled_ref(cpi, ref); setup_pred_plane(&pd->pre[is_second], mbmi->sb_type, upsampled_ref->y_buffer, upsampled_ref->y_crop_width, diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c index d9a13336a..ae4981236 100644 --- a/av1/encoder/rd.c +++ b/av1/encoder/rd.c @@ -444,6 +444,12 @@ void av1_initialize_rd_consts(AV1_COMP *cpi) { av1_cost_tokens((int *)cpi->inter_compound_mode_cost[i], cm->fc->inter_compound_mode_probs[i], av1_inter_compound_mode_tree); +#if CONFIG_COMPOUND_SINGLEREF + for (i = 0; i < INTER_MODE_CONTEXTS; ++i) + av1_cost_tokens((int *)cpi->inter_singleref_comp_mode_cost[i], + cm->fc->inter_singleref_comp_mode_probs[i], + av1_inter_singleref_comp_mode_tree); +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_INTERINTRA for (i = 0; i < BLOCK_SIZE_GROUPS; ++i) av1_cost_tokens((int *)cpi->interintra_mode_cost[i], @@ -993,6 +999,54 @@ void av1_set_rd_speed_thresholds(AV1_COMP *cpi) { #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + rd->thresh_mult[THR_SR_NEAREST_NEARMV] += 1200; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEAREST_NEARL2] += 1200; + rd->thresh_mult[THR_SR_NEAREST_NEARL3] += 1200; + rd->thresh_mult[THR_SR_NEAREST_NEARB] += 1200; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEAREST_NEARA] += 1200; + rd->thresh_mult[THR_SR_NEAREST_NEARG] += 1200; + + /* + rd->thresh_mult[THR_SR_NEAREST_NEWMV] += 1200; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEAREST_NEWL2] += 1200; + rd->thresh_mult[THR_SR_NEAREST_NEWL3] += 1200; + rd->thresh_mult[THR_SR_NEAREST_NEWB] += 1200; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEAREST_NEWA] += 1200; + rd->thresh_mult[THR_SR_NEAREST_NEWG] += 1200;*/ + + rd->thresh_mult[THR_SR_NEAR_NEWMV] += 1500; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEAR_NEWL2] += 1500; + rd->thresh_mult[THR_SR_NEAR_NEWL3] += 1500; + rd->thresh_mult[THR_SR_NEAR_NEWB] += 1500; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEAR_NEWA] += 1500; + rd->thresh_mult[THR_SR_NEAR_NEWG] += 1500; + + rd->thresh_mult[THR_SR_ZERO_NEWMV] += 2000; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_ZERO_NEWL2] += 2000; + rd->thresh_mult[THR_SR_ZERO_NEWL3] += 2000; + rd->thresh_mult[THR_SR_ZERO_NEWB] += 2000; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_ZERO_NEWA] += 2000; + rd->thresh_mult[THR_SR_ZERO_NEWG] += 2000; + + rd->thresh_mult[THR_SR_NEW_NEWMV] += 1700; +#if CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEW_NEWL2] += 1700; + rd->thresh_mult[THR_SR_NEW_NEWL3] += 1700; + rd->thresh_mult[THR_SR_NEW_NEWB] += 1700; +#endif // CONFIG_EXT_REFS + rd->thresh_mult[THR_SR_NEW_NEWA] += 1700; + rd->thresh_mult[THR_SR_NEW_NEWG] += 1700; +#endif // CONFIG_COMPOUND_SINGLEREF + rd->thresh_mult[THR_COMP_NEAREST_NEARESTLA] += 1000; #if CONFIG_EXT_REFS rd->thresh_mult[THR_COMP_NEAREST_NEARESTL2A] += 1000; diff --git a/av1/encoder/rd.h b/av1/encoder/rd.h index dfd4fcc49..2e35cffb5 100644 --- a/av1/encoder/rd.h +++ b/av1/encoder/rd.h @@ -96,6 +96,54 @@ typedef enum { #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + THR_SR_NEAREST_NEARMV, +#if CONFIG_EXT_REFS + THR_SR_NEAREST_NEARL2, + THR_SR_NEAREST_NEARL3, + THR_SR_NEAREST_NEARB, +#endif // CONFIG_EXT_REFS + THR_SR_NEAREST_NEARG, + THR_SR_NEAREST_NEARA, + + /* + THR_SR_NEAREST_NEWMV, +#if CONFIG_EXT_REFS + THR_SR_NEAREST_NEWL2, + THR_SR_NEAREST_NEWL3, + THR_SR_NEAREST_NEWB, +#endif // CONFIG_EXT_REFS + THR_SR_NEAREST_NEWG, + THR_SR_NEAREST_NEWA,*/ + + THR_SR_NEAR_NEWMV, +#if CONFIG_EXT_REFS + THR_SR_NEAR_NEWL2, + THR_SR_NEAR_NEWL3, + THR_SR_NEAR_NEWB, +#endif // CONFIG_EXT_REFS + THR_SR_NEAR_NEWG, + THR_SR_NEAR_NEWA, + + THR_SR_ZERO_NEWMV, +#if CONFIG_EXT_REFS + THR_SR_ZERO_NEWL2, + THR_SR_ZERO_NEWL3, + THR_SR_ZERO_NEWB, +#endif // CONFIG_EXT_REFS + THR_SR_ZERO_NEWG, + THR_SR_ZERO_NEWA, + + THR_SR_NEW_NEWMV, +#if CONFIG_EXT_REFS + THR_SR_NEW_NEWL2, + THR_SR_NEW_NEWL3, + THR_SR_NEW_NEWB, +#endif // CONFIG_EXT_REFS + THR_SR_NEW_NEWG, + THR_SR_NEW_NEWA, +#endif // CONFIG_COMPOUND_SINGLEREF + THR_COMP_NEAREST_NEARESTLA, #if CONFIG_EXT_REFS THR_COMP_NEAREST_NEARESTL2A, diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index 953ce9001..a220fb313 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c @@ -191,6 +191,56 @@ static const MODE_DEFINITION av1_mode_order[MAX_MODES] = { // TODO(zoeliu): May need to reconsider the order on the modes to check #if CONFIG_EXT_INTER + +#if CONFIG_COMPOUND_SINGLEREF + // Single ref comp mode + { SR_NEAREST_NEARMV, { LAST_FRAME, NONE_FRAME } }, +#if CONFIG_EXT_REFS + { SR_NEAREST_NEARMV, { LAST2_FRAME, NONE_FRAME } }, + { SR_NEAREST_NEARMV, { LAST3_FRAME, NONE_FRAME } }, + { SR_NEAREST_NEARMV, { BWDREF_FRAME, NONE_FRAME } }, +#endif // CONFIG_EXT_REFS + { SR_NEAREST_NEARMV, { GOLDEN_FRAME, NONE_FRAME } }, + { SR_NEAREST_NEARMV, { ALTREF_FRAME, NONE_FRAME } }, + + /* + { SR_NEAREST_NEWMV, { LAST_FRAME, NONE_FRAME } }, +#if CONFIG_EXT_REFS + { SR_NEAREST_NEWMV, { LAST2_FRAME, NONE_FRAME } }, + { SR_NEAREST_NEWMV, { LAST3_FRAME, NONE_FRAME } }, + { SR_NEAREST_NEWMV, { BWDREF_FRAME, NONE_FRAME } }, +#endif // CONFIG_EXT_REFS + { SR_NEAREST_NEWMV, { GOLDEN_FRAME, NONE_FRAME } }, + { SR_NEAREST_NEWMV, { ALTREF_FRAME, NONE_FRAME } },*/ + + { SR_NEAR_NEWMV, { LAST_FRAME, NONE_FRAME } }, +#if CONFIG_EXT_REFS + { SR_NEAR_NEWMV, { LAST2_FRAME, NONE_FRAME } }, + { SR_NEAR_NEWMV, { LAST3_FRAME, NONE_FRAME } }, + { SR_NEAR_NEWMV, { BWDREF_FRAME, NONE_FRAME } }, +#endif // CONFIG_EXT_REFS + { SR_NEAR_NEWMV, { GOLDEN_FRAME, NONE_FRAME } }, + { SR_NEAR_NEWMV, { ALTREF_FRAME, NONE_FRAME } }, + + { SR_ZERO_NEWMV, { LAST_FRAME, NONE_FRAME } }, +#if CONFIG_EXT_REFS + { SR_ZERO_NEWMV, { LAST2_FRAME, NONE_FRAME } }, + { SR_ZERO_NEWMV, { LAST3_FRAME, NONE_FRAME } }, + { SR_ZERO_NEWMV, { BWDREF_FRAME, NONE_FRAME } }, +#endif // CONFIG_EXT_REFS + { SR_ZERO_NEWMV, { GOLDEN_FRAME, NONE_FRAME } }, + { SR_ZERO_NEWMV, { ALTREF_FRAME, NONE_FRAME } }, + + { SR_NEW_NEWMV, { LAST_FRAME, NONE_FRAME } }, +#if CONFIG_EXT_REFS + { SR_NEW_NEWMV, { LAST2_FRAME, NONE_FRAME } }, + { SR_NEW_NEWMV, { LAST3_FRAME, NONE_FRAME } }, + { SR_NEW_NEWMV, { BWDREF_FRAME, NONE_FRAME } }, +#endif // CONFIG_EXT_REFS + { SR_NEW_NEWMV, { GOLDEN_FRAME, NONE_FRAME } }, + { SR_NEW_NEWMV, { ALTREF_FRAME, NONE_FRAME } }, +#endif // CONFIG_COMPOUND_SINGLEREF + { NEAREST_NEARESTMV, { LAST_FRAME, ALTREF_FRAME } }, #if CONFIG_EXT_REFS { NEAREST_NEARESTMV, { LAST2_FRAME, ALTREF_FRAME } }, @@ -4967,6 +5017,12 @@ static int cost_mv_ref(const AV1_COMP *const cpi, PREDICTION_MODE mode, if (is_inter_compound_mode(mode)) { return cpi ->inter_compound_mode_cost[mode_context][INTER_COMPOUND_OFFSET(mode)]; +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(mode)) { + return cpi + ->inter_singleref_comp_mode_cost[mode_context] + [INTER_SINGLEREF_COMP_OFFSET(mode)]; +#endif // CONFIG_COMPOUND_SINGLEREF } #endif @@ -5052,8 +5108,13 @@ typedef struct { int segment_yrate; PREDICTION_MODE modes[4]; #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + SEG_RDSTAT rdstat[4][INTER_MODES + INTER_SINGLEREF_COMP_MODES + + INTER_COMPOUND_MODES]; +#else // !CONFIG_COMPOUND_SINGLEREF SEG_RDSTAT rdstat[4][INTER_MODES + INTER_COMPOUND_MODES]; -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER SEG_RDSTAT rdstat[4][INTER_MODES]; #endif // CONFIG_EXT_INTER int mvthresh; @@ -5158,8 +5219,11 @@ static int check_best_zero_mv( } static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, - BLOCK_SIZE bsize, int_mv *frame_mv, int mi_row, - int mi_col, + BLOCK_SIZE bsize, int_mv *frame_mv, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int_mv *frame_comp_mv, +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int mi_row, int mi_col, #if CONFIG_EXT_INTER int_mv *ref_mv_sub8x8[2], const uint8_t *mask, int mask_stride, @@ -5170,9 +5234,20 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, const int ph = block_size_high[bsize]; MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; - // This function should only ever be called for compound modes +// This function should only ever be called for compound modes +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) { + assert(is_inter_singleref_comp_mode(mbmi->mode)); + assert(frame_comp_mv); + } + assert(has_second_ref(mbmi) || is_inter_singleref_comp_mode(mbmi->mode)); + const int refs[2] = { mbmi->ref_frame[0], has_second_ref(mbmi) + ? mbmi->ref_frame[1] + : mbmi->ref_frame[0] }; +#else assert(has_second_ref(mbmi)); const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] }; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF int_mv ref_mv[2]; int ite, ref; struct scale_factors sf; @@ -5185,11 +5260,18 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, const int p_row = ((mi_row * MI_SIZE) >> pd->subsampling_y) + 4 * ir; #if CONFIG_GLOBAL_MOTION int is_global[2]; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { +#else for (ref = 0; ref < 2; ++ref) { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF WarpedMotionParams *const wm = &xd->global_motion[xd->mi[0]->mbmi.ref_frame[ref]]; is_global[ref] = is_global_mv_block(xd->mi[0], block, wm->wmtype); } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) is_global[1] = is_global[0]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_GLOBAL_MOTION #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION @@ -5213,7 +5295,11 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, (void)ref_mv_sub8x8; #endif // CONFIG_EXT_INTER && CONFIG_CB4X4 +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { +#else for (ref = 0; ref < 2; ++ref) { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #if CONFIG_EXT_INTER && !CONFIG_CB4X4 if (bsize < BLOCK_8X8 && ref_mv_sub8x8 != NULL) ref_mv[ref].as_int = ref_mv_sub8x8[ref]->as_int; @@ -5233,6 +5319,24 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, } } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) { + assert(is_inter_singleref_comp_mode(mbmi->mode)); + // NOTE: For single ref comp mode, set up the 2nd set of ref_mv/pre_planes + // all from the 1st reference frame, i.e. refs[0]. + ref_mv[1] = x->mbmi_ext->ref_mvs[refs[0]][0]; + if (scaled_ref_frame[0]) { + int i; + // Swap out the reference frame for a version that's been scaled to + // match the resolution of the current frame, allowing the existing + // motion search code to be used without additional modifications. + for (i = 0; i < MAX_MB_PLANE; i++) + backup_yv12[1][i] = xd->plane[i].pre[1]; + av1_setup_pre_planes(xd, 1, scaled_ref_frame[0], mi_row, mi_col, NULL); + } + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // Since we have scaled the reference frames to match the size of the current // frame we must use a unit scaling factor during mode selection. #if CONFIG_HIGHBITDEPTH @@ -5243,9 +5347,16 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, cm->height); #endif // CONFIG_HIGHBITDEPTH - // Allow joint search multiple times iteratively for each reference frame - // and break out of the search loop if it couldn't find a better mv. +// Allow joint search multiple times iteratively for each reference frame +// and break out of the search loop if it couldn't find a better mv. +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + const int num_ites = + (has_second_ref(mbmi) || mbmi->mode == SR_NEW_NEWMV) ? 4 : 1; + const int start_ite = has_second_ref(mbmi) ? 0 : 1; + for (ite = start_ite; ite < (start_ite + num_ites); ite++) { +#else for (ite = 0; ite < 4; ite++) { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF struct buf_2d ref_yv12[2]; int bestsme = INT_MAX; int sadpb = x->sadperbit16; @@ -5273,12 +5384,23 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, ref_yv12[1] = xd->plane[plane].pre[1]; // Get the prediction block from the 'other' reference frame. +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + MV *const the_other_mv = (has_second_ref(mbmi) || id) + ? &frame_mv[refs[!id]].as_mv + : &frame_comp_mv[refs[0]].as_mv; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if CONFIG_HIGHBITDEPTH if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { second_pred = CONVERT_TO_BYTEPTR(second_pred_alloc_16); av1_highbd_build_inter_predictor( ref_yv12[!id].buf, ref_yv12[!id].stride, second_pred, pw, - &frame_mv[refs[!id]].as_mv, &sf, pw, ph, 0, mbmi->interp_filter, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + the_other_mv, +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) + &frame_mv[refs[!id]].as_mv, +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + &sf, pw, ph, 0, mbmi->interp_filter, #if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION &warp_types, p_col, p_row, #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION @@ -5286,14 +5408,18 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, } else { second_pred = (uint8_t *)second_pred_alloc_16; #endif // CONFIG_HIGHBITDEPTH - av1_build_inter_predictor(ref_yv12[!id].buf, ref_yv12[!id].stride, - second_pred, pw, &frame_mv[refs[!id]].as_mv, - &sf, pw, ph, &conv_params, mbmi->interp_filter, + av1_build_inter_predictor( + ref_yv12[!id].buf, ref_yv12[!id].stride, second_pred, pw, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + the_other_mv, +#else // !(CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF) + &frame_mv[refs[!id]].as_mv, +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + &sf, pw, ph, &conv_params, mbmi->interp_filter, #if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION - &warp_types, p_col, p_row, plane, !id, + &warp_types, p_col, p_row, plane, !id, #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION - MV_PRECISION_Q3, mi_col * MI_SIZE, - mi_row * MI_SIZE, xd); + MV_PRECISION_Q3, mi_col * MI_SIZE, mi_row * MI_SIZE, xd); #if CONFIG_HIGHBITDEPTH } #endif // CONFIG_HIGHBITDEPTH @@ -5302,13 +5428,24 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, if (id) xd->plane[plane].pre[0] = ref_yv12[id]; av1_set_mv_search_range(&x->mv_limits, &ref_mv[id].as_mv); - // Use the mv result from the single mode as mv predictor. - *best_mv = frame_mv[refs[id]].as_mv; +// Use the mv result from the single mode as mv predictor. +// Use the mv result from the single mode as mv predictor. +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi) && id) + *best_mv = frame_comp_mv[refs[0]].as_mv; + else +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + *best_mv = frame_mv[refs[id]].as_mv; best_mv->col >>= 3; best_mv->row >>= 3; - av1_set_mvcost(x, refs[id], id, mbmi->ref_mv_idx); +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + av1_set_mvcost(x, refs[0], 0, mbmi->ref_mv_idx); + else +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + av1_set_mvcost(x, refs[id], id, mbmi->ref_mv_idx); // Small-range full-pixel motion search. bestsme = @@ -5386,8 +5523,18 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, if (id) xd->plane[plane].pre[0] = ref_yv12[0]; if (bestsme < last_besterr[id]) { - frame_mv[refs[id]].as_mv = *best_mv; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // NOTE: For single ref comp mode, frame_mv stores the first mv and + // frame_comp_mv stores the second mv. + if (!has_second_ref(mbmi) && id) + frame_comp_mv[refs[0]].as_mv = *best_mv; + else +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + frame_mv[refs[id]].as_mv = *best_mv; last_besterr[id] = bestsme; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) last_besterr[!id] = last_besterr[id]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } else { break; } @@ -5395,27 +5542,67 @@ static void joint_motion_search(const AV1_COMP *cpi, MACROBLOCK *x, *rate_mv = 0; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + for (ref = 0; ref < 1 + has_second_ref(mbmi); ++ref) { +#else for (ref = 0; ref < 2; ++ref) { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF if (scaled_ref_frame[ref]) { // Restore the prediction frame pointers to their unscaled versions. int i; for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[ref] = backup_yv12[ref][i]; } - av1_set_mvcost(x, refs[ref], ref, mbmi->ref_mv_idx); + +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + av1_set_mvcost(x, refs[0], 0, mbmi->ref_mv_idx); + else +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + av1_set_mvcost(x, refs[ref], ref, mbmi->ref_mv_idx); + +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) { + // NOTE: For single ref comp mode, i.e. !has_second_ref(mbmi) is true, the + // first mv is stored in frame_mv[] and the second mv is stored in + // frame_comp_mv[]. + if (compound_ref0_mode(mbmi->mode) == NEWMV) // SR_NEW_NEWMV + *rate_mv += av1_mv_bit_cost(&frame_mv[refs[0]].as_mv, + &x->mbmi_ext->ref_mvs[refs[0]][0].as_mv, + x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); + assert(compound_ref1_mode(mbmi->mode) == NEWMV); + *rate_mv += av1_mv_bit_cost(&frame_comp_mv[refs[0]].as_mv, + &x->mbmi_ext->ref_mvs[refs[0]][0].as_mv, + x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); + } else { +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF #if CONFIG_EXT_INTER && !CONFIG_CB4X4 - if (bsize >= BLOCK_8X8) + if (bsize >= BLOCK_8X8) #endif // CONFIG_EXT_INTER && !CONFIG_CB4X4 - *rate_mv += av1_mv_bit_cost(&frame_mv[refs[ref]].as_mv, - &x->mbmi_ext->ref_mvs[refs[ref]][0].as_mv, - x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); + *rate_mv += av1_mv_bit_cost(&frame_mv[refs[ref]].as_mv, + &x->mbmi_ext->ref_mvs[refs[ref]][0].as_mv, + x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); #if CONFIG_EXT_INTER && !CONFIG_CB4X4 - else - *rate_mv += av1_mv_bit_cost(&frame_mv[refs[ref]].as_mv, - &ref_mv_sub8x8[ref]->as_mv, x->nmvjointcost, - x->mvcost, MV_COST_WEIGHT); + else + *rate_mv += av1_mv_bit_cost(&frame_mv[refs[ref]].as_mv, + &ref_mv_sub8x8[ref]->as_mv, x->nmvjointcost, + x->mvcost, MV_COST_WEIGHT); #endif // CONFIG_EXT_INTER && !CONFIG_CB4X4 +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } + +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) { + if (scaled_ref_frame[0]) { + // Restore the prediction frame pointers to their unscaled versions. + int i; + for (i = 0; i < MAX_MB_PLANE; i++) + xd->plane[i].pre[1] = backup_yv12[1][i]; + } + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } static void estimate_ref_frame_costs(const AV1_COMMON *cm, @@ -5699,8 +5886,13 @@ static void single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x, int sadpb = x->sadperbit16; MV mvp_full; #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + int ref = + has_second_ref(mbmi) ? mbmi->ref_frame[ref_idx] : mbmi->ref_frame[0]; +#else // !CONFIG_COMPOUND_SINGLEREF int ref = mbmi->ref_frame[ref_idx]; -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER int ref = mbmi->ref_frame[0]; int ref_idx = 0; #endif // CONFIG_EXT_INTER @@ -5942,7 +6134,12 @@ static void build_second_inter_pred(const AV1_COMP *cpi, MACROBLOCK *x, const int ph = block_size_high[bsize]; MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; +#if CONFIG_COMPOUND_SINGLEREF + const int other_ref = + has_second_ref(mbmi) ? mbmi->ref_frame[!ref_idx] : mbmi->ref_frame[0]; +#else // !CONFIG_COMPOUND_SINGLEREF const int other_ref = mbmi->ref_frame[!ref_idx]; +#endif // CONFIG_COMPOUND_SINGLEREF struct scale_factors sf; #if CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION struct macroblockd_plane *const pd = &xd->plane[0]; @@ -5959,8 +6156,12 @@ static void build_second_inter_pred(const AV1_COMP *cpi, MACROBLOCK *x, (void)block; #endif // CONFIG_GLOBAL_MOTION || CONFIG_WARPED_MOTION - // This function should only ever be called for compound modes +// This function should only ever be called for compound modes +#if CONFIG_COMPOUND_SINGLEREF + assert(has_second_ref(mbmi) || is_inter_singleref_comp_mode(mbmi->mode)); +#else // !CONFIG_COMPOUND_SINGLEREF assert(has_second_ref(mbmi)); +#endif // CONFIG_COMPOUND_SINGLEREF struct buf_2d backup_yv12[MAX_MB_PLANE]; const YV12_BUFFER_CONFIG *const scaled_ref_frame = @@ -6044,7 +6245,12 @@ static void compound_single_motion_search( const int ph = block_size_high[bsize]; MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; +#if CONFIG_COMPOUND_SINGLEREF + const int ref = + has_second_ref(mbmi) ? mbmi->ref_frame[ref_idx] : mbmi->ref_frame[0]; +#else const int ref = mbmi->ref_frame[ref_idx]; +#endif // CONFIG_COMPOUND_SINGLEREF int_mv ref_mv = x->mbmi_ext->ref_mvs[ref][0]; struct macroblockd_plane *const pd = &xd->plane[0]; @@ -6054,6 +6260,10 @@ static void compound_single_motion_search( // Check that this is either an interinter or an interintra block assert(has_second_ref(mbmi) || +#if CONFIG_COMPOUND_SINGLEREF + // or a single ref comp pred mode + is_inter_singleref_comp_mode(mbmi->mode) || +#endif // CONFIG_COMPOUND_SINGLEREF (ref_idx == 0 && mbmi->ref_frame[1] == INTRA_FRAME)); if (scaled_ref_frame) { @@ -6089,7 +6299,12 @@ static void compound_single_motion_search( best_mv->col >>= 3; best_mv->row >>= 3; - av1_set_mvcost(x, ref, ref_idx, mbmi->ref_mv_idx); +#if CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + av1_set_mvcost(x, ref, 0, mbmi->ref_mv_idx); + else +#endif // CONFIG_COMPOUND_SINGLEREF + av1_set_mvcost(x, ref, ref_idx, mbmi->ref_mv_idx); // Small-range full-pixel motion search. bestsme = av1_refining_search_8p_c(x, sadpb, search_range, @@ -6163,7 +6378,12 @@ static void compound_single_motion_search( xd->plane[i].pre[ref_idx] = backup_yv12[i]; } - av1_set_mvcost(x, ref, ref_idx, mbmi->ref_mv_idx); +#if CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + av1_set_mvcost(x, ref, 0, mbmi->ref_mv_idx); + else +#endif // CONFIG_COMPOUND_SINGLEREF + av1_set_mvcost(x, ref, ref_idx, mbmi->ref_mv_idx); *rate_mv += av1_mv_bit_cost(this_mv, &ref_mv.as_mv, x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); } @@ -6172,13 +6392,23 @@ static void compound_single_motion_search( // where the second prediction is also an inter mode. static void compound_single_motion_search_interinter( const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, int_mv *frame_mv, +#if CONFIG_COMPOUND_SINGLEREF + int_mv *frame_comp_mv, +#endif // CONFIG_COMPOUND_SINGLEREF int mi_row, int mi_col, const uint8_t *mask, int mask_stride, int *rate_mv, const int block, int ref_idx) { MACROBLOCKD *xd = &x->e_mbd; MB_MODE_INFO *mbmi = &xd->mi[0]->mbmi; - // This function should only ever be called for compound modes +// This function should only ever be called for compound modes +#if CONFIG_COMPOUND_SINGLEREF + int is_singleref_comp_mode = + !has_second_ref(mbmi) && is_inter_singleref_comp_mode(mbmi->mode); + assert(has_second_ref(mbmi) || is_singleref_comp_mode); + if (is_singleref_comp_mode && ref_idx) assert(frame_comp_mv); +#else // !CONFIG_COMPOUND_SINGLEREF assert(has_second_ref(mbmi)); +#endif // CONFIG_COMPOUND_SINGLEREF // Prediction buffer from second frame. #if CONFIG_HIGHBITDEPTH @@ -6192,8 +6422,20 @@ static void compound_single_motion_search_interinter( DECLARE_ALIGNED(16, uint8_t, second_pred[MAX_SB_SQUARE]); #endif // CONFIG_HIGHBITDEPTH +#if CONFIG_COMPOUND_SINGLEREF + MV *this_mv = has_second_ref(mbmi) + ? &frame_mv[mbmi->ref_frame[ref_idx]].as_mv + : (ref_idx ? &frame_comp_mv[mbmi->ref_frame[0]].as_mv + : &frame_mv[mbmi->ref_frame[0]].as_mv); + const MV *other_mv = + has_second_ref(mbmi) + ? &frame_mv[mbmi->ref_frame[!ref_idx]].as_mv + : (ref_idx ? &frame_mv[mbmi->ref_frame[0]].as_mv + : &frame_comp_mv[mbmi->ref_frame[0]].as_mv); +#else // !CONFIG_COMPOUND_SINGLEREF MV *this_mv = &frame_mv[mbmi->ref_frame[ref_idx]].as_mv; const MV *other_mv = &frame_mv[mbmi->ref_frame[!ref_idx]].as_mv; +#endif // CONFIG_COMPOUND_SINGLEREF build_second_inter_pred(cpi, x, bsize, other_mv, mi_row, mi_col, block, ref_idx, second_pred); @@ -6218,21 +6460,40 @@ static void do_masked_motion_search_indexed( mask = av1_get_compound_type_mask(comp_data, sb_type); int_mv frame_mv[TOTAL_REFS_PER_FRAME]; +#if CONFIG_COMPOUND_SINGLEREF + int_mv frame_comp_mv[TOTAL_REFS_PER_FRAME]; +#endif // CONFIG_COMPOUND_SINGLEREF MV_REFERENCE_FRAME rf[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] }; assert(bsize >= BLOCK_8X8 || CONFIG_CB4X4); frame_mv[rf[0]].as_int = cur_mv[0].as_int; - frame_mv[rf[1]].as_int = cur_mv[1].as_int; +#if CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + frame_comp_mv[rf[0]].as_int = cur_mv[1].as_int; + else +#endif // CONFIG_COMPOUND_SINGLEREF + frame_mv[rf[1]].as_int = cur_mv[1].as_int; if (which == 0 || which == 1) { - compound_single_motion_search_interinter(cpi, x, bsize, frame_mv, mi_row, - mi_col, mask, mask_stride, rate_mv, - 0, which); + compound_single_motion_search_interinter( + cpi, x, bsize, frame_mv, +#if CONFIG_COMPOUND_SINGLEREF + has_second_ref(mbmi) ? NULL : frame_comp_mv, +#endif // CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, mask, mask_stride, rate_mv, 0, which); } else if (which == 2) { - joint_motion_search(cpi, x, bsize, frame_mv, mi_row, mi_col, NULL, mask, - mask_stride, rate_mv, 0); + joint_motion_search(cpi, x, bsize, frame_mv, +#if CONFIG_COMPOUND_SINGLEREF + has_second_ref(mbmi) ? NULL : frame_comp_mv, +#endif // CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, NULL, mask, mask_stride, rate_mv, 0); } tmp_mv[0].as_int = frame_mv[rf[0]].as_int; - tmp_mv[1].as_int = frame_mv[rf[1]].as_int; +#if CONFIG_COMPOUND_SINGLEREF + if (!has_second_ref(mbmi)) + tmp_mv[1].as_int = frame_comp_mv[rf[0]].as_int; + else // comp ref +#endif // CONFIG_COMPOUND_SINGLEREF + tmp_mv[1].as_int = frame_mv[rf[1]].as_int; } #endif // CONFIG_COMPOUND_SEGMENT || CONFIG_WEDGE #endif // CONFIG_EXT_INTER @@ -6727,7 +6988,17 @@ static int interinter_compound_motion_search( #endif // CONFIG_COMPOUND_SEGMENT mbmi->interinter_compound_type }; - if (this_mode == NEW_NEWMV) { +#if CONFIG_COMPOUND_SINGLEREF + // NOTE: Mode is needed to identify the compound mode prediction, regardless + // of comp refs or single ref. + mbmi->mode = this_mode; +#endif // CONFIG_COMPOUND_SINGLEREF + + if (this_mode == NEW_NEWMV +#if CONFIG_COMPOUND_SINGLEREF + || this_mode == SR_NEW_NEWMV +#endif // CONFIG_COMPOUND_SINGLEREF + ) { do_masked_motion_search_indexed(cpi, x, cur_mv, &compound_data, bsize, mi_row, mi_col, tmp_mv, &tmp_rate_mv, 2); mbmi->mv[0].as_int = tmp_mv[0].as_int; @@ -6736,7 +7007,12 @@ static int interinter_compound_motion_search( do_masked_motion_search_indexed(cpi, x, cur_mv, &compound_data, bsize, mi_row, mi_col, tmp_mv, &tmp_rate_mv, 0); mbmi->mv[0].as_int = tmp_mv[0].as_int; - } else if (this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV) { + } else if (this_mode == NEAREST_NEWMV || this_mode == NEAR_NEWMV +#if CONFIG_COMPOUND_SINGLEREF + // || this_mode == SR_NEAREST_NEWMV + || this_mode == SR_NEAR_NEWMV || this_mode == SR_ZERO_NEWMV +#endif // CONFIG_COMPOUND_SINGLEREF + ) { do_masked_motion_search_indexed(cpi, x, cur_mv, &compound_data, bsize, mi_row, mi_col, tmp_mv, &tmp_rate_mv, 1); mbmi->mv[1].as_int = tmp_mv[1].as_int; @@ -6830,6 +7106,9 @@ typedef struct { static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, const BLOCK_SIZE bsize, int_mv (*const mode_mv)[TOTAL_REFS_PER_FRAME], +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int_mv (*const mode_comp_mv)[TOTAL_REFS_PER_FRAME], +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF const int mi_row, const int mi_col, int *const rate_mv, int_mv *const single_newmv, HandleInterModeArgs *const args) { @@ -6842,6 +7121,9 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, const int is_comp_interintra_pred = (mbmi->ref_frame[1] == INTRA_FRAME); #endif // CONFIG_EXT_INTER int_mv *const frame_mv = mode_mv[this_mode]; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int_mv *const frame_comp_mv = mode_comp_mv[this_mode]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF const int refs[2] = { mbmi->ref_frame[0], mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1] }; int i; @@ -6859,8 +7141,11 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, frame_mv[refs[1]].as_int = single_newmv[refs[1]].as_int; if (cpi->sf.comp_inter_joint_search_thresh <= bsize) { - joint_motion_search(cpi, x, bsize, frame_mv, mi_row, mi_col, NULL, NULL, - 0, rate_mv, 0); + joint_motion_search(cpi, x, bsize, frame_mv, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + NULL, // int_mv *frame_comp_mv +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, NULL, NULL, 0, rate_mv, 0); } else { *rate_mv = 0; for (i = 0; i < 2; ++i) { @@ -6875,8 +7160,12 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, if (cpi->sf.comp_inter_joint_search_thresh <= bsize) { frame_mv[refs[0]].as_int = mode_mv[compound_ref0_mode(this_mode)][refs[0]].as_int; - compound_single_motion_search_interinter( - cpi, x, bsize, frame_mv, mi_row, mi_col, NULL, 0, rate_mv, 0, 1); + compound_single_motion_search_interinter(cpi, x, bsize, frame_mv, +#if CONFIG_COMPOUND_SINGLEREF + NULL, +#endif // CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, NULL, 0, + rate_mv, 0, 1); } else { av1_set_mvcost(x, refs[1], 1, mbmi->ref_mv_idx); *rate_mv = av1_mv_bit_cost(&frame_mv[refs[1]].as_mv, @@ -6889,8 +7178,12 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, if (cpi->sf.comp_inter_joint_search_thresh <= bsize) { frame_mv[refs[1]].as_int = mode_mv[compound_ref1_mode(this_mode)][refs[1]].as_int; - compound_single_motion_search_interinter( - cpi, x, bsize, frame_mv, mi_row, mi_col, NULL, 0, rate_mv, 0, 0); + compound_single_motion_search_interinter(cpi, x, bsize, frame_mv, +#if CONFIG_COMPOUND_SINGLEREF + NULL, +#endif // CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, NULL, 0, + rate_mv, 0, 0); } else { av1_set_mvcost(x, refs[0], 0, mbmi->ref_mv_idx); *rate_mv = av1_mv_bit_cost(&frame_mv[refs[0]].as_mv, @@ -6898,7 +7191,7 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); } } -#else +#else // !CONFIG_EXT_INTER // Initialize mv using single prediction mode result. frame_mv[refs[0]].as_int = single_newmv[refs[0]].as_int; frame_mv[refs[1]].as_int = single_newmv[refs[1]].as_int; @@ -6915,6 +7208,41 @@ static int64_t handle_newmv(const AV1_COMP *const cpi, MACROBLOCK *const x, } } #endif // CONFIG_EXT_INTER +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(this_mode)) { + // Single ref comp mode + const int mode0 = compound_ref0_mode(this_mode); + + single_newmv[refs[0]].as_int = args->single_newmv[refs[0]].as_int; + frame_mv[refs[0]].as_int = (mode0 == NEWMV) + ? single_newmv[refs[0]].as_int + : mode_mv[mode0][refs[0]].as_int; + assert(compound_ref1_mode(this_mode) == NEWMV); + frame_comp_mv[refs[0]].as_int = single_newmv[refs[0]].as_int; + + if (cpi->sf.comp_inter_joint_search_thresh <= bsize) { + if (this_mode == SR_NEW_NEWMV) { + joint_motion_search(cpi, x, bsize, frame_mv, frame_comp_mv, mi_row, + mi_col, NULL, NULL, 0, rate_mv, 0); + } else { + assert( // this_mode == SR_NEAREST_NEWMV || + this_mode == SR_NEAR_NEWMV || this_mode == SR_ZERO_NEWMV); + compound_single_motion_search_interinter(cpi, x, bsize, frame_mv, + frame_comp_mv, mi_row, mi_col, + NULL, 0, rate_mv, 0, 1); + } + } else { + *rate_mv = 0; + av1_set_mvcost(x, refs[0], 0, mbmi->ref_mv_idx); + if (mode0 == NEWMV) + *rate_mv += av1_mv_bit_cost(&frame_mv[refs[0]].as_mv, + &mbmi_ext->ref_mvs[refs[0]][0].as_mv, + x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); + *rate_mv += av1_mv_bit_cost(&frame_comp_mv[refs[0]].as_mv, + &mbmi_ext->ref_mvs[refs[0]][0].as_mv, + x->nmvjointcost, x->mvcost, MV_COST_WEIGHT); + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } else { #if CONFIG_EXT_INTER if (is_comp_interintra_pred) { @@ -7153,7 +7481,11 @@ static int64_t motion_mode_rd( *mbmi = *best_bmc_mbmi; mbmi->motion_mode = OBMC_CAUSAL; #endif // CONFIG_EXT_INTER - if (!is_comp_pred && have_newmv_in_inter_mode(this_mode)) { + if (!is_comp_pred && +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + !is_inter_singleref_comp_mode(this_mode) && +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + have_newmv_in_inter_mode(this_mode)) { int tmp_rate_mv = 0; single_motion_search(cpi, x, bsize, mi_row, mi_col, @@ -7464,11 +7796,17 @@ static int64_t motion_mode_rd( return 0; } -static int64_t handle_inter_mode( - const AV1_COMP *const cpi, MACROBLOCK *x, BLOCK_SIZE bsize, - RD_STATS *rd_stats, RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv, - int *disable_skip, int_mv (*mode_mv)[TOTAL_REFS_PER_FRAME], int mi_row, - int mi_col, HandleInterModeArgs *args, const int64_t ref_best_rd) { +static int64_t handle_inter_mode(const AV1_COMP *const cpi, MACROBLOCK *x, + BLOCK_SIZE bsize, RD_STATS *rd_stats, + RD_STATS *rd_stats_y, RD_STATS *rd_stats_uv, + int *disable_skip, + int_mv (*mode_mv)[TOTAL_REFS_PER_FRAME], +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int_mv (*mode_comp_mv)[TOTAL_REFS_PER_FRAME], +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int mi_row, int mi_col, + HandleInterModeArgs *args, + const int64_t ref_best_rd) { const AV1_COMMON *cm = &cpi->common; (void)cm; MACROBLOCKD *xd = &x->e_mbd; @@ -7477,7 +7815,14 @@ static int64_t handle_inter_mode( MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext; const int is_comp_pred = has_second_ref(mbmi); const int this_mode = mbmi->mode; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + const int is_singleref_comp_mode = is_inter_singleref_comp_mode(this_mode); +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF int_mv *frame_mv = mode_mv[this_mode]; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // The comp mv for the compound mode in single ref + int_mv *frame_comp_mv = mode_comp_mv[this_mode]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF int i; int refs[2] = { mbmi->ref_frame[0], (mbmi->ref_frame[1] < 0 ? 0 : mbmi->ref_frame[1]) }; @@ -7544,7 +7889,11 @@ static int64_t handle_inter_mode( #endif // CONFIG_EXT_INTER #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if (is_comp_pred || is_singleref_comp_mode) +#else // !CONFIG_COMPOUND_SINGLEREF if (is_comp_pred) +#endif // CONFIG_COMPOUND_SINGLEREF mode_ctx = mbmi_ext->compound_mode_context[refs[0]]; else #endif // CONFIG_EXT_INTER @@ -7570,12 +7919,22 @@ static int64_t handle_inter_mode( if (frame_mv[refs[0]].as_int == INVALID_MV || frame_mv[refs[1]].as_int == INVALID_MV) return INT64_MAX; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + } else if (is_singleref_comp_mode) { + if (frame_mv[refs[0]].as_int == INVALID_MV || + frame_comp_mv[refs[0]].as_int == INVALID_MV) + return INT64_MAX; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF } mbmi->motion_mode = SIMPLE_TRANSLATION; if (have_newmv_in_inter_mode(this_mode)) { - const int64_t ret_val = handle_newmv(cpi, x, bsize, mode_mv, mi_row, mi_col, - &rate_mv, single_newmv, args); + const int64_t ret_val = + handle_newmv(cpi, x, bsize, mode_mv, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + mode_comp_mv, +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, &rate_mv, single_newmv, args); if (ret_val != 0) return ret_val; else @@ -7589,6 +7948,16 @@ static int64_t handle_inter_mode( mbmi->mv[i].as_int = cur_mv[i].as_int; } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (!is_comp_pred && is_singleref_comp_mode) { + cur_mv[1] = frame_comp_mv[refs[0]]; + // Clip "next_nearest" so that it does not extend to far out of image + if (this_mode != NEWMV) clamp_mv2(&cur_mv[1].as_mv, xd); + if (mv_check_bounds(&x->mv_limits, &cur_mv[1].as_mv)) return INT64_MAX; + mbmi->mv[1].as_int = cur_mv[1].as_int; + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if CONFIG_EXT_INTER if (this_mode == NEAREST_NEARESTMV) #else @@ -7612,7 +7981,12 @@ static int64_t handle_inter_mode( #if CONFIG_EXT_INTER if (mbmi_ext->ref_mv_count[ref_frame_type] > 0) { +#if CONFIG_COMPOUND_SINGLEREF + if (this_mode == NEAREST_NEWMV || // this_mode == SR_NEAREST_NEWMV || + this_mode == SR_NEAREST_NEARMV) { +#else // !CONFIG_COMPOUND_SINGLEREF if (this_mode == NEAREST_NEWMV) { +#endif // CONFIG_COMPOUND_SINGLEREF cur_mv[0] = mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv; lower_mv_precision(&cur_mv[0].as_mv, cm->allow_high_precision_mv); @@ -7633,7 +8007,11 @@ static int64_t handle_inter_mode( if (mbmi_ext->ref_mv_count[ref_frame_type] > 1) { int ref_mv_idx = mbmi->ref_mv_idx + 1; - if (this_mode == NEAR_NEWMV || this_mode == NEAR_NEARMV) { + if (this_mode == NEAR_NEWMV || +#if CONFIG_COMPOUND_SINGLEREF + this_mode == SR_NEAR_NEWMV || +#endif // CONFIG_COMPOUND_SINGLEREF + this_mode == NEAR_NEARMV) { cur_mv[0] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; lower_mv_precision(&cur_mv[0].as_mv, cm->allow_high_precision_mv); @@ -7642,8 +8020,17 @@ static int64_t handle_inter_mode( mbmi->mv[0].as_int = cur_mv[0].as_int; } - if (this_mode == NEW_NEARMV || this_mode == NEAR_NEARMV) { - cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv; + if (this_mode == NEW_NEARMV || +#if CONFIG_COMPOUND_SINGLEREF + this_mode == SR_NEAREST_NEARMV || +#endif // CONFIG_COMPOUND_SINGLEREF + this_mode == NEAR_NEARMV) { +#if CONFIG_COMPOUND_SINGLEREF + if (this_mode == SR_NEAREST_NEARMV) + cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + else +#endif // CONFIG_COMPOUND_SINGLEREF + cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv; lower_mv_precision(&cur_mv[1].as_mv, cm->allow_high_precision_mv); clamp_mv2(&cur_mv[1].as_mv, xd); @@ -7651,7 +8038,7 @@ static int64_t handle_inter_mode( mbmi->mv[1].as_int = cur_mv[1].as_int; } } -#else +#else // !CONFIG_EXT_INTER if (this_mode == NEARMV && is_comp_pred) { uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame); if (mbmi_ext->ref_mv_count[ref_frame_type] > 1) { @@ -7729,7 +8116,11 @@ static int64_t handle_inter_mode( #endif // CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION #if CONFIG_WEDGE || CONFIG_COMPOUND_SEGMENT +#if CONFIG_COMPOUND_SINGLEREF + if (is_comp_pred || is_singleref_comp_mode) { +#else if (is_comp_pred) { +#endif // CONFIG_COMPOUND_SINGLEREF int rate_sum, rs2; int64_t dist_sum; int64_t best_rd_compound = INT64_MAX, best_rd_cur = INT64_MAX; @@ -7759,6 +8150,17 @@ static int64_t handle_inter_mode( best_compound_data.seg_mask = tmp_mask_buf; #endif // CONFIG_COMPOUND_SEGMENT +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // TODO(zoeliu): To further check whether the following setups are needed. + // Single ref compound mode: Prepare the 2nd ref frame predictor the same as + // the 1st one. + if (!is_comp_pred && is_singleref_comp_mode) { + xd->block_refs[1] = xd->block_refs[0]; + for (i = 0; i < MAX_MB_PLANE; i++) + xd->plane[i].pre[1] = xd->plane[i].pre[0]; + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (masked_compound_used) { av1_cost_tokens(compound_type_cost, cm->fc->compound_type_prob[bsize], av1_compound_type_tree); @@ -8691,6 +9093,9 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, unsigned char segment_id = mbmi->segment_id; int comp_pred, i, k; int_mv frame_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME]; +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + int_mv frame_comp_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME]; +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF struct buf_2d yv12_mb[TOTAL_REFS_PER_FRAME][MAX_MB_PLANE]; int_mv single_newmv[TOTAL_REFS_PER_FRAME] = { { 0 } }; #if CONFIG_EXT_INTER @@ -8871,6 +9276,10 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, #endif // CONFIG_GLOBAL_MOTION #if CONFIG_EXT_INTER frame_mv[NEW_NEWMV][ref_frame].as_int = INVALID_MV; +#if CONFIG_COMPOUND_SINGLEREF + frame_mv[SR_NEW_NEWMV][ref_frame].as_int = INVALID_MV; + frame_comp_mv[SR_NEW_NEWMV][ref_frame].as_int = INVALID_MV; +#endif // CONFIG_COMPOUND_SINGLEREF #if CONFIG_GLOBAL_MOTION frame_mv[ZERO_ZEROMV][ref_frame].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame], @@ -8998,6 +9407,12 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, mode_skip_mask[ALTREF_FRAME] |= (1 << NEAREST_NEARESTMV); if (frame_mv[NEAR_NEARMV][ALTREF_FRAME].as_int != zeromv.as_int) mode_skip_mask[ALTREF_FRAME] |= (1 << NEAR_NEARMV); +#if CONFIG_COMPOUND_SINGLEREF + if (frame_mv[SR_NEAREST_NEARMV][ALTREF_FRAME].as_int != zeromv.as_int || + frame_comp_mv[SR_NEAREST_NEARMV][ALTREF_FRAME].as_int != + zeromv.as_int) + mode_skip_mask[ALTREF_FRAME] |= (1 << SR_NEAREST_NEARMV); +#endif // CONFIG_COMPOUND_SINGLEREF #endif // CONFIG_EXT_INTER } } @@ -9104,6 +9519,13 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, frame_mv[compound_ref0_mode(this_mode)][ref_frame].as_int; frame_mv[this_mode][second_ref_frame].as_int = frame_mv[compound_ref1_mode(this_mode)][second_ref_frame].as_int; +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(this_mode)) { + frame_mv[this_mode][ref_frame].as_int = + frame_mv[compound_ref0_mode(this_mode)][ref_frame].as_int; + frame_comp_mv[this_mode][ref_frame].as_int = + frame_mv[compound_ref1_mode(this_mode)][ref_frame].as_int; +#endif // CONFIG_COMPOUND_SINGLEREF } #endif // CONFIG_EXT_INTER @@ -9265,6 +9687,15 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, if (comp_pred) xd->plane[i].pre[1] = yv12_mb[second_ref_frame][i]; } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // Single ref compound mode + if (!comp_pred && is_inter_singleref_comp_mode(mbmi->mode)) { + xd->block_refs[1] = xd->block_refs[0]; + for (i = 0; i < MAX_MB_PLANE; i++) + xd->plane[i].pre[1] = xd->plane[i].pre[0]; + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if CONFIG_EXT_INTER && CONFIG_INTERINTRA mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1); #endif // CONFIG_EXT_INTER && CONFIG_INTERINTRA @@ -9479,6 +9910,27 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, mbmi_ext->ref_mvs[mbmi->ref_frame[1]][0] = this_mv; } } +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(mbmi->mode)) { + if (mbmi_ext->ref_mv_count[ref_frame_type] > 1) { + // TODO(zoeliu): To further investigate which ref_mv_idx should be + // chosen for the mode of SR_NEAR_NEWMV. + int ref_mv_idx = 0; + // Special case: SR_NEAR_NEWMV mode use + // 1 + mbmi->ref_mv_idx (like NEARMV) instead of + // mbmi->ref_mv_idx (like NEWMV) + if (mbmi->mode == SR_NEAR_NEWMV) ref_mv_idx = 1; + + if (compound_ref0_mode(mbmi->mode) == NEWMV || + compound_ref1_mode(mbmi->mode) == NEWMV) { + int_mv this_mv = + mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + clamp_mv_ref(&this_mv.as_mv, xd->n8_w << MI_SIZE_LOG2, + xd->n8_h << MI_SIZE_LOG2, xd); + mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0] = this_mv; + } + } +#endif // CONFIG_COMPOUND_SINGLEREF } else { #endif // CONFIG_EXT_INTER if (mbmi->mode == NEWMV && mbmi_ext->ref_mv_count[ref_frame_type] > 1) { @@ -9521,6 +9973,9 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, #endif // CONFIG_EXT_INTER this_rd = handle_inter_mode(cpi, x, bsize, &rd_stats, &rd_stats_y, &rd_stats_uv, &disable_skip, frame_mv, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + frame_comp_mv, +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF mi_row, mi_col, &args, best_rd); rate2 = rd_stats.rate; @@ -9544,15 +9999,23 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, // TODO(jingning): This needs some refactoring to improve code quality // and reduce redundant steps. #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + if ((have_nearmv_in_inter_mode(mbmi->mode) && + mbmi_ext->ref_mv_count[ref_frame_type] > 2) || + ((mbmi->mode == NEWMV || mbmi->mode == SR_NEW_NEWMV || + mbmi->mode == NEW_NEWMV) && + mbmi_ext->ref_mv_count[ref_frame_type] > 1)) { +#else // !CONFIG_COMPOUND_SINGLEREF if ((have_nearmv_in_inter_mode(mbmi->mode) && mbmi_ext->ref_mv_count[ref_frame_type] > 2) || ((mbmi->mode == NEWMV || mbmi->mode == NEW_NEWMV) && mbmi_ext->ref_mv_count[ref_frame_type] > 1)) { -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER if ((mbmi->mode == NEARMV && mbmi_ext->ref_mv_count[ref_frame_type] > 2) || (mbmi->mode == NEWMV && mbmi_ext->ref_mv_count[ref_frame_type] > 1)) { -#endif +#endif // CONFIG_EXT_INTER int_mv backup_mv = frame_mv[NEARMV][ref_frame]; MB_MODE_INFO backup_mbmi = *mbmi; int backup_skip = x->skip; @@ -9646,6 +10109,34 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, xd->n8_h << MI_SIZE_LOG2, xd); mbmi_ext->ref_mvs[mbmi->ref_frame[1]][0] = this_mv; } +#if CONFIG_COMPOUND_SINGLEREF + } else if (is_inter_singleref_comp_mode(mbmi->mode)) { + int ref_mv_idx = mbmi->ref_mv_idx; + // Special case: SR_NEAR_NEWMV mode use + // 1 + mbmi->ref_mv_idx (like NEARMV) instead of + // mbmi->ref_mv_idx (like NEWMV) + if (mbmi->mode == SR_NEAR_NEWMV) ref_mv_idx = 1 + mbmi->ref_mv_idx; + + // TODO(zoeliu): For the mode of SR_NEAREST_NEWMV, as it only runs + // the "if", not the "else if", + // mbmi_ext->ref_mvs[mbmi->ref_frame[0]] takes the + // value for "NEWMV", instead of "NEARESTMV". + if (compound_ref0_mode(mbmi->mode) == NEWMV || + compound_ref1_mode(mbmi->mode) == NEWMV) { + int_mv this_mv = + mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv; + clamp_mv_ref(&this_mv.as_mv, xd->n8_w << MI_SIZE_LOG2, + xd->n8_h << MI_SIZE_LOG2, xd); + mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0] = this_mv; + } else if (compound_ref0_mode(mbmi->mode) == NEARESTMV || + compound_ref1_mode(mbmi->mode) == NEARESTMV) { + int_mv this_mv = + mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv; + clamp_mv_ref(&this_mv.as_mv, xd->n8_w << MI_SIZE_LOG2, + xd->n8_h << MI_SIZE_LOG2, xd); + mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0] = this_mv; + } +#endif // CONFIG_COMPOUND_SINGLEREF } else { #endif // CONFIG_EXT_INTER for (ref = 0; ref < 1 + comp_pred; ++ref) { @@ -9691,9 +10182,13 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, args.single_newmv_rate = dummy_single_newmv_rate; args.modelled_rd = NULL; #endif // CONFIG_EXT_INTER - tmp_alt_rd = handle_inter_mode( - cpi, x, bsize, &tmp_rd_stats, &tmp_rd_stats_y, &tmp_rd_stats_uv, - &dummy_disable_skip, frame_mv, mi_row, mi_col, &args, best_rd); + tmp_alt_rd = handle_inter_mode(cpi, x, bsize, &tmp_rd_stats, + &tmp_rd_stats_y, &tmp_rd_stats_uv, + &dummy_disable_skip, frame_mv, +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + frame_comp_mv, +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + mi_row, mi_col, &args, best_rd); // Prevent pointers from escaping local scope args.single_newmv = NULL; #if CONFIG_EXT_INTER @@ -9813,6 +10308,15 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, rate2 += ref_costs_single[ref_frame]; } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // Add the cost to signal single/comp mode in single ref. + if (!comp_pred && cm->reference_mode != COMPOUND_REFERENCE) { + aom_prob singleref_comp_mode_p = av1_get_inter_mode_prob(cm, xd); + rate2 += av1_cost_bit(singleref_comp_mode_p, + is_inter_singleref_comp_mode(mbmi->mode)); + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + #if CONFIG_MOTION_VAR || CONFIG_WARPED_MOTION if (ref_frame == INTRA_FRAME) { #else @@ -10010,6 +10514,15 @@ void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data, xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i]; } +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + // Single ref compound mode + if (!has_second_ref(mbmi) && is_inter_singleref_comp_mode(mbmi->mode)) { + xd->block_refs[1] = xd->block_refs[0]; + for (i = 0; i < MAX_MB_PLANE; i++) + xd->plane[i].pre[1] = xd->plane[i].pre[0]; + } +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF + if (is_inter_mode(mbmi->mode)) { av1_build_inter_predictors_sb(cm, xd, mi_row, mi_col, NULL, bsize); #if CONFIG_MOTION_VAR @@ -10222,10 +10735,14 @@ PALETTE_EXIT: } #endif // CONFIG_FILTER_INTRA - // The inter modes' rate costs are not calculated precisely in some cases. - // Therefore, sometimes, NEWMV is chosen instead of NEARESTMV, NEARMV, and - // ZEROMV. Here, checks are added for those cases, and the mode decisions - // are corrected. +// The inter modes' rate costs are not calculated precisely in some cases. +// Therefore, sometimes, NEWMV is chosen instead of NEARESTMV, NEARMV, and +// ZEROMV. Here, checks are added for those cases, and the mode decisions +// are corrected. +#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF +// NOTE: For SR_NEW_NEWMV, no need to check as the two mvs from the same ref +// are surely different from each other. +#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF if (best_mbmode.mode == NEWMV #if CONFIG_EXT_INTER || best_mbmode.mode == NEW_NEWMV @@ -10344,11 +10861,17 @@ PALETTE_EXIT: // using a mode which can support ref_mv_idx if (best_mbmode.ref_mv_idx != 0 && #if CONFIG_EXT_INTER +#if CONFIG_COMPOUND_SINGLEREF + !(best_mbmode.mode == NEWMV || best_mbmode.mode == SR_NEW_NEWMV || + best_mbmode.mode == NEW_NEWMV || + have_nearmv_in_inter_mode(best_mbmode.mode))) { +#else // !CONFIG_COMPOUND_SINGLEREF !(best_mbmode.mode == NEWMV || best_mbmode.mode == NEW_NEWMV || have_nearmv_in_inter_mode(best_mbmode.mode))) { -#else +#endif // CONFIG_COMPOUND_SINGLEREF +#else // !CONFIG_EXT_INTER !(best_mbmode.mode == NEARMV || best_mbmode.mode == NEWMV)) { -#endif +#endif // CONFIG_EXT_INTER best_mbmode.ref_mv_idx = 0; } diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h index 5710d77c7..346d06433 100644 --- a/av1/encoder/speed_features.h +++ b/av1/encoder/speed_features.h @@ -38,6 +38,11 @@ enum { #if CONFIG_EXT_INTER enum { +#if CONFIG_COMPOUND_SINGLEREF +// TODO(zoeliu): To further consider following single ref comp modes: +// SR_NEAREST_NEARMV, SR_NEAREST_NEWMV, SR_NEAR_NEWMV, +// SR_ZERO_NEWMV, and SR_NEW_NEWMV. +#endif // CONFIG_COMPOUND_SINGLEREF INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV) | (1 << NEWMV) | (1 << NEAREST_NEARESTMV) | (1 << NEAR_NEARMV) | (1 << NEW_NEWMV) | (1 << NEAREST_NEWMV) | (1 << NEAR_NEWMV) | (1 << NEW_NEARMV) | @@ -67,7 +72,7 @@ enum { (1 << NEW_NEARMV) | (1 << NEAR_NEWMV) | (1 << NEAR_NEARMV), }; -#else +#else // !CONFIG_EXT_INTER enum { INTER_ALL = (1 << NEARESTMV) | (1 << NEARMV) | (1 << ZEROMV) | (1 << NEWMV), INTER_NEAREST = (1 << NEARESTMV), diff --git a/configure b/configure index 3a609f11a..0735dba93 100755 --- a/configure +++ b/configure @@ -524,6 +524,7 @@ post_process_cmdline() { enabled chroma_2x2 && disable_feature chroma_sub8x8 enabled dpcm_intra && enable_feature ext_tx enabled chroma_sub8x8 && enable_feature cb4x4 + enabled compound_singleref && enable_feature ext_inter if ! enabled delta_q && enabled ext_delta_q; then log_echo "ext_delta_q requires delta_q, so disabling ext_delta_q" -- GitLab