Add motion selection to ext_skip
A new block mode, referred to as skip_mode is added. If a block is
coded as skip_mode, it will be inter-coded, with its references and
motion vectors derived from its neighboring blocks with zero-residue.
Otherwise, the block can be coded in the current intra or inter mode.
The computational load on skip_mode evaluation at the encoder should
be kept minimum. No transform size / type evaluations are needed.
Change-Id: I5aef0159c7d5ecd64258510835903375d6c536d6
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index 10dc769..51d80dd 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -1415,62 +1415,9 @@
}
}
#endif // CONFIG_FRAME_SIGN_BIAS
-
-#if CONFIG_EXT_SKIP
-void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
- cm->is_skip_mode_allowed = 0;
- cm->ref_frame_idx_0 = cm->ref_frame_idx_1 = INVALID_IDX;
-
- if (cm->frame_type == KEY_FRAME || cm->intra_only) return;
-
- BufferPool *const pool = cm->buffer_pool;
- RefCntBuffer *const frame_bufs = pool->frame_bufs;
-
- int ref_frame_offset_0 = -1;
- int ref_frame_offset_1 = INT_MAX;
- int ref_idx_0 = INVALID_IDX;
- int ref_idx_1 = INVALID_IDX;
-
- // Identify the nearest forward and backward references
- for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
- RefBuffer *const ref_frame = &cm->frame_refs[i];
- const int buf_idx = ref_frame->idx;
-
- // Invalid reference frame buffer
- if (buf_idx == INVALID_IDX) continue;
-
- const int ref_offset = frame_bufs[buf_idx].cur_frame_offset;
- if (ref_offset < (int)cm->frame_offset) {
- // Forward reference
- if (ref_offset > ref_frame_offset_0) {
- ref_frame_offset_0 = ref_offset;
- ref_idx_0 = i;
- }
- } else if (ref_offset > (int)cm->frame_offset) {
- // Backward reference
- if (ref_offset < ref_frame_offset_1) {
- ref_frame_offset_1 = ref_offset;
- ref_idx_1 = i;
- }
- }
- }
-
- // Flag is set when and only when both forward and backward references
- // are available and their distance is no greater than 3, i.e. as
- // opposed to the current frame position, the reference distance pair are
- // either: (1, 1), (1, 2), or (2, 1).
- if (ref_idx_0 != INVALID_IDX && ref_idx_1 != INVALID_IDX) {
- if ((ref_frame_offset_1 - ref_frame_offset_0) <= 3) {
- cm->is_skip_mode_allowed = 1;
- cm->ref_frame_idx_0 = ref_idx_0;
- cm->ref_frame_idx_1 = ref_idx_1;
- }
- }
-}
-#endif // CONFIG_EXT_SKIP
#endif // CONFIG_FRAME_MARKER
-#if CONFIG_MFMV
+#if CONFIG_MFMV || CONFIG_EXT_SKIP
// Although we assign 32 bit integers, all the values are strictly under 14
// bits.
static int div_mult[32] = {
@@ -1487,7 +1434,9 @@
output->col =
(int16_t)(ROUND_POWER_OF_TWO_SIGNED(ref.col * num * div_mult[den], 14));
}
+#endif // CONFIG_MFMV || CONFIG_EXT_SKIP
+#if CONFIG_MFMV
#define MAX_OFFSET_WIDTH 64
#define MAX_OFFSET_HEIGHT 0
@@ -2240,3 +2189,271 @@
return np;
}
#endif // CONFIG_EXT_WARPED_MOTION
+
+#if CONFIG_EXT_SKIP
+void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
+ cm->is_skip_mode_allowed = 0;
+ cm->ref_frame_idx_0 = cm->ref_frame_idx_1 = INVALID_IDX;
+
+ if (cm->frame_type == KEY_FRAME || cm->intra_only) return;
+
+ RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+ const int cur_frame_offset = cm->frame_offset;
+ int ref_frame_offset[2] = { -1, INT_MAX };
+ int ref_idx[2] = { INVALID_IDX, INVALID_IDX };
+ int ref_buf_idx[2] = { INVALID_IDX, INVALID_IDX };
+
+ // Identify the nearest forward and backward references
+ for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ const int buf_idx = cm->frame_refs[i].idx;
+ if (buf_idx == INVALID_IDX) continue;
+
+ const int ref_offset = frame_bufs[buf_idx].cur_frame_offset;
+ if (ref_offset < cur_frame_offset) {
+ // Forward reference
+ if (ref_offset > ref_frame_offset[0]) {
+ ref_frame_offset[0] = ref_offset;
+ ref_idx[0] = i;
+ ref_buf_idx[0] = buf_idx;
+ }
+ } else if (ref_offset > cur_frame_offset) {
+ // Backward reference
+ if (ref_offset < ref_frame_offset[1]) {
+ ref_frame_offset[1] = ref_offset;
+ ref_idx[1] = i;
+ ref_buf_idx[1] = buf_idx;
+ }
+ }
+ }
+
+ // Flag is set when and only when both forward and backward references
+ // are available and their distance is no greater than 3, i.e. as
+ // opposed to the current frame position, the reference distance pair are
+ // either: (1, 1), (1, 2), or (2, 1).
+ if (ref_idx[0] != INVALID_IDX && ref_idx[1] != INVALID_IDX) {
+ const int cur_to_fwd = cm->frame_offset - ref_frame_offset[0];
+ const int cur_to_bwd = ref_frame_offset[1] - cm->frame_offset;
+#if 0
+ if ((ref_frame_offset[1] - ref_frame_offset[0]) <= 3)
+#endif // 0
+ if (abs(cur_to_fwd - cur_to_bwd) <= 1) {
+ cm->is_skip_mode_allowed = 1;
+ cm->ref_frame_idx_0 = ref_idx[0];
+ cm->ref_frame_idx_1 = ref_idx[1];
+ }
+ }
+
+ // Set up the temporal mv candidates for skip mode.
+ cm->tpl_frame_ref0_idx = INVALID_IDX;
+ if (cm->is_skip_mode_allowed && cm->use_ref_frame_mvs) {
+ const int tpl_ref1_buf_idx = ref_buf_idx[1];
+ const int tpl_ref1_ref_offsets[INTER_REFS_PER_FRAME] = {
+ frame_bufs[tpl_ref1_buf_idx].lst_frame_offset,
+ frame_bufs[tpl_ref1_buf_idx].lst2_frame_offset,
+ frame_bufs[tpl_ref1_buf_idx].lst3_frame_offset,
+ frame_bufs[tpl_ref1_buf_idx].gld_frame_offset,
+ frame_bufs[tpl_ref1_buf_idx].bwd_frame_offset,
+ frame_bufs[tpl_ref1_buf_idx].alt2_frame_offset,
+ frame_bufs[tpl_ref1_buf_idx].alt_frame_offset
+ };
+
+ for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ if (tpl_ref1_ref_offsets[i] == ref_frame_offset[0]) {
+ cm->tpl_frame_ref0_idx = i;
+ break;
+ }
+ }
+ }
+}
+
+// Identify mvs for skip mode in the following order:
+// (1) Search the spatial two neighboring blocks (left/top);
+// (2) Search the temporal neighboring blocks;
+// (3) Consider NEAREST_NEARESTMV.
+
+#define SKIP_MODE_MV_LISTS 3
+#define SPATIAL_CANDIDATES 2
+#define TEMPORAL_CANDIDATES 2
+#define TOTAL_CANDIDATES (SPATIAL_CANDIDATES + TEMPORAL_CANDIDATES)
+
+void av1_setup_skip_mode_mvs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+ MB_MODE_INFO *mbmi, int mi_row, int mi_col,
+ const int_mv nearest_mv[2], find_mv_refs_sync sync,
+ void *const data) {
+#if 0
+ const int sb_mi_size = mi_size_wide[cm->sb_size];
+#endif // 0
+ const TileInfo *const tile = &xd->tile;
+ int i;
+
+ const MV_REFERENCE_FRAME skip_mode_refs[2] = {
+ LAST_FRAME + cm->ref_frame_idx_0, LAST_FRAME + cm->ref_frame_idx_1
+ };
+ const int8_t ref_frame_types[SKIP_MODE_MV_LISTS] = {
+ skip_mode_refs[0], skip_mode_refs[1], av1_ref_frame_type(skip_mode_refs)
+ };
+ int_mv mv_list[SKIP_MODE_MV_LISTS][TOTAL_CANDIDATES][2];
+ int mv_list_count[SKIP_MODE_MV_LISTS] = { 0 };
+
+ const BLOCK_SIZE bsize = mbmi->sb_type;
+ const int bw = block_size_wide[AOMMAX(bsize, BLOCK_8X8)];
+ const int bh = block_size_high[AOMMAX(bsize, BLOCK_8X8)];
+ const int num_8x8_blocks_wide = num_8x8_blocks_wide_lookup[bsize];
+ const int num_8x8_blocks_high = num_8x8_blocks_high_lookup[bsize];
+
+ // === Search mv candidate(s) over spatial neighboring blocks.
+ POSITION mv_search_pos_cur[SPATIAL_CANDIDATES];
+ mv_search_pos_cur[0].row = num_8x8_blocks_high - 1; // LEFT
+ mv_search_pos_cur[0].col = -1;
+ mv_search_pos_cur[1].row = -1; // TOP
+ mv_search_pos_cur[1].col = num_8x8_blocks_wide - 1;
+
+ MB_MODE_INFO *candidate_mbmi[SPATIAL_CANDIDATES] = { NULL };
+ for (i = 0; i < SPATIAL_CANDIDATES; ++i) {
+ const POSITION *const mv_pos = &mv_search_pos_cur[i];
+ if (is_inside(tile, mi_col, mi_row, cm->mi_rows, cm, mv_pos)) {
+ candidate_mbmi[i] =
+ !xd->mi[mv_pos->col + mv_pos->row * xd->mi_stride]
+ ? NULL
+ : &(xd->mi[mv_pos->col + mv_pos->row * xd->mi_stride]->mbmi);
+#if 0
+ if (candidate_mbmi[i] == NULL) continue;
+ // TODO(zoeliu): To investigate whether following sanity check is needed.
+ if ((mi_row & (sb_mi_size - 1)) + mv_pos->row >= sb_mi_size ||
+ (mi_col & (sb_mi_size - 1)) + mv_pos->col >= sb_mi_size)
+ continue;
+#endif // 0
+ }
+ }
+
+ // First scan on the spatial neighbors, considering both reference frames
+ // matched for compound mode.
+ for (i = 0; i < SPATIAL_CANDIDATES; ++i) {
+ if (candidate_mbmi[i]) {
+ if (has_second_ref(candidate_mbmi[i])) { // comp
+ if (av1_ref_frame_type(candidate_mbmi[i]->ref_frame) ==
+ ref_frame_types[2])
+ SKIP_MODE_MV_LIST_ADD(candidate_mbmi[i]->mv, mv_list, mv_list_count,
+ 2, bw, bh, xd);
+ } else { // single
+ if (candidate_mbmi[i]->ref_frame[0] == ref_frame_types[0])
+ SKIP_MODE_MV_LIST_ADD(candidate_mbmi[i]->mv, mv_list, mv_list_count,
+ 0, bw, bh, xd);
+ else if (candidate_mbmi[i]->ref_frame[0] == ref_frame_types[1])
+ SKIP_MODE_MV_LIST_ADD(candidate_mbmi[i]->mv, mv_list, mv_list_count,
+ 1, bw, bh, xd);
+ }
+ }
+ }
+
+ // Re-scan mv candidate(s) over spatial neighboring blocks of compound mode,
+ // with only one reference frame matching the skip mode.
+ for (i = 0; i < SPATIAL_CANDIDATES; ++i) {
+ if (candidate_mbmi[i] && has_second_ref(candidate_mbmi[i])) { // comp
+ if (candidate_mbmi[i]->ref_frame[0] == ref_frame_types[0] ||
+ candidate_mbmi[i]->ref_frame[1] == ref_frame_types[1]) {
+ const int rf_idx =
+ (candidate_mbmi[i]->ref_frame[1] == ref_frame_types[1]);
+ const int_mv rf_mv[2] = { candidate_mbmi[i]->mv[rf_idx],
+ candidate_mbmi[i]->mv[1 - rf_idx] };
+
+ SKIP_MODE_MV_LIST_ADD(rf_mv, mv_list, mv_list_count, rf_idx, bw, bh,
+ xd);
+ }
+ }
+ }
+
+// TODO(hkuang): Remove this sync after fixing pthread_cond_broadcast
+// on windows platform. The sync here is unncessary if use_perv_frame_mvs
+// is 0. But after removing it, there will be hang in the unit test on windows
+// due to several threads waiting for a thread's signal.
+#if defined(_WIN32) && !HAVE_PTHREAD_H
+ if (cm->frame_parallel_decode && sync != NULL) sync(data, mi_row);
+#endif
+
+ // === Search mv candidate(s) over temporal neighboring blocks.
+ if (cm->tpl_frame_ref0_idx != INVALID_IDX) {
+ // Synchronize here for frame parallel decode if sync function is provided.
+ if (cm->frame_parallel_decode && sync != NULL) {
+ sync(data, mi_row);
+ }
+
+ POSITION mv_search_pos_tpl[TEMPORAL_CANDIDATES];
+ mv_search_pos_tpl[0].row = num_8x8_blocks_high - 1; // current
+ mv_search_pos_tpl[0].col = num_8x8_blocks_wide - 1;
+ mv_search_pos_tpl[1].row = num_8x8_blocks_high; // bottom-right
+ mv_search_pos_tpl[1].col = num_8x8_blocks_wide;
+
+ const int mvs_rows = (cm->mi_rows + 1) >> 1;
+ const int mvs_cols = (cm->mi_cols + 1) >> 1;
+
+ RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
+
+ const int tpl_ref0_buf_idx = cm->frame_refs[cm->ref_frame_idx_0].idx;
+ const int tpl_ref0_offset = frame_bufs[tpl_ref0_buf_idx].cur_frame_offset;
+ const int tpl_ref1_buf_idx = cm->frame_refs[cm->ref_frame_idx_1].idx;
+ const int tpl_ref1_offset = frame_bufs[tpl_ref1_buf_idx].cur_frame_offset;
+
+ MV_REF *const tpl_mvs_base = frame_bufs[tpl_ref1_buf_idx].mvs;
+
+ for (i = 0; i < TEMPORAL_CANDIDATES; ++i) {
+ const POSITION *const mv_pos = &mv_search_pos_tpl[i];
+ const int tpl_mvs_row = (mi_row + mv_pos->row + 1) >> 1;
+ const int tpl_mvs_col = (mi_col + mv_pos->col + 1) >> 1;
+
+ if (tpl_mvs_row >= 0 && tpl_mvs_row < mvs_rows && tpl_mvs_col >= 0 &&
+ tpl_mvs_col < mvs_cols) {
+ MV_REF *mv_ref = &tpl_mvs_base[tpl_mvs_row * mvs_cols + tpl_mvs_col];
+ MV_REFERENCE_FRAME tpl_frame_rf[2] = { mv_ref->ref_frame[0],
+ mv_ref->ref_frame[1] };
+
+ // Check whether the temporal candidate block has its reference frame 0
+ // point to the same forward reference most recent to the current frame.
+ if (tpl_frame_rf[0] <= INTRA_FRAME ||
+ FWD_RF_OFFSET(tpl_frame_rf[0]) != cm->tpl_frame_ref0_idx)
+ continue;
+
+ // Scale the temporal candiate mv of the same forward reference frame
+ // for the current frame.
+ const int cur_to_ref0 = AOMMAX(1, cm->frame_offset - tpl_ref0_offset);
+ const int ref1_to_ref0 = AOMMAX(1, tpl_ref1_offset - tpl_ref0_offset);
+
+ MV tpl_frame_mv[2] = { mv_ref->mv[0].as_mv, mv_ref->mv[1].as_mv };
+ int_mv candidate_mv;
+ get_mv_projection(&candidate_mv.as_mv, tpl_frame_mv[0], cur_to_ref0,
+ ref1_to_ref0);
+
+ const int_mv tpl_mv[2] = { candidate_mv, mv_ref->mv[1] };
+ SKIP_MODE_MV_LIST_ADD(tpl_mv, mv_list, mv_list_count, 0, bw, bh, xd);
+ }
+ }
+ }
+
+ // === Finalize the mv/ref selection for the current block of skip mode.
+ // TODO(zoeliu): Several items to consider for possibly improving the coding
+ // performance further:
+ // (1) Consider more spatial / temporal neighboring blocks;
+ // (2) Signal the selection to differentiate between single or compoud mode;
+ // (3) May allow the use of the most recent forward reference of the temporal
+ // neighboring block.
+ if (mv_list_count[2] > 0) { // comp
+ mbmi->ref_frame[0] = cm->ref_frame_idx_0 + LAST_FRAME;
+ mbmi->ref_frame[1] = cm->ref_frame_idx_1 + LAST_FRAME;
+ mbmi->mv[0].as_int = mv_list[2][0][0].as_int;
+ mbmi->mv[1].as_int = mv_list[2][0][1].as_int;
+ } else if (mv_list_count[0] > 0) { // single - forward
+ mbmi->ref_frame[0] = cm->ref_frame_idx_0 + LAST_FRAME;
+ mbmi->ref_frame[1] = -1;
+ mbmi->mv[0].as_int = mv_list[0][0][0].as_int;
+ } else if (mv_list_count[1] > 0) { // single - backward
+ mbmi->ref_frame[0] = cm->ref_frame_idx_1 + LAST_FRAME;
+ mbmi->ref_frame[1] = -1;
+ mbmi->mv[0].as_int = mv_list[1][0][0].as_int;
+ } else {
+ mbmi->ref_frame[0] = cm->ref_frame_idx_0 + LAST_FRAME;
+ mbmi->ref_frame[1] = cm->ref_frame_idx_1 + LAST_FRAME;
+ mbmi->mv[0].as_int = nearest_mv[0].as_int;
+ mbmi->mv[1].as_int = nearest_mv[1].as_int;
+ }
+}
+#endif // CONFIG_EXT_SKIP
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index f0640ef..608e220 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -174,6 +174,22 @@
} \
} while (0)
+#if CONFIG_EXT_SKIP
+// This macro is used to add a motion vector pair to the skip mode mv list.
+#define SKIP_MODE_MV_LIST_ADD(mv, mv_list, mv_list_count, mv_list_idx, bw, bh, \
+ xd) \
+ do { \
+ const int mv_idx = (mv_list_count)[mv_list_idx]; \
+ (mv_list)[mv_list_idx][mv_idx][0] = (mv)[0]; \
+ CLIP_IN_ADD(&(mv_list)[mv_list_idx][mv_idx][0].as_mv, (bw), (bh), (xd)); \
+ if (mv_list_idx == 2) { \
+ (mv_list)[mv_list_idx][mv_idx][1] = (mv)[1]; \
+ CLIP_IN_ADD(&(mv_list)[mv_list_idx][mv_idx][1].as_mv, (bw), (bh), (xd)); \
+ } \
+ (mv_list_count)[mv_list_idx]++; \
+ } while (0)
+#endif // CONFIG_EXT_SKIP
+
// Checks that the given mi_row, mi_col and search point
// are inside the borders of the tile.
static INLINE int is_inside(const TileInfo *const tile, int mi_col, int mi_row,
@@ -389,6 +405,12 @@
int16_t *compound_mode_context, int_mv *mv_ref_list,
int mi_row, int mi_col, find_mv_refs_sync sync,
void *const data, int16_t *mode_context);
+#if CONFIG_EXT_SKIP
+void av1_setup_skip_mode_mvs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+ MB_MODE_INFO *mbmi, int mi_row, int mi_col,
+ const int_mv nearest_mv[2], find_mv_refs_sync sync,
+ void *const data);
+#endif // CONFIG_EXT_SKIP
// check a list of motion vectors by sad score using a number rows of pixels
// above and a number cols of pixels in the left to select the one with best
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 3952256..3755268 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -271,8 +271,10 @@
RefBuffer frame_refs[INTER_REFS_PER_FRAME];
#if CONFIG_EXT_SKIP
int is_skip_mode_allowed;
+ int skip_mode_flag;
int ref_frame_idx_0;
int ref_frame_idx_1;
+ int tpl_frame_ref0_idx;
#endif // CONFIG_EXT_SKIP
int new_fb_idx;
diff --git a/av1/common/reconinter.h b/av1/common/reconinter.h
index 272e4f6..f1e1ab1 100644
--- a/av1/common/reconinter.h
+++ b/av1/common/reconinter.h
@@ -448,10 +448,10 @@
static INLINE int av1_is_interp_needed(const MACROBLOCKD *const xd) {
(void)xd;
const MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
- if (mbmi->motion_mode == WARPED_CAUSAL) return 0;
#if CONFIG_EXT_SKIP
if (mbmi->skip_mode) return 0;
#endif // CONFIG_EXT_SKIP
+ if (mbmi->motion_mode == WARPED_CAUSAL) return 0;
if (is_nontrans_global_motion(xd)) return 0;
return 1;
}
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 650a053..91b14ad 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -3008,6 +3008,22 @@
}
av1_setup_frame_buf_refs(cm);
+#if CONFIG_EXT_SKIP
+ av1_setup_skip_mode_allowed(cm);
+ cm->skip_mode_flag = cm->is_skip_mode_allowed ? aom_rb_read_bit(rb) : 0;
+#if 0
+ printf(
+ "DECODER: Frame=%d, frame_offset=%d, show_frame=%d, "
+ "show_existing_frame=%d, is_skip_mode_allowed=%d, "
+ "ref_frame_idx=(%d,%d), frame_reference_mode=%d, "
+ "tpl_frame_ref0_idx=%d, skip_mode_flag=%d\n\n",
+ cm->current_video_frame, cm->frame_offset, cm->show_frame,
+ cm->show_existing_frame, cm->is_skip_mode_allowed, cm->ref_frame_idx_0,
+ cm->ref_frame_idx_1, cm->reference_mode, cm->tpl_frame_ref0_idx,
+ cm->skip_mode_flag);
+#endif // 0
+#endif // CONFIG_EXT_SKIP
+
#if CONFIG_FRAME_SIGN_BIAS
#if CONFIG_OBU
if (cm->frame_type != S_FRAME)
@@ -3516,16 +3532,6 @@
(cm->last_frame_type != KEY_FRAME);
#endif // CONFIG_TEMPMV_SIGNALING
-#if CONFIG_EXT_SKIP
- av1_setup_skip_mode_allowed(cm);
-#if 0
- printf("\nDECODER: Frame=%d, frame_offset=%d, show_frame=%d, "
- "is_skip_mode_allowed=%d, ref_frame_idx=(%d,%d)\n",
- cm->current_video_frame, cm->frame_offset, cm->show_frame,
- cm->is_skip_mode_allowed, cm->ref_frame_idx_0, cm->ref_frame_idx_1);
-#endif // 0
-#endif // CONFIG_EXT_SKIP
-
#if CONFIG_MFMV
av1_setup_motion_field(cm);
#endif // CONFIG_MFMV
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 5e06b37..8b17582 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -254,6 +254,10 @@
MB_MODE_INFO *mbmi = &mi->mbmi;
(void)cm;
+#if CONFIG_EXT_SKIP
+ if (mbmi->skip_mode) return SIMPLE_TRANSLATION;
+#endif // CONFIG_EXT_SKIP
+
const MOTION_MODE last_motion_mode_allowed =
motion_mode_allowed(0, xd->global_motion, xd, mi);
int motion_mode;
@@ -278,22 +282,9 @@
static PREDICTION_MODE read_inter_compound_mode(AV1_COMMON *cm, MACROBLOCKD *xd,
aom_reader *r, int16_t ctx) {
(void)cm;
-#if CONFIG_EXT_SKIP
- FRAME_CONTEXT *const ec_ctx = xd->tile_ctx;
- const int mode =
- xd->mi[0]->mbmi.skip_mode
- ? (NEAREST_NEARESTMV - NEAREST_NEARESTMV)
- : aom_read_symbol(r, ec_ctx->inter_compound_mode_cdf[ctx],
- INTER_COMPOUND_MODES, ACCT_STR);
- if (xd->mi[0]->mbmi.skip_mode && r->allow_update_cdf)
- update_cdf(ec_ctx->inter_compound_mode_cdf[ctx], mode,
- INTER_COMPOUND_MODES);
-#else
const int mode =
aom_read_symbol(r, xd->tile_ctx->inter_compound_mode_cdf[ctx],
INTER_COMPOUND_MODES, ACCT_STR);
-#endif // CONFIG_EXT_SKIP
-
FRAME_COUNTS *counts = xd->counts;
if (counts) ++counts->inter_compound_mode[ctx][mode];
assert(is_inter_compound_mode(NEAREST_NEARESTMV + mode));
@@ -602,23 +593,23 @@
#if CONFIG_EXT_SKIP
static int read_skip_mode(AV1_COMMON *cm, const MACROBLOCKD *xd, int segment_id,
aom_reader *r) {
- if (!cm->is_skip_mode_allowed) return 0;
+ if (!cm->skip_mode_flag) return 0;
if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {
// TODO(zoeliu): To revisit the handling of this scenario.
return 0;
- } else {
- const int ctx = av1_get_skip_mode_context(xd);
- FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
- const int skip_mode =
- aom_read_symbol(r, ec_ctx->skip_mode_cdfs[ctx], 2, ACCT_STR);
- FRAME_COUNTS *counts = xd->counts;
- if (counts) ++counts->skip_mode[ctx][skip_mode];
-
- // TODO(zoeliu): To handle:
- // if (!is_comp_ref_allowed(xd->mi[0]->mbmi.sb_type))
- return skip_mode;
}
+
+ if (!is_comp_ref_allowed(xd->mi[0]->mbmi.sb_type)) return 0;
+
+ const int ctx = av1_get_skip_mode_context(xd);
+ FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
+ const int skip_mode =
+ aom_read_symbol(r, ec_ctx->skip_mode_cdfs[ctx], 2, ACCT_STR);
+ FRAME_COUNTS *counts = xd->counts;
+ if (counts) ++counts->skip_mode[ctx][skip_mode];
+
+ return skip_mode;
}
#endif // CONFIG_EXT_SKIP
@@ -1258,21 +1249,6 @@
}
}
-#if CONFIG_EXT_SKIP
-static void update_block_reference_mode(AV1_COMMON *cm, const MACROBLOCKD *xd,
- REFERENCE_MODE mode,
- uint8_t allow_update_cdf) {
- if (cm->reference_mode == REFERENCE_MODE_SELECT) {
- assert(mode == SINGLE_REFERENCE || mode == COMPOUND_REFERENCE);
- const int ctx = av1_get_reference_mode_context(cm, xd);
- if (allow_update_cdf)
- update_cdf(xd->tile_ctx->comp_inter_cdf[ctx], mode, 2);
- FRAME_COUNTS *counts = xd->counts;
- if (counts) ++counts->comp_inter[ctx][mode];
- }
-}
-#endif // CONFIG_EXT_SKIP
-
#define READ_REF_BIT(pname) \
aom_read_symbol(r, av1_get_pred_cdf_##pname(cm, xd), 2, ACCT_STR)
#define READ_REF_BIT2(pname) \
@@ -1294,60 +1270,10 @@
#endif // CONFIG_EXT_COMP_REFS
#if CONFIG_EXT_SKIP
-#if CONFIG_EXT_COMP_REFS
-static void update_comp_reference_type(AV1_COMMON *cm, const MACROBLOCKD *xd,
- COMP_REFERENCE_TYPE comp_ref_type,
- uint8_t allow_update_cdf) {
- assert(comp_ref_type == UNIDIR_COMP_REFERENCE ||
- comp_ref_type == BIDIR_COMP_REFERENCE);
- (void)cm;
- const int ctx = av1_get_comp_reference_type_context(xd);
- if (allow_update_cdf)
- update_cdf(xd->tile_ctx->comp_ref_type_cdf[ctx], comp_ref_type, 2);
- FRAME_COUNTS *counts = xd->counts;
- if (counts) ++counts->comp_ref_type[ctx][comp_ref_type];
-}
-#endif // CONFIG_EXT_COMP_REFS
-
static void set_ref_frames_for_skip_mode(AV1_COMMON *const cm,
- MACROBLOCKD *const xd,
- MV_REFERENCE_FRAME ref_frame[2],
- uint8_t allow_update_cdf) {
- assert(xd->mi[0]->mbmi.skip_mode);
-
+ MV_REFERENCE_FRAME ref_frame[2]) {
ref_frame[0] = LAST_FRAME + cm->ref_frame_idx_0;
ref_frame[1] = LAST_FRAME + cm->ref_frame_idx_1;
-
- const REFERENCE_MODE mode = COMPOUND_REFERENCE;
- update_block_reference_mode(cm, xd, mode, allow_update_cdf);
-
-#if CONFIG_EXT_COMP_REFS
- const COMP_REFERENCE_TYPE comp_ref_type = BIDIR_COMP_REFERENCE;
- update_comp_reference_type(cm, xd, comp_ref_type, allow_update_cdf);
-#endif // CONFIG_EXT_COMP_REFS
-
-// Update stats for both forward and backward references
-#define UPDATE_REF_BIT(bname, pname, cname, iname) \
- if (allow_update_cdf) \
- update_cdf(av1_get_pred_cdf_##pname(cm, xd), bname, 2); \
- if (counts) \
- ++counts->comp_##cname[av1_get_pred_context_##pname(cm, xd)][iname][bname];
-
- FRAME_COUNTS *counts = xd->counts;
-
- const int bit = (ref_frame[0] == GOLDEN_FRAME || ref_frame[0] == LAST3_FRAME);
- UPDATE_REF_BIT(bit, comp_ref_p, ref, 0)
- if (!bit) {
- UPDATE_REF_BIT(ref_frame[0] == LAST_FRAME, comp_ref_p1, ref, 1)
- } else {
- UPDATE_REF_BIT(ref_frame[0] == GOLDEN_FRAME, comp_ref_p2, ref, 2)
- }
-
- const int bit_bwd = ref_frame[1] == ALTREF_FRAME;
- UPDATE_REF_BIT(bit_bwd, comp_bwdref_p, bwdref, 0)
- if (!bit_bwd) {
- UPDATE_REF_BIT(ref_frame[1] == ALTREF2_FRAME, comp_bwdref_p1, bwdref, 1)
- }
}
#endif // CONFIG_EXT_SKIP
@@ -1374,7 +1300,7 @@
} else {
#if CONFIG_EXT_SKIP
if (xd->mi[0]->mbmi.skip_mode) {
- set_ref_frames_for_skip_mode(cm, xd, ref_frame, r->allow_update_cdf);
+ set_ref_frames_for_skip_mode(cm, ref_frame);
return;
}
#endif // CONFIG_EXT_SKIP
@@ -1793,21 +1719,6 @@
}
}
-#if CONFIG_EXT_SKIP
-static void update_block_intra_inter(AV1_COMMON *const cm,
- MACROBLOCKD *const xd, int segment_id,
- const int is_inter,
- uint8_t allow_update_cdf) {
- if (!segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
- const int ctx = av1_get_intra_inter_context(xd);
- FRAME_CONTEXT *ec_ctx = xd->tile_ctx;
- if (allow_update_cdf) update_cdf(ec_ctx->intra_inter_cdf[ctx], is_inter, 2);
- FRAME_COUNTS *counts = xd->counts;
- if (counts) ++counts->intra_inter[ctx][is_inter];
- }
-}
-#endif // CONFIG_EXT_SKIP
-
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,
@@ -1837,19 +1748,34 @@
}
}
-#define FRAME_TO_CHECK 1
+#define FRAME_TO_CHECK 11
+#if CONFIG_EXT_SKIP
if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) {
printf(
"=== DECODER ===: "
"Frame=%d, (mi_row,mi_col)=(%d,%d), skip_mode=%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, mode_ctx=%d, "
- "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d\n",
+ "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
cm->current_video_frame, mi_row, mi_col, mbmi->skip_mode, mbmi->mode,
mbmi->sb_type, 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, mode_ctx, newmv_ctx, zeromv_ctx,
- refmv_ctx);
+ refmv_ctx, mbmi->tx_size);
+#else
+ if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) {
+ 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, mode_ctx=%d, "
+ "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
+ cm->current_video_frame, mi_row, mi_col, mbmi->mode, mbmi->sb_type,
+ 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, mode_ctx, newmv_ctx, zeromv_ctx, refmv_ctx,
+ mbmi->tx_size);
+#endif // CONFIG_EXT_SKIP
}
}
#endif // DEC_MISMATCH_DEBUG
@@ -1885,6 +1811,10 @@
read_ref_frames(cm, xd, r, mbmi->segment_id, mbmi->ref_frame);
is_compound = has_second_ref(mbmi);
+#if CONFIG_EXT_SKIP
+// TODO(zoeliu): To work with JNT_COMP
+#endif // CONFIG_EXT_SKIP
+
#if CONFIG_JNT_COMP
if (is_compound) {
const int comp_index_ctx = get_comp_index_context(cm, xd);
@@ -1969,6 +1899,11 @@
#endif
{
mbmi->mode = GLOBALMV;
+#if CONFIG_EXT_SKIP
+ } else if (mbmi->skip_mode) {
+ assert(is_compound);
+ mbmi->mode = NEAREST_NEARESTMV;
+#endif // CONFIG_EXT_SKIP
} else {
if (is_compound)
mbmi->mode = read_inter_compound_mode(cm, xd, r, mode_ctx);
@@ -2098,13 +2033,36 @@
}
}
- int mv_corrupted_flag =
- !assign_mv(cm, xd, mbmi->mode, mbmi->ref_frame, 0, mbmi->mv, ref_mv,
- nearestmv, nearmv, mi_row, mi_col, is_compound, allow_hp, r);
- aom_merge_corrupted_flag(&xd->corrupted, mv_corrupted_flag);
+#if CONFIG_EXT_SKIP
+ if (mbmi->skip_mode) {
+#define USE_MV_SELECTION 0
+#if USE_MV_SELECTION
+ // NOTE: For skip mode, above reference selection has been set as compound,
+ // in order to obtain the two nearest mvs, but after the following mv setup,
+ // skip mode may choose either single reference or compound reference mode.
+ av1_setup_skip_mode_mvs(cm, xd, mbmi, mi_row, mi_col, nearestmv, NULL,
+ NULL);
+#else // !USE_MV_SELECTION
+ assert(mbmi->mode == NEAREST_NEARESTMV);
+ mbmi->mv[0].as_int = nearestmv[0].as_int;
+ mbmi->mv[1].as_int = nearestmv[1].as_int;
+#endif // USE_MV_SELECTION
+#undef USE_MV_SELECTION
+ } else {
+#endif // CONFIG_EXT_SKIP
+ int mv_corrupted_flag =
+ !assign_mv(cm, xd, mbmi->mode, mbmi->ref_frame, 0, mbmi->mv, ref_mv,
+ nearestmv, nearmv, mi_row, mi_col, is_compound, allow_hp, r);
+ aom_merge_corrupted_flag(&xd->corrupted, mv_corrupted_flag);
+#if CONFIG_EXT_SKIP
+ }
+#endif // CONFIG_EXT_SKIP
mbmi->use_wedge_interintra = 0;
if (cm->reference_mode != COMPOUND_REFERENCE &&
+#if CONFIG_EXT_SKIP
+ !mbmi->skip_mode &&
+#endif // CONFIG_EXT_SKIP
cm->allow_interintra_compound && is_interintra_allowed(mbmi)) {
const int bsize_group = size_group_lookup[bsize];
const int interintra =
@@ -2146,7 +2104,11 @@
}
mbmi->motion_mode = SIMPLE_TRANSLATION;
- if (mbmi->sb_type >= BLOCK_8X8 && !has_second_ref(mbmi))
+ if (mbmi->sb_type >= BLOCK_8X8 &&
+#if CONFIG_EXT_SKIP
+ !mbmi->skip_mode &&
+#endif // CONFIG_EXT_SKIP
+ !has_second_ref(mbmi))
#if CONFIG_EXT_WARPED_MOTION
mbmi->num_proj_ref[0] =
findSamples(cm, xd, mi_row, mi_col, pts, pts_inref, pts_mv, pts_wm);
@@ -2267,85 +2229,62 @@
mbmi->skip_mode);
#endif // 0
- if (mbmi->skip_mode) {
+ if (mbmi->skip_mode)
mbmi->skip = 1;
-#if CONFIG_Q_SEGMENTATION
- mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
-#endif
-
- if (cm->delta_q_present_flag) {
- xd->current_qindex = xd->prev_qindex;
-#if CONFIG_EXT_DELTA_Q
- if (cm->delta_lf_present_flag) {
-#if CONFIG_LOOPFILTER_LEVEL
- if (cm->delta_lf_multi)
- for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id)
- mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
- xd->prev_delta_lf[lf_id];
- else
-#endif // CONFIG_LOOPFILTER_LEVEL
- mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
- xd->prev_delta_lf_from_base;
- }
-#endif // CONFIG_EXT_DELTA_Q
- }
-
- update_block_intra_inter(cm, xd, mbmi->segment_id, inter_block,
- r->allow_update_cdf);
- } else {
+ else
#endif // CONFIG_EXT_SKIP
mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r);
-#if CONFIG_Q_SEGMENTATION
- mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
-#endif
- if (cm->delta_q_present_flag) {
- xd->current_qindex =
- xd->prev_qindex +
- read_delta_qindex(cm, xd, r, mbmi, mi_col, mi_row) * cm->delta_q_res;
- /* Normative: Clamp to [1,MAXQ] to not interfere with lossless mode */
- xd->current_qindex = clamp(xd->current_qindex, 1, MAXQ);
- xd->prev_qindex = xd->current_qindex;
+#if CONFIG_Q_SEGMENTATION
+ mbmi->q_segment_id = read_q_segment_id(cm, xd, mi_row, mi_col, r);
+#endif // CONFIG_Q_SEGMENTATION
+
+ if (cm->delta_q_present_flag) {
+ xd->current_qindex =
+ xd->prev_qindex +
+ read_delta_qindex(cm, xd, r, mbmi, mi_col, mi_row) * cm->delta_q_res;
+ /* Normative: Clamp to [1,MAXQ] to not interfere with lossless mode */
+ xd->current_qindex = clamp(xd->current_qindex, 1, MAXQ);
+ xd->prev_qindex = xd->current_qindex;
#if CONFIG_EXT_DELTA_Q
- if (cm->delta_lf_present_flag) {
+ if (cm->delta_lf_present_flag) {
#if CONFIG_LOOPFILTER_LEVEL
- if (cm->delta_lf_multi) {
- for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
- const int tmp_lvl =
- xd->prev_delta_lf[lf_id] +
- read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
- cm->delta_lf_res;
- mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
- clamp(tmp_lvl, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
- xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
- }
- } else {
+ if (cm->delta_lf_multi) {
+ for (int lf_id = 0; lf_id < FRAME_LF_COUNT; ++lf_id) {
const int tmp_lvl =
- xd->prev_delta_lf_from_base +
- read_delta_lflevel(cm, xd, r, -1, mbmi, mi_col, mi_row) *
+ xd->prev_delta_lf[lf_id] +
+ read_delta_lflevel(cm, xd, r, lf_id, mbmi, mi_col, mi_row) *
cm->delta_lf_res;
- mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
+ mbmi->curr_delta_lf[lf_id] = xd->curr_delta_lf[lf_id] =
clamp(tmp_lvl, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
- xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
+ xd->prev_delta_lf[lf_id] = xd->curr_delta_lf[lf_id];
}
-#else
- const int current_delta_lf_from_base =
+ } else {
+ const int tmp_lvl =
xd->prev_delta_lf_from_base +
- read_delta_lflevel(cm, xd, r, mbmi, mi_col, mi_row) *
+ read_delta_lflevel(cm, xd, r, -1, mbmi, mi_col, mi_row) *
cm->delta_lf_res;
mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
- clamp(current_delta_lf_from_base, -MAX_LOOP_FILTER,
- MAX_LOOP_FILTER);
+ clamp(tmp_lvl, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
-#endif // CONFIG_LOOPFILTER_LEVEL
}
-#endif // CONFIG_EXT_DELTA_Q
+#else
+ const int current_delta_lf_from_base =
+ xd->prev_delta_lf_from_base +
+ read_delta_lflevel(cm, xd, r, mbmi, mi_col, mi_row) *
+ cm->delta_lf_res;
+ mbmi->current_delta_lf_from_base = xd->current_delta_lf_from_base =
+ clamp(current_delta_lf_from_base, -MAX_LOOP_FILTER, MAX_LOOP_FILTER);
+ xd->prev_delta_lf_from_base = xd->current_delta_lf_from_base;
+#endif // CONFIG_LOOPFILTER_LEVEL
}
-
- inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
-#if CONFIG_EXT_SKIP
+#endif // CONFIG_EXT_DELTA_Q
}
+
+#if CONFIG_EXT_SKIP
+ if (!mbmi->skip_mode)
#endif // CONFIG_EXT_SKIP
+ inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r);
mbmi->current_q_index = xd->current_qindex;
@@ -2371,22 +2310,16 @@
} else {
mbmi->tx_size = read_tx_size(cm, xd, inter_block, !mbmi->skip, r);
-#if CONFIG_EXT_SKIP
- if (!mbmi->skip_mode) {
-#endif // CONFIG_EXT_SKIP
- if (inter_block) {
- const int width = block_size_wide[bsize] >> tx_size_wide_log2[0];
- const int height = block_size_high[bsize] >> tx_size_high_log2[0];
- int idx, idy;
- for (idy = 0; idy < height; ++idy)
- for (idx = 0; idx < width; ++idx)
- mbmi->inter_tx_size[idy >> 1][idx >> 1] = mbmi->tx_size;
- }
- mbmi->min_tx_size = get_min_tx_size(mbmi->tx_size);
- set_txfm_ctxs(mbmi->tx_size, xd->n8_w, xd->n8_h, mbmi->skip, xd);
-#if CONFIG_EXT_SKIP
+ if (inter_block) {
+ const int width = block_size_wide[bsize] >> tx_size_wide_log2[0];
+ const int height = block_size_high[bsize] >> tx_size_high_log2[0];
+ int idx, idy;
+ for (idy = 0; idy < height; ++idy)
+ for (idx = 0; idx < width; ++idx)
+ mbmi->inter_tx_size[idy >> 1][idx >> 1] = mbmi->tx_size;
}
-#endif // CONFIG_EXT_SKIP
+ mbmi->min_tx_size = get_min_tx_size(mbmi->tx_size);
+ set_txfm_ctxs(mbmi->tx_size, xd->n8_w, xd->n8_h, mbmi->skip, xd);
}
if (inter_block)
@@ -2395,7 +2328,10 @@
read_intra_block_mode_info(cm, mi_row, mi_col, xd, mi, r);
#if !CONFIG_TXK_SEL
- av1_read_tx_type(cm, xd, r);
+#if CONFIG_EXT_SKIP
+ if (!mbmi->skip_mode)
+#endif // CONFIG_EXT_SKIP
+ av1_read_tx_type(cm, xd, r);
#endif // !CONFIG_TXK_SEL
}
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index d8965c3..de693dc 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -282,6 +282,24 @@
}
}
+#if CONFIG_EXT_SKIP
+static int write_skip_mode(const AV1_COMMON *cm, const MACROBLOCKD *xd,
+ int segment_id, const MODE_INFO *mi, aom_writer *w) {
+ if (!cm->skip_mode_flag) return 0;
+ if (segfeature_active(&cm->seg, segment_id, SEG_LVL_SKIP)) {
+ return 0;
+ }
+ const int skip_mode = mi->mbmi.skip_mode;
+ if (!is_comp_ref_allowed(mi->mbmi.sb_type)) {
+ assert(!skip_mode);
+ return 0;
+ }
+ const int ctx = av1_get_skip_mode_context(xd);
+ aom_write_symbol(w, skip_mode, xd->tile_ctx->skip_mode_cdfs[ctx], 2);
+ return skip_mode;
+}
+#endif // CONFIG_EXT_SKIP
+
static void write_is_inter(const AV1_COMMON *cm, const MACROBLOCKD *xd,
int segment_id, aom_writer *w, const int is_inter) {
if (!segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME)) {
@@ -1207,10 +1225,23 @@
}
}
- skip = write_skip(cm, xd, segment_id, mi, w);
+#if CONFIG_EXT_SKIP
+ write_skip_mode(cm, xd, segment_id, mi, w);
+
+ if (mbmi->skip_mode) {
+ skip = mbmi->skip;
+ assert(skip);
+ } else {
+#endif // CONFIG_EXT_SKIP
+ skip = write_skip(cm, xd, segment_id, mi, w);
+#if CONFIG_EXT_SKIP
+ }
+#endif // CONFIG_EXT_SKIP
+
#if CONFIG_Q_SEGMENTATION
write_q_segment_id(cm, skip, mbmi, w, seg, segp, bsize, mi_row, mi_col);
-#endif
+#endif // CONFIG_Q_SEGMENTATION
+
if (cm->delta_q_present_flag) {
int super_block_upper_left = ((mi_row & (cm->mib_size - 1)) == 0) &&
((mi_col & (cm->mib_size - 1)) == 0);
@@ -1252,7 +1283,10 @@
}
}
- write_is_inter(cm, xd, mbmi->segment_id, w, is_inter);
+#if CONFIG_EXT_SKIP
+ if (!mbmi->skip_mode)
+#endif // CONFIG_EXT_SKIP
+ write_is_inter(cm, xd, mbmi->segment_id, w, is_inter);
if (cm->tx_mode == TX_MODE_SELECT && block_signals_txsize(bsize) &&
!(is_inter && skip) && !xd->lossless[segment_id]) {
@@ -1274,6 +1308,10 @@
set_txfm_ctxs(mbmi->tx_size, xd->n8_w, xd->n8_h, skip, xd);
}
+#if CONFIG_EXT_SKIP
+ if (mbmi->skip_mode) return;
+#endif // CONFIG_EXT_SKIP
+
if (!is_inter) {
write_intra_mode(ec_ctx, bsize, mode, w);
if (is_chroma_reference(mi_row, mi_col, bsize, xd->plane[1].subsampling_x,
@@ -1310,7 +1348,6 @@
if (is_compound)
mode_ctx = mbmi_ext->compound_mode_context[mbmi->ref_frame[0]];
else
-
mode_ctx = av1_mode_context_analyzer(mbmi_ext->mode_context,
mbmi->ref_frame, bsize, -1);
@@ -1607,7 +1644,7 @@
xd->mi = cm->mi_grid_visible + (mi_row * cm->mi_stride + mi_col);
m = xd->mi[0];
if (is_inter_block(&m->mbmi)) {
-#define FRAME_TO_CHECK 1
+#define FRAME_TO_CHECK 11
if (cm->current_video_frame == FRAME_TO_CHECK && cm->show_frame == 1) {
const MB_MODE_INFO *const mbmi = &m->mbmi;
const BLOCK_SIZE bsize = mbmi->sb_type;
@@ -1625,11 +1662,15 @@
MACROBLOCK *const x = &cpi->td.mb;
const MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
- const int16_t mode_ctx = av1_mode_context_analyzer(
- mbmi_ext->mode_context, mbmi->ref_frame, bsize, -1);
+ const int16_t mode_ctx =
+ is_comp_ref ? mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]
+ : av1_mode_context_analyzer(mbmi_ext->mode_context,
+ mbmi->ref_frame, bsize, -1);
+
const int16_t newmv_ctx = mode_ctx & NEWMV_CTX_MASK;
int16_t zeromv_ctx = -1;
int16_t refmv_ctx = -1;
+
if (mbmi->mode != NEWMV) {
zeromv_ctx = (mode_ctx >> GLOBALMV_OFFSET) & GLOBALMV_CTX_MASK;
if (mode_ctx & (1 << ALL_ZERO_FLAG_OFFSET)) {
@@ -1643,18 +1684,31 @@
}
}
- int8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+#if CONFIG_EXT_SKIP
+ printf(
+ "=== ENCODER ===: "
+ "Frame=%d, (mi_row,mi_col)=(%d,%d), skip_mode=%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, mode_ctx=%d, "
+ "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%d\n",
+ cm->current_video_frame, mi_row, mi_col, mbmi->skip_mode, 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, mode_ctx, newmv_ctx,
+ zeromv_ctx, refmv_ctx, mbmi->tx_size);
+#else
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, inter_mode_ctx=%d, mode_ctx=%d, "
- "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d\n",
+ "ref[1]=%d, motion_mode=%d, mode_ctx=%d, "
+ "newmv_ctx=%d, zeromv_ctx=%d, refmv_ctx=%d, tx_size=%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, mbmi_ext->mode_context[ref_frame_type], mode_ctx,
- newmv_ctx, zeromv_ctx, refmv_ctx);
+ mbmi->motion_mode, mode_ctx, newmv_ctx, zeromv_ctx, refmv_ctx,
+ mbmi->tx_size);
+#endif // CONFIG_EXT_SKIP
}
}
}
@@ -1750,6 +1804,9 @@
for (plane = 0; plane < AOMMIN(2, num_planes); ++plane) {
const uint8_t palette_size_plane =
mbmi->palette_mode_info.palette_size[plane];
+#if CONFIG_EXT_SKIP
+ assert(!mbmi->skip_mode || !palette_size_plane);
+#endif // CONFIG_EXT_SKIP
if (palette_size_plane > 0) {
#if CONFIG_INTRABC
assert(mbmi->use_intrabc == 0);
@@ -3669,8 +3726,6 @@
aom_wb_write_literal(wb, cpi->common.ans_window_size_log2 - 8, 4);
#endif // CONFIG_ANS && ANS_MAX_SYMBOLS
} else {
- MV_REFERENCE_FRAME ref_frame;
-
aom_wb_write_literal(wb, cpi->refresh_frame_mask, REF_FRAMES);
if (!cpi->refresh_frame_mask) {
@@ -3679,7 +3734,8 @@
cm->is_reference_frame = 0;
}
- for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+ for (MV_REFERENCE_FRAME ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME;
+ ++ref_frame) {
assert(get_ref_frame_map_idx(cpi, ref_frame) != INVALID_IDX);
aom_wb_write_literal(wb, get_ref_frame_map_idx(cpi, ref_frame),
REF_FRAMES_LOG2);
@@ -3750,7 +3806,11 @@
arf_offset = AOMMIN((MAX_GF_INTERVAL - 1), arf_offset + brf_offset);
aom_wb_write_literal(wb, arf_offset, 4);
}
-#endif
+
+#if CONFIG_EXT_SKIP
+ if (cm->is_skip_mode_allowed) aom_wb_write_bit(wb, cm->skip_mode_flag);
+#endif // CONFIG_EXT_SKIP
+#endif // CONFIG_FRAME_MARKER
#if CONFIG_REFERENCE_BUFFER
if (cm->seq_params.frame_id_numbers_present_flag) {
diff --git a/av1/encoder/block.h b/av1/encoder/block.h
index 8c50017..b9fd22c 100644
--- a/av1/encoder/block.h
+++ b/av1/encoder/block.h
@@ -207,6 +207,20 @@
int skip_chroma_rd;
int skip_cost[SKIP_CONTEXTS][2];
+#if CONFIG_EXT_SKIP
+ int skip_mode; // 0: off; 1: on
+ int skip_mode_cost[SKIP_CONTEXTS][2];
+
+ int64_t skip_mode_rdcost; // -1: Not set
+ int skip_mode_rate;
+ int64_t skip_mode_sse;
+ int64_t skip_mode_dist;
+ MV_REFERENCE_FRAME skip_mode_ref_frame[2];
+ int_mv skip_mode_mv[2];
+ int skip_mode_index_candidate;
+ int skip_mode_index;
+#endif // CONFIG_EXT_SKIP
+
#if CONFIG_LV_MAP
LV_MAP_COEFF_COST coeff_costs[TX_SIZES][PLANE_TYPES];
uint16_t cb_offset;
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index a5c59c8..a380330 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1020,12 +1020,25 @@
const int seg_ref_active =
segfeature_active(&cm->seg, mbmi->segment_id, SEG_LVL_REF_FRAME);
- if (!seg_ref_active) {
- const int skip_ctx = av1_get_skip_context(xd);
- td->counts->skip[skip_ctx][mbmi->skip]++;
- if (allow_update_cdf) update_cdf(fc->skip_cdfs[skip_ctx], mbmi->skip, 2);
+#if CONFIG_EXT_SKIP
+ if (cm->skip_mode_flag && !seg_ref_active && is_comp_ref_allowed(bsize)) {
+ const int skip_mode_ctx = av1_get_skip_mode_context(xd);
+ td->counts->skip_mode[skip_mode_ctx][mbmi->skip_mode]++;
+ if (allow_update_cdf)
+ update_cdf(fc->skip_mode_cdfs[skip_mode_ctx], mbmi->skip_mode, 2);
}
+ if (!mbmi->skip_mode) {
+#endif // CONFIG_EXT_SKIP
+ if (!seg_ref_active) {
+ const int skip_ctx = av1_get_skip_context(xd);
+ td->counts->skip[skip_ctx][mbmi->skip]++;
+ if (allow_update_cdf) update_cdf(fc->skip_cdfs[skip_ctx], mbmi->skip, 2);
+ }
+#if CONFIG_EXT_SKIP
+ }
+#endif // CONFIG_EXT_SKIP
+
if (cm->delta_q_present_flag && (bsize != cm->sb_size || !mbmi->skip) &&
super_block_upper_left) {
const int dq = (mbmi->current_q_index - xd->prev_qindex) / cm->delta_q_res;
@@ -1080,10 +1093,24 @@
#endif // CONFIG_LOOPFILTER_LEVEL
#endif
}
+
if (!frame_is_intra_only(cm)) {
- FRAME_COUNTS *const counts = td->counts;
RD_COUNTS *rdc = &td->rd_counts;
+
+#if CONFIG_EXT_SKIP
+ if (mbmi->skip_mode) {
+ if (cm->reference_mode == REFERENCE_MODE_SELECT) {
+ assert(has_second_ref(mbmi));
+ rdc->compound_ref_used_flag = 1;
+ }
+ set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
+ return;
+ }
+#endif // CONFIG_EXT_SKIP
+
+ FRAME_COUNTS *const counts = td->counts;
const int inter_block = is_inter_block(mbmi);
+
if (!seg_ref_active) {
counts->intra_inter[av1_get_intra_inter_context(xd)][inter_block]++;
if (allow_update_cdf)
@@ -4194,6 +4221,41 @@
av1_setup_motion_field(cm);
#endif // CONFIG_MFMV
+#if CONFIG_EXT_SKIP
+ av1_setup_skip_mode_allowed(cm);
+ cm->skip_mode_flag = cm->is_skip_mode_allowed;
+ if (cm->skip_mode_flag) {
+ if (cm->reference_mode == SINGLE_REFERENCE) {
+ cm->skip_mode_flag = 0;
+ } else {
+ static const int flag_list[TOTAL_REFS_PER_FRAME] = { 0,
+ AOM_LAST_FLAG,
+ AOM_LAST2_FLAG,
+ AOM_LAST3_FLAG,
+ AOM_GOLD_FLAG,
+ AOM_BWD_FLAG,
+ AOM_ALT2_FLAG,
+ AOM_ALT_FLAG };
+ const int ref_frame[2] = { cm->ref_frame_idx_0 + LAST_FRAME,
+ cm->ref_frame_idx_1 + LAST_FRAME };
+ if (!(cpi->ref_frame_flags & flag_list[ref_frame[0]]) ||
+ !(cpi->ref_frame_flags & flag_list[ref_frame[1]]))
+ cm->skip_mode_flag = 0;
+ }
+ }
+#if 0
+ printf(
+ "\nENCODER: Frame=%d, frame_offset=%d, show_frame=%d, "
+ "show_existing_frame=%d, is_skip_mode_allowed=%d, "
+ "ref_frame_idx=(%d,%d), frame_reference_mode=%d, "
+ "tpl_frame_ref0_idx=%d, skip_mode_flag=%d\n",
+ cm->current_video_frame, cm->frame_offset, cm->show_frame,
+ cm->show_existing_frame, cm->is_skip_mode_allowed, cm->ref_frame_idx_0,
+ cm->ref_frame_idx_1, cm->reference_mode, cm->tpl_frame_ref0_idx,
+ cm->skip_mode_flag);
+#endif // 0
+#endif // CONFIG_EXT_SKIP
+
#if CONFIG_FRAME_MARKER
cpi->all_one_sided_refs = refs_are_one_sided(cm);
#endif // CONFIG_FRAME_MARKER
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 44c48d2..33605d6 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -5273,16 +5273,31 @@
return;
}
}
+#if CONFIG_FRAME_MARKER
printf(
- "\nFrame=%5d, encode_update_type[%5d]=%1d, show_existing_frame=%d, "
- "source_alt_ref_active=%d, refresh_alt_ref_frame=%d, rf_level=%d, "
- "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n",
+ "\nFrame=%5d, encode_update_type[%5d]=%1d, frame_offset=%d, "
+ "show_frame=%d, show_existing_frame=%d, source_alt_ref_active=%d, "
+ "refresh_alt_ref_frame=%d, rf_level=%d, "
+ "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n\n",
cm->current_video_frame, cpi->twopass.gf_group.index,
cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
- cm->show_existing_frame, cpi->rc.source_alt_ref_active,
+ cm->frame_offset, cm->show_frame, cm->show_existing_frame,
+ cpi->rc.source_alt_ref_active, cpi->refresh_alt_ref_frame,
+ cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index],
+ recon_buf->y_stride, recon_buf->uv_stride, cm->width, cm->height);
+#else
+ printf(
+ "\nFrame=%5d, encode_update_type[%5d]=%1d, "
+ "show_frame=%d, show_existing_frame=%d, source_alt_ref_active=%d, "
+ "refresh_alt_ref_frame=%d, rf_level=%d, "
+ "y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n\n",
+ cm->current_video_frame, cpi->twopass.gf_group.index,
+ cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index],
+ cm->show_frame, cm->show_existing_frame, cpi->rc.source_alt_ref_active,
cpi->refresh_alt_ref_frame,
cpi->twopass.gf_group.rf_level[cpi->twopass.gf_group.index],
recon_buf->y_stride, recon_buf->uv_stride, cm->width, cm->height);
+#endif // CONFIG_FRAME_MARKER
#if 0
int ref_frame;
printf("get_ref_frame_map_idx: [");
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index d511812..800d7fb 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -93,6 +93,15 @@
NULL);
}
+#if CONFIG_EXT_SKIP
+ if (cm->skip_mode_flag) {
+ for (i = 0; i < SKIP_CONTEXTS; ++i) {
+ av1_cost_tokens_from_cdf(x->skip_mode_cost[i], fc->skip_mode_cdfs[i],
+ NULL);
+ }
+ }
+#endif // CONFIG_EXT_SKIP
+
for (i = 0; i < SKIP_CONTEXTS; ++i) {
av1_cost_tokens_from_cdf(x->skip_cost[i], fc->skip_cdfs[i], NULL);
}
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index db7fa25..2f3ee0d 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -7685,6 +7685,51 @@
return 0;
}
+#if CONFIG_EXT_SKIP
+static int64_t skip_mode_rd(const AV1_COMP *const cpi, MACROBLOCK *const x,
+ BLOCK_SIZE bsize, int mi_row, int mi_col,
+ BUFFER_SET *const orig_dst) {
+ const AV1_COMMON *cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
+
+ InterpFilter assign_filter =
+ (cm->interp_filter == SWITCHABLE) ? EIGHTTAP_REGULAR : cm->interp_filter;
+ set_default_interp_filters(mbmi, assign_filter);
+ av1_build_inter_predictors_sb(cm, xd, mi_row, mi_col, orig_dst, bsize);
+
+ int64_t total_sse = 0;
+
+ for (int plane = 0; plane < MAX_MB_PLANE; ++plane) {
+ const struct macroblock_plane *const p = &x->plane[plane];
+ const struct macroblockd_plane *const pd = &xd->plane[plane];
+ const BLOCK_SIZE plane_bsize = get_plane_block_size(bsize, pd);
+ const int bw = block_size_wide[plane_bsize];
+ const int bh = block_size_high[plane_bsize];
+
+ av1_subtract_plane(x, bsize, plane);
+ int64_t sse = aom_sum_squares_2d_i16(p->src_diff, bw, bw, bh);
+ sse = sse << 4;
+ total_sse += sse;
+ }
+ x->skip_mode_dist = x->skip_mode_sse = total_sse;
+ x->skip_mode_rate = 0;
+ x->skip_mode_rdcost = RDCOST(x->rdmult, x->skip_mode_rate, x->skip_mode_dist);
+
+ // Save the ref frames / motion vectors
+ x->skip_mode_ref_frame[0] = mbmi->ref_frame[0];
+ x->skip_mode_ref_frame[1] = mbmi->ref_frame[1];
+ x->skip_mode_mv[0].as_int = mbmi->mv[0].as_int;
+ x->skip_mode_mv[1].as_int = mbmi->mv[1].as_int;
+
+ // Save the mode index
+ x->skip_mode_index = x->skip_mode_index_candidate;
+
+ restore_dst_buf(xd, *orig_dst);
+ return 0;
+}
+#endif // CONFIG_EXT_SKIP
+
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,
@@ -8634,6 +8679,127 @@
int above_stride, const uint8_t *left,
int left_stride);
+#if CONFIG_EXT_SKIP
+static void estimate_skip_mode_rdcost(
+ const AV1_COMP *const cpi, TileDataEnc *tile_data, MACROBLOCK *const x,
+ BLOCK_SIZE bsize, int mi_row, int mi_col,
+ int_mv frame_mv[MB_MODE_COUNT][TOTAL_REFS_PER_FRAME],
+ struct buf_2d yv12_mb[TOTAL_REFS_PER_FRAME][MAX_MB_PLANE]) {
+ const AV1_COMMON *const cm = &cpi->common;
+ MACROBLOCKD *const xd = &x->e_mbd;
+ MB_MODE_INFO *const mbmi = &xd->mi[0]->mbmi;
+ MB_MODE_INFO_EXT *const mbmi_ext = x->mbmi_ext;
+
+ int *mode_map = tile_data->mode_map[bsize];
+ static const int flag_list[TOTAL_REFS_PER_FRAME] = { 0,
+ AOM_LAST_FLAG,
+ AOM_LAST2_FLAG,
+ AOM_LAST3_FLAG,
+ AOM_GOLD_FLAG,
+ AOM_BWD_FLAG,
+ AOM_ALT2_FLAG,
+ AOM_ALT_FLAG };
+ int i;
+
+ for (int midx = 0; midx < MAX_MODES; ++midx) {
+ const int mode_index = mode_map[midx];
+ x->skip_mode_index_candidate = mode_index;
+
+ const MV_REFERENCE_FRAME ref_frame =
+ av1_mode_order[mode_index].ref_frame[0];
+ const MV_REFERENCE_FRAME second_ref_frame =
+ av1_mode_order[mode_index].ref_frame[1];
+ const int comp_pred = second_ref_frame > INTRA_FRAME;
+
+ if (!comp_pred) continue;
+
+ const PREDICTION_MODE this_mode = av1_mode_order[mode_index].mode;
+
+ if (!(cpi->ref_frame_flags & flag_list[ref_frame])) continue;
+ if (comp_pred && !(cpi->ref_frame_flags & flag_list[second_ref_frame]))
+ continue;
+ // Check whether current refs/mode align with skip_mode
+ if (!(ref_frame == (LAST_FRAME + cm->ref_frame_idx_0) &&
+ second_ref_frame == (LAST_FRAME + cm->ref_frame_idx_1) &&
+ this_mode == NEAREST_NEARESTMV)) {
+ continue;
+ }
+
+ frame_mv[this_mode][ref_frame].as_int =
+ 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 (frame_mv[this_mode][ref_frame].as_int == INVALID_MV ||
+ frame_mv[this_mode][second_ref_frame].as_int == INVALID_MV)
+ break;
+
+ // TODO(zoeliu): To work with JNT_COMP
+
+ mbmi->mode = this_mode;
+ mbmi->uv_mode = UV_DC_PRED;
+ mbmi->ref_frame[0] = ref_frame;
+ mbmi->ref_frame[1] = second_ref_frame;
+
+ // Obtain NEAREST_NEARESTMV.
+ {
+ for (i = 0; i < 2; ++i) {
+ int_mv cur_mv = frame_mv[mbmi->mode][mbmi->ref_frame[i]];
+ clamp_mv2(&cur_mv.as_mv, xd);
+ if (mv_check_bounds(&x->mv_limits, &cur_mv.as_mv)) {
+ x->skip_mode_rdcost = INT64_MAX;
+ break;
+ }
+ mbmi->mv[i].as_int = cur_mv.as_int;
+ }
+ if (x->skip_mode_rdcost == INT64_MAX) break;
+
+ const uint8_t ref_frame_type = av1_ref_frame_type(mbmi->ref_frame);
+ if (mbmi_ext->ref_mv_count[ref_frame_type] > 0) {
+ for (i = 0; i < 2; ++i) {
+ int_mv cur_mv =
+ (i == 0) ? mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv
+ : mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
+ clamp_mv2(&cur_mv.as_mv, xd);
+ if (mv_check_bounds(&x->mv_limits, &cur_mv.as_mv)) {
+ x->skip_mode_rdcost = INT64_MAX;
+ break;
+ }
+ mbmi->mv[i].as_int = cur_mv.as_int;
+ }
+ if (x->skip_mode_rdcost == INT64_MAX) break;
+ }
+ }
+
+#if CONFIG_FILTER_INTRA
+ mbmi->filter_intra_mode_info.use_filter_intra_mode[0] = 0;
+ mbmi->filter_intra_mode_info.use_filter_intra_mode[1] = 0;
+#endif // CONFIG_FILTER_INTRA
+ mbmi->interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
+ mbmi->interinter_compound_type = COMPOUND_AVERAGE;
+ mbmi->motion_mode = SIMPLE_TRANSLATION;
+ mbmi->ref_mv_idx = 0;
+ mbmi->skip_mode = mbmi->skip = 1;
+
+ set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
+ for (i = 0; i < MAX_MB_PLANE; i++) {
+ xd->plane[i].pre[0] = yv12_mb[mbmi->ref_frame[0]][i];
+ xd->plane[i].pre[1] = yv12_mb[mbmi->ref_frame[1]][i];
+ }
+
+ BUFFER_SET orig_dst;
+ for (i = 0; i < MAX_MB_PLANE; i++) {
+ orig_dst.plane[i] = xd->plane[i].dst.buf;
+ orig_dst.stride[i] = xd->plane[i].dst.stride;
+ }
+
+ // Obtain the rdcost for skip_mode.
+ skip_mode_rd(cpi, x, bsize, mi_row, mi_col, &orig_dst);
+ break;
+ }
+}
+#endif // CONFIG_EXT_SKIP
+
void av1_rd_pick_inter_mode_sb(const AV1_COMP *cpi, TileDataEnc *tile_data,
MACROBLOCK *x, int mi_row, int mi_col,
RD_STATS *rd_cost, BLOCK_SIZE bsize,
@@ -8972,6 +9138,11 @@
for (ref_frame = 0; ref_frame < TOTAL_REFS_PER_FRAME; ++ref_frame)
modelled_rd[i][ref_frame] = INT64_MAX;
+#if CONFIG_EXT_SKIP
+ x->skip_mode_rdcost = -1;
+ x->skip_mode_index = -1;
+#endif // CONFIG_EXT_SKIP
+
for (midx = 0; midx < MAX_MODES; ++midx) {
int mode_index;
int mode_excluded = 0;
@@ -8986,6 +9157,9 @@
uint8_t ref_frame_type;
mode_index = mode_map[midx];
+#if CONFIG_EXT_SKIP
+ x->skip_mode_index_candidate = mode_index;
+#endif // CONFIG_EXT_SKIP
this_mode = av1_mode_order[mode_index].mode;
ref_frame = av1_mode_order[mode_index].ref_frame[0];
second_ref_frame = av1_mode_order[mode_index].ref_frame[1];
@@ -9520,7 +9694,6 @@
this_rd = handle_inter_mode(cpi, x, bsize, &rd_stats, &rd_stats_y,
&rd_stats_uv, &disable_skip, frame_mv,
mi_row, mi_col, &args, best_rd);
-
rate2 = rd_stats.rate;
skippable = rd_stats.skip;
distortion2 = rd_stats.dist;
@@ -10024,6 +10197,102 @@
}
}
PALETTE_EXIT:
+
+#if CONFIG_EXT_SKIP
+ // Obtain the rdcost for skip_mode if it has not been calculated yet
+ if (x->skip_mode_rdcost < 0 && cm->skip_mode_flag &&
+ !segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) &&
+ is_comp_ref_allowed(bsize)) {
+ x->skip_mode_rdcost = INT64_MAX;
+ estimate_skip_mode_rdcost(cpi, tile_data, x, bsize, mi_row, mi_col,
+ frame_mv, yv12_mb);
+ }
+
+ // Compare the use of skip_mode with the best intra/inter mode obtained so far
+ best_mbmode.skip_mode = 0;
+ if (x->skip_mode_rdcost >= 0 && x->skip_mode_rdcost < INT64_MAX) {
+ const int skip_mode_ctx = av1_get_skip_mode_context(xd);
+ const int64_t best_intra_inter_mode_cost =
+ RDCOST(x->rdmult, rd_cost->rate + x->skip_mode_cost[skip_mode_ctx][0],
+ rd_cost->dist);
+ const int64_t skip_mode_cost = RDCOST(
+ x->rdmult, x->skip_mode_rate + x->skip_mode_cost[skip_mode_ctx][1],
+ x->skip_mode_dist);
+
+ if (skip_mode_cost <= best_intra_inter_mode_cost) {
+ best_mbmode = *mbmi;
+
+ best_mbmode.skip_mode = best_mbmode.skip = 1;
+ best_mbmode.mode = NEAREST_NEARESTMV;
+ best_mbmode.ref_frame[0] = x->skip_mode_ref_frame[0];
+ best_mbmode.ref_frame[1] = x->skip_mode_ref_frame[1];
+ best_mbmode.mv[0].as_int = x->skip_mode_mv[0].as_int;
+ best_mbmode.mv[1].as_int = x->skip_mode_mv[1].as_int;
+
+ // Set up tx_size related variables for skip-specific loop filtering.
+ best_mbmode.tx_size = block_signals_txsize(bsize)
+ ? tx_size_from_tx_mode(bsize, cm->tx_mode, 1)
+ : max_txsize_rect_lookup[bsize];
+ {
+ const int width = block_size_wide[bsize] >> tx_size_wide_log2[0];
+ const int height = block_size_high[bsize] >> tx_size_high_log2[0];
+ for (int idy = 0; idy < height; ++idy)
+ for (int idx = 0; idx < width; ++idx)
+ best_mbmode.inter_tx_size[idy >> 1][idx >> 1] = best_mbmode.tx_size;
+ }
+ best_mbmode.min_tx_size = get_min_tx_size(best_mbmode.tx_size);
+ set_txfm_ctxs(best_mbmode.tx_size, xd->n8_w, xd->n8_h, best_mbmode.skip,
+ xd);
+
+ // Set up color-related variables for skip mode.
+ best_mbmode.uv_mode = UV_DC_PRED;
+ best_mbmode.palette_mode_info.palette_size[0] = 0;
+ best_mbmode.palette_mode_info.palette_size[1] = 0;
+
+ best_mbmode.interintra_mode = (INTERINTRA_MODE)(II_DC_PRED - 1);
+ best_mbmode.interinter_compound_type = COMPOUND_AVERAGE;
+ best_mbmode.motion_mode = SIMPLE_TRANSLATION;
+ best_mbmode.ref_mv_idx = 0;
+
+#if CONFIG_FILTER_INTRA
+ best_mbmode.filter_intra_mode_info.use_filter_intra_mode[0] = 0;
+ best_mbmode.filter_intra_mode_info.use_filter_intra_mode[1] = 0;
+#endif // CONFIG_FILTER_INTRA
+
+#if 0
+ set_ref_ptrs(cm, xd, best_mbmode.ref_frame[0], best_mbmode.ref_frame[1]);
+ // Select prediction reference frames.
+ for (i = 0; i < MAX_MB_PLANE; i++) {
+ xd->plane[i].pre[0] = yv12_mb[best_mbmode.ref_frame[0]][i];
+ xd->plane[i].pre[1] = yv12_mb[best_mbmode.ref_frame[1]][i];
+ }
+#endif
+
+ best_mode_index = x->skip_mode_index;
+ best_skip2 = 1;
+ // TODO(zoeliu): To further determine the setup for best_mode_skippable
+ // best_mode_skippable = 1;
+ best_mode_skippable = (x->skip_mode_sse == 0);
+
+ set_default_interp_filters(&best_mbmode, cm->interp_filter);
+
+ // Update rd_cost
+ rd_cost->rate = x->skip_mode_rate + x->skip_mode_cost[skip_mode_ctx][1];
+ rd_cost->dist = rd_cost->sse = x->skip_mode_dist;
+ rd_cost->rdcost = RDCOST(x->rdmult, rd_cost->rate, rd_cost->dist);
+ best_rd = rd_cost->rdcost;
+
+ x->skip = 1;
+#if 0
+ // TODO(zoeliu): To understand what ctx->blk_skip[] for?
+ for (i = 0; i < MAX_MB_PLANE; ++i)
+ memset(ctx->blk_skip[i], 0
+ sizeof(uint8_t) * ctx->num_4x4_blk);
+#endif // 0
+ }
+ }
+#endif // CONFIG_EXT_SKIP
+
// The inter modes' rate costs are not calculated precisely in some cases.
// Therefore, sometimes, NEWMV is chosen instead of NEARESTMV, NEARMV, and
// GLOBALMV. Here, checks are added for those cases, and the mode decisions
@@ -10135,6 +10404,9 @@
#if CONFIG_EXT_WARPED_MOTION
&& best_mbmode.motion_mode != WARPED_CAUSAL
#endif // CONFIG_EXT_WARPED_MOTION
+#if CONFIG_EXT_SKIP
+ && !best_mbmode.skip_mode
+#endif // CONFIG_EXT_SKIP
) {
int8_t ref_frame_type = av1_ref_frame_type(best_mbmode.ref_frame);
int16_t mode_ctx = mbmi_ext->mode_context[ref_frame_type];