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/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],