Commit 4b847e19 authored by Zoe Liu's avatar Zoe Liu

Expand skip mode support for all comp frames

All compound predicted frames now have the choice to either turn on
or off the use of the skip mode. The current encoder design only
turns on the use of skip mode when the temporal distances of the two
reference frames to the current frame are only different by 1.

This patch also includes a fix on the calculating of the temporal
distance between the two reference frames to the current frame for
skip mode.

Performance wise, this patch does not have noticeable impact as the
encoder stays with the same choice with the frame-level skip mode
flag.

Change-Id: I34f370940b3b25d2ab429b8721344133ae6288ad
parent 76224b0e
......@@ -2022,7 +2022,7 @@ 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;
if (frame_is_intra_only(cm) || cm->reference_mode == SINGLE_REFERENCE) return;
RefCntBuffer *const frame_bufs = cm->buffer_pool->frame_bufs;
const int cur_frame_offset = cm->frame_offset;
......@@ -2030,7 +2030,7 @@ void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
int ref_idx[2] = { INVALID_IDX, INVALID_IDX };
int ref_buf_idx[2] = { INVALID_IDX, INVALID_IDX };
// Identify the nearest forward and backward references
// 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;
......@@ -2053,30 +2053,15 @@ void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
}
}
// Flag is set when and only when both forward and backward references
// are available and the difference between their temporal distance to
// the current frame is no greater than 1, i.e. they may have the same
// temporal distance to the current frame, or the distances are off by 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];
}
}
// NOTE: Low delay scenario
if (av1_refs_are_one_sided(cm)) {
assert(ref_idx[1] == INVALID_IDX);
assert(ref_idx[0] != INVALID_IDX);
// Identify the second closest forward reference frame.
// == Bi-directional prediction ==
cm->is_skip_mode_allowed = 1;
cm->ref_frame_idx_0 = ref_idx[0];
cm->ref_frame_idx_1 = ref_idx[1];
} else if (ref_idx[0] != INVALID_IDX && ref_idx[1] == INVALID_IDX) {
// == Forward prediction only ==
// Identify the second nearest forward reference.
ref_frame_offset[1] = -1;
cm->is_skip_mode_allowed = 0;
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;
......@@ -2091,14 +2076,9 @@ void av1_setup_skip_mode_allowed(AV1_COMMON *const cm) {
}
}
if (ref_frame_offset[1] >= 0) {
const int cur_to_fwd0 = cur_frame_offset - ref_frame_offset[0];
const int cur_to_fwd1 = cur_frame_offset - ref_frame_offset[1];
assert(cur_to_fwd1 > cur_to_fwd0);
if ((cur_to_fwd1 - cur_to_fwd0) <= 1) {
cm->is_skip_mode_allowed = 1;
cm->ref_frame_idx_0 = AOMMIN(ref_idx[0], ref_idx[1]);
cm->ref_frame_idx_1 = AOMMAX(ref_idx[0], ref_idx[1]);
}
cm->is_skip_mode_allowed = 1;
cm->ref_frame_idx_0 = AOMMIN(ref_idx[0], ref_idx[1]);
cm->ref_frame_idx_1 = AOMMAX(ref_idx[0], ref_idx[1]);
}
}
......
......@@ -420,6 +420,21 @@ static INLINE int av1_refs_are_one_sided(const AV1_COMMON *cm) {
return one_sided_refs;
}
#if CONFIG_EXT_SKIP
static INLINE void get_skip_mode_ref_offsets(const AV1_COMMON *cm,
int ref_offset[2]) {
ref_offset[0] = ref_offset[1] = 0;
if (!cm->is_skip_mode_allowed) return;
const int buf_idx_0 = cm->frame_refs[cm->ref_frame_idx_0].idx;
const int buf_idx_1 = cm->frame_refs[cm->ref_frame_idx_1].idx;
assert(buf_idx_0 != INVALID_IDX && buf_idx_1 != INVALID_IDX);
ref_offset[0] = cm->buffer_pool->frame_bufs[buf_idx_0].cur_frame_offset;
ref_offset[1] = cm->buffer_pool->frame_bufs[buf_idx_1].cur_frame_offset;
}
#endif // CONFIG_EXT_SKIP
void av1_setup_frame_buf_refs(AV1_COMMON *cm);
#if CONFIG_FRAME_SIGN_BIAS
void av1_setup_frame_sign_bias(AV1_COMMON *cm);
......
......@@ -2850,23 +2850,6 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
}
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;
xd->all_one_sided_refs = cm->skip_mode_flag ? av1_refs_are_one_sided(cm) : 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)
......@@ -3060,6 +3043,24 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
cm->tx_mode = read_tx_mode(cm, rb);
cm->reference_mode = read_frame_reference_mode(cm, rb);
if (cm->reference_mode != SINGLE_REFERENCE) setup_compound_reference_mode(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;
xd->all_one_sided_refs =
frame_is_intra_only(cm) ? 0 : av1_refs_are_one_sided(cm);
#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), reference_mode=%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->skip_mode_flag);
#endif // 0
#endif // CONFIG_EXT_SKIP
read_compound_tools(cm, rb);
cm->reduced_tx_set_used = aom_rb_read_bit(rb);
......
......@@ -2198,9 +2198,11 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi,
#if CONFIG_JNT_COMP && SKIP_MODE_WITH_JNT_COMP
if (mbmi->skip_mode) {
const int cur_offset = (int)cm->frame_offset;
const int cur_to_fwd = cur_offset - cm->ref_frame_idx_0;
const int cur_to_bwd = abs(cm->ref_frame_idx_1 - cur_offset);
if (cur_to_fwd != cur_to_bwd && xd->all_one_sided_refs) {
int ref_offset[2];
get_skip_mode_ref_offsets(cm, ref_offset);
const int cur_to_ref0 = cur_offset - ref_offset[0];
const int cur_to_ref1 = abs(cur_offset - ref_offset[1]);
if (cur_to_ref0 != cur_to_ref1 && xd->all_one_sided_refs) {
const int comp_index_ctx = get_comp_index_context(cm, xd);
mbmi->compound_idx = aom_read_symbol(
r, ec_ctx->compound_index_cdf[comp_index_ctx], 2, ACCT_STR);
......@@ -2349,12 +2351,6 @@ static void read_inter_frame_mode_info(AV1Decoder *const pbi,
#if CONFIG_EXT_SKIP
mbmi->skip_mode = read_skip_mode(cm, xd, mbmi->segment_id, r);
#if 0
if (mbmi->skip_mode)
printf("Frame=%d, frame_offset=%d, (mi_row,mi_col)=(%d,%d), skip_mode=%d\n",
cm->current_video_frame, cm->frame_offset, mi_row, mi_col,
mbmi->skip_mode);
#endif // 0
if (mbmi->skip_mode)
mbmi->skip = 1;
......
......@@ -1389,9 +1389,11 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row,
if (mbmi->skip_mode) {
#if CONFIG_JNT_COMP && SKIP_MODE_WITH_JNT_COMP
const int cur_offset = (int)cm->frame_offset;
const int cur_to_fwd = cur_offset - cm->ref_frame_idx_0;
const int cur_to_bwd = abs(cm->ref_frame_idx_1 - cur_offset);
if (cur_to_fwd != cur_to_bwd && xd->all_one_sided_refs) {
int ref_offset[2];
get_skip_mode_ref_offsets(cm, ref_offset);
const int cur_to_ref0 = cur_offset - ref_offset[0];
const int cur_to_ref1 = abs(cur_offset - ref_offset[1]);
if (cur_to_ref0 != cur_to_ref1 && xd->all_one_sided_refs) {
const int comp_index_ctx = get_comp_index_context(cm, xd);
aom_write_symbol(w, mbmi->compound_idx,
ec_ctx->compound_index_cdf[comp_index_ctx], 2);
......@@ -3805,10 +3807,6 @@ static void write_uncompressed_header_frame(AV1_COMP *cpi,
arf_offset = AOMMIN((MAX_GF_INTERVAL - 1), arf_offset + brf_offset);
aom_wb_write_literal(wb, arf_offset, FRAME_OFFSET_BITS);
}
#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
......@@ -3889,6 +3887,11 @@ static void write_uncompressed_header_frame(AV1_COMP *cpi,
if (!use_hybrid_pred) aom_wb_write_bit(wb, use_compound_pred);
#endif // !CONFIG_REF_ADAPT
}
#if CONFIG_EXT_SKIP
if (cm->is_skip_mode_allowed) aom_wb_write_bit(wb, cm->skip_mode_flag);
#endif // CONFIG_EXT_SKIP
write_compound_tools(cm, wb);
aom_wb_write_bit(wb, cm->reduced_tx_set_used);
......@@ -4167,10 +4170,6 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi,
arf_offset = AOMMIN((MAX_GF_INTERVAL - 1), arf_offset + brf_offset);
aom_wb_write_literal(wb, arf_offset, FRAME_OFFSET_BITS);
}
#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
......@@ -4245,6 +4244,15 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi,
if (!use_hybrid_pred) aom_wb_write_bit(wb, use_compound_pred);
#endif // !CONFIG_REF_ADAPT
}
#if CONFIG_EXT_SKIP
#if 0
printf("\n[ENCODER] Frame=%d, is_skip_mode_allowed=%d, skip_mode_flag=%d\n\n",
(int)cm->frame_offset, cm->is_skip_mode_allowed, cm->skip_mode_flag);
#endif // 0
if (cm->is_skip_mode_allowed) aom_wb_write_bit(wb, cm->skip_mode_flag);
#endif // CONFIG_EXT_SKIP
write_compound_tools(cm, wb);
aom_wb_write_bit(wb, cm->reduced_tx_set_used);
......
......@@ -871,9 +871,11 @@ static void update_stats(const AV1_COMMON *const cm, TileDataEnc *tile_data,
}
#if CONFIG_JNT_COMP && SKIP_MODE_WITH_JNT_COMP
const int cur_offset = (int)cm->frame_offset;
const int cur_to_fwd = cur_offset - cm->ref_frame_idx_0;
const int cur_to_bwd = abs(cm->ref_frame_idx_1 - cur_offset);
if (cur_to_fwd != cur_to_bwd && xd->all_one_sided_refs) {
int ref_offset[2];
get_skip_mode_ref_offsets(cm, ref_offset);
const int cur_to_ref0 = cur_offset - ref_offset[0];
const int cur_to_ref1 = abs(cur_offset - ref_offset[1]);
if (cur_to_ref0 != cur_to_ref1 && xd->all_one_sided_refs) {
const int comp_index_ctx = get_comp_index_context(cm, xd);
++counts->compound_index[comp_index_ctx][mbmi->compound_idx];
if (allow_update_cdf)
......@@ -3649,6 +3651,43 @@ static void enforce_max_ref_frames(AV1_COMP *cpi) {
}
#endif // CONFIG_FRAME_MARKER
#if CONFIG_EXT_SKIP
static int check_skip_mode_enabled(AV1_COMP *const cpi) {
AV1_COMMON *const cm = &cpi->common;
av1_setup_skip_mode_allowed(cm);
if (!cm->is_skip_mode_allowed) return 0;
// Turn off skip mode if the temporal distances of the reference pair to the
// current frame are different by more than 1 frame.
const int cur_offset = (int)cm->frame_offset;
int ref_offset[2];
get_skip_mode_ref_offsets(cm, ref_offset);
const int cur_to_ref0 = cur_offset - ref_offset[0];
const int cur_to_ref1 = abs(cur_offset - ref_offset[1]);
if (abs(cur_to_ref0 - cur_to_ref1) > 1) return 0;
// High Latency: Turn off skip mode if all refs are fwd.
if (cpi->all_one_sided_refs && cpi->oxcf.lag_in_frames > 0) return 0;
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]]))
return 0;
return 1;
}
#endif // CONFIG_EXT_SKIP
static void encode_frame_internal(AV1_COMP *cpi) {
ThreadData *const td = &cpi->td;
MACROBLOCK *const x = &td->mb;
......@@ -3991,43 +4030,18 @@ static void encode_frame_internal(AV1_COMP *cpi) {
#endif // CONFIG_FRAME_MARKER
#if CONFIG_EXT_SKIP
av1_setup_skip_mode_allowed(cm);
cm->skip_mode_flag = cm->is_skip_mode_allowed;
if (cm->skip_mode_flag && cpi->all_one_sided_refs &&
cpi->oxcf.lag_in_frames > 0) {
// High latency: Turn off skip mode if all refs are fwd.
cm->skip_mode_flag = 0;
}
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;
}
}
xd->all_one_sided_refs = cm->skip_mode_flag ? cpi->all_one_sided_refs : 0;
cm->skip_mode_flag = check_skip_mode_enabled(cpi);
xd->all_one_sided_refs = cpi->all_one_sided_refs;
#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, lag_in_frames=%d\n",
"ref_frame_idx=(%d,%d), reference_mode=%d, "
"skip_mode_flag=%d, lag_in_frames=%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, cpi->oxcf.lag_in_frames);
cm->ref_frame_idx_1, cm->reference_mode, cm->skip_mode_flag,
cpi->oxcf.lag_in_frames);
#endif // 0
#endif // CONFIG_EXT_SKIP
......@@ -4203,8 +4217,12 @@ void av1_encode_frame(AV1_COMP *cpi) {
}
make_consistent_compound_tools(cm);
#if CONFIG_EXT_SKIP
if (frame_is_intra_only(cm) || cm->reference_mode == SINGLE_REFERENCE ||
rdc->skip_mode_used_flag == 0)
// Re-check on the skip mode status as reference mode may have been changed.
if (frame_is_intra_only(cm) || cm->reference_mode == SINGLE_REFERENCE) {
cm->is_skip_mode_allowed = 0;
cm->skip_mode_flag = 0;
}
if (cm->skip_mode_flag && rdc->skip_mode_used_flag == 0)
cm->skip_mode_flag = 0;
#endif // CONFIG_EXT_SKIP
......
......@@ -10647,9 +10647,11 @@ PALETTE_EXIT:
x->compound_idx = 1; // COMPOUND_AVERAGE
#if SKIP_MODE_WITH_JNT_COMP
const int cur_offset = (int)cm->frame_offset;
const int cur_to_fwd = cur_offset - cm->ref_frame_idx_0;
const int cur_to_bwd = abs(cm->ref_frame_idx_1 - cur_offset);
if (cur_to_fwd != cur_to_bwd && xd->all_one_sided_refs) {
int ref_offset[2];
get_skip_mode_ref_offsets(cm, ref_offset);
const int cur_to_ref0 = cur_offset - ref_offset[0];
const int cur_to_ref1 = abs(cur_offset - ref_offset[0]);
if (cur_to_ref0 != cur_to_ref1 && xd->all_one_sided_refs) {
// Decide on the JNT_COMP mode.
int64_t best_skip_mode_rd = INT64_MAX;
int best_compound_idx = 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment