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
diff --git a/av1/common/av1_loopfilter.c b/av1/common/av1_loopfilter.c
index 4b27ae9..e08aef9 100644
--- a/av1/common/av1_loopfilter.c
+++ b/av1/common/av1_loopfilter.c
@@ -273,6 +273,11 @@
#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 e134548..a7a6332 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -119,14 +119,17 @@
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 @@
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 @@
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 @@
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 @@
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 @@
(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_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 3d8bf11..34842dc 100644
--- a/av1/common/entropymode.c
+++ b/av1/common/entropymode.c
@@ -1027,6 +1027,7 @@
#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 @@
{ 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 @@
};
#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 @@
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 @@
// 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 3f905de..d105f94 100644
--- a/av1/common/enums.h
+++ b/av1/common/enums.h
@@ -346,7 +346,7 @@
#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 ec5edee..209a636 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -66,7 +66,7 @@
#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 51c343d..bda1fc5 100644
--- a/av1/common/pred_common.c
+++ b/av1/common/pred_common.c
@@ -223,27 +223,34 @@
// 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 a0d1b63..8ca06c0 100644
--- a/av1/common/reconinter.c
+++ b/av1/common/reconinter.c
@@ -710,7 +710,8 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
#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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
#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 @@
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 @@
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 @@
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 7ea4289..2977864 100644
--- a/av1/common/reconinter.h
+++ b/av1/common/reconinter.h
@@ -407,14 +407,23 @@
#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 5e5db93..37583d6 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -215,7 +215,23 @@
}
}
}
+
+#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_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 @@
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 @@
} 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 @@
}
#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 @@
#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 @@
}
#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 @@
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 @@
#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 657eb6e..a1700ff 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 @@
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 @@
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 @@
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 @@
}
}
+#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 @@
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 @@
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 @@
}
#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 @@
#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 @@
}
#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 @@
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 @@
#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 @@
}
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 @@
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 @@
#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 @@
#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 fb8ab94..a9277fa 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 @@
{ 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 @@
#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 @@
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 @@
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 @@
}
}
}
+
+#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 @@
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 @@
#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 @@
#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 @@
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 @@
#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 @@
// 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;
+ 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;
- // 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;
+ int_mv mv[2];
+ int is_comp_ref = has_second_ref(&m->mbmi);
+ int ref;
- 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]);
+ 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 @@
*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 @@
}
#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 @@
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 @@
}
#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 @@
}
}
+#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 cf98b35..5c8744e 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -539,6 +539,21 @@
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 @@
#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 @@
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 @@
#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 @@
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 @@
#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 @@
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 @@
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 @@
&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 e1b515b..8aed521 100644
--- a/av1/encoder/encodemv.c
+++ b/av1/encoder/encodemv.c
@@ -295,6 +295,27 @@
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 @@
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 70de507..82c47b8 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -539,6 +539,10 @@
#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 52080ca..79543c4 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -2763,7 +2763,13 @@
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 d9a1333..ae49812 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -444,6 +444,12 @@
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 @@
#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 dfd4fcc..2e35cff 100644
--- a/av1/encoder/rd.h
+++ b/av1/encoder/rd.h
@@ -96,6 +96,54 @@
#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 953ce90..a220fb3 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -191,6 +191,56 @@
// 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 @@
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 @@
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 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 @@
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 @@
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 @@
(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 @@
}
}
+#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 @@
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 @@
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 @@
} 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 @@
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 @@
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 @@
*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_CB4X4
- 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);
-#if CONFIG_EXT_INTER && !CONFIG_CB4X4
+
+#if CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
+ if (!has_second_ref(mbmi))
+ av1_set_mvcost(x, refs[0], 0, mbmi->ref_mv_idx);
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_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)
#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);
+#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);
+#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 @@
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 @@
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 @@
(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 @@
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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
#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 @@
*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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
}
#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 @@
// 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 5710d77..346d064 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -38,6 +38,11 @@
#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 @@
(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 3a609f1..0735dba 100755
--- a/configure
+++ b/configure
@@ -524,6 +524,7 @@
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"