Adaptive Motion Vector Resolution
Change-Id: Ic3c93a5d2e427ce1ed578389196a265245063821
diff --git a/av1/common/blockd.h b/av1/common/blockd.h
index 007e039..bc3bec3 100644
--- a/av1/common/blockd.h
+++ b/av1/common/blockd.h
@@ -825,7 +825,10 @@
int qindex[MAX_SEGMENTS];
int lossless[MAX_SEGMENTS];
int corrupted;
-
+#if CONFIG_AMVR
+ int cur_frame_mv_precision_level;
+// same with that in AV1_COMMON
+#endif
struct aom_internal_error_info *error_info;
#if CONFIG_GLOBAL_MOTION
WarpedMotionParams *global_motion;
@@ -1621,10 +1624,16 @@
#endif
const MODE_INFO *mi) {
const MB_MODE_INFO *mbmi = &mi->mbmi;
+#if CONFIG_AMVR
+ if (xd->cur_frame_mv_precision_level == 0) {
+#endif
#if CONFIG_GLOBAL_MOTION
- const TransformationType gm_type = gm_params[mbmi->ref_frame[0]].wmtype;
- if (is_global_mv_block(mi, block, gm_type)) return SIMPLE_TRANSLATION;
+ const TransformationType gm_type = gm_params[mbmi->ref_frame[0]].wmtype;
+ if (is_global_mv_block(mi, block, gm_type)) return SIMPLE_TRANSLATION;
#endif // CONFIG_GLOBAL_MOTION
+#if CONFIG_AMVR
+ }
+#endif
#if CONFIG_EXT_INTER
if (is_motion_variation_allowed_bsize(mbmi->sb_type) &&
is_inter_mode(mbmi->mode) && mbmi->ref_frame[1] != INTRA_FRAME &&
@@ -1639,8 +1648,14 @@
#if CONFIG_WARPED_MOTION
if (!has_second_ref(mbmi) && mbmi->num_proj_ref[0] >= 1 &&
!av1_is_scaled(&(xd->block_refs[0]->sf))) {
+#if CONFIG_AMVR
+ if (xd->cur_frame_mv_precision_level) {
+ return OBMC_CAUSAL;
+ }
+#endif
return WARPED_CAUSAL;
}
+
#endif // CONFIG_WARPED_MOTION
#if CONFIG_MOTION_VAR
#if CONFIG_NCOBMC_ADAPT_WEIGHT
@@ -1689,7 +1704,8 @@
// Returns sub-sampled dimensions of the given block.
// The output values for 'rows_within_bounds' and 'cols_within_bounds' will
-// differ from 'height' and 'width' when part of the block is outside the right
+// differ from 'height' and 'width' when part of the block is outside the
+// right
// and/or bottom image boundary.
static INLINE void av1_get_block_dimensions(BLOCK_SIZE bsize, int plane,
const MACROBLOCKD *xd, int *width,
diff --git a/av1/common/entropymv.c b/av1/common/entropymv.c
index 4737915..32e6c91 100644
--- a/av1/common/entropymv.c
+++ b/av1/common/entropymv.c
@@ -169,7 +169,7 @@
if (c == MV_CLASS_0) {
comp_counts->class0[d] += incr;
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
if (precision > MV_SUBPEL_NONE)
#endif
comp_counts->class0_fp[d][f] += incr;
@@ -178,7 +178,7 @@
int i;
int b = c + CLASS0_BITS - 1; // number of bits
for (i = 0; i < b; ++i) comp_counts->bits[i][((d >> i) & 1)] += incr;
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
if (precision > MV_SUBPEL_NONE)
#endif
comp_counts->fp[f] += incr;
@@ -222,18 +222,23 @@
for (j = 0; j < MV_OFFSET_BITS; ++j)
comp->bits[j] = av1_mode_mv_merge_probs(pre_comp->bits[j], c->bits[j]);
+#if CONFIG_AMVR
+ if (cm->cur_frame_mv_precision_level == 0) {
+#endif
+ for (j = 0; j < CLASS0_SIZE; ++j)
+ aom_tree_merge_probs(av1_mv_fp_tree, pre_comp->class0_fp[j],
+ c->class0_fp[j], comp->class0_fp[j]);
- for (j = 0; j < CLASS0_SIZE; ++j)
- aom_tree_merge_probs(av1_mv_fp_tree, pre_comp->class0_fp[j],
- c->class0_fp[j], comp->class0_fp[j]);
+ aom_tree_merge_probs(av1_mv_fp_tree, pre_comp->fp, c->fp, comp->fp);
- aom_tree_merge_probs(av1_mv_fp_tree, pre_comp->fp, c->fp, comp->fp);
-
- if (allow_hp) {
- comp->class0_hp =
- av1_mode_mv_merge_probs(pre_comp->class0_hp, c->class0_hp);
- comp->hp = av1_mode_mv_merge_probs(pre_comp->hp, c->hp);
+ if (allow_hp) {
+ comp->class0_hp =
+ av1_mode_mv_merge_probs(pre_comp->class0_hp, c->class0_hp);
+ comp->hp = av1_mode_mv_merge_probs(pre_comp->hp, c->hp);
+ }
+#if CONFIG_AMVR
}
+#endif
}
}
}
diff --git a/av1/common/entropymv.h b/av1/common/entropymv.h
index bea5c67..3f2c152 100644
--- a/av1/common/entropymv.h
+++ b/av1/common/entropymv.h
@@ -133,7 +133,7 @@
} nmv_context_counts;
typedef enum {
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
MV_SUBPEL_NONE = -1,
#endif
MV_SUBPEL_LOW_PRECISION = 0,
diff --git a/av1/common/mv.h b/av1/common/mv.h
index 59b9ad9..96da22e 100644
--- a/av1/common/mv.h
+++ b/av1/common/mv.h
@@ -206,13 +206,43 @@
else
return ROUND_POWER_OF_TWO_SIGNED(coor, WARPEDMODEL_PREC_BITS - 2) * 2;
}
+#if CONFIG_AMVR
+static INLINE void integer_mv_precision(MV *mv) {
+ int mod = (mv->row % 8);
+ if (mod != 0) {
+ mv->row -= mod;
+ if (abs(mod) > 4) {
+ if (mod > 0) {
+ mv->row += 8;
+ } else {
+ mv->row -= 8;
+ }
+ }
+ }
+ mod = (mv->col % 8);
+ if (mod != 0) {
+ mv->col -= mod;
+ if (abs(mod) > 4) {
+ if (mod > 0) {
+ mv->col += 8;
+ } else {
+ mv->col -= 8;
+ }
+ }
+ }
+}
+#endif
// Convert a global motion translation vector (which may have more bits than a
// regular motion vector) into a motion vector
static INLINE int_mv gm_get_motion_vector(const WarpedMotionParams *gm,
int allow_hp, BLOCK_SIZE bsize,
- int mi_col, int mi_row,
- int block_idx) {
+ int mi_col, int mi_row, int block_idx
+#if CONFIG_AMVR
+ ,
+ int is_integer
+#endif
+ ) {
const int unify_bsize = CONFIG_CB4X4;
int_mv res;
const int32_t *mat = gm->wmmat;
@@ -260,6 +290,11 @@
res.as_mv.row = ty;
res.as_mv.col = tx;
+#if CONFIG_AMVR
+ if (is_integer) {
+ integer_mv_precision(&res.as_mv);
+ }
+#endif
return res;
}
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index 9905086..9b0c40a 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -20,7 +20,12 @@
uint8_t *refmv_count,
CANDIDATE_MV *ref_mv_stack,
const int use_hp, int len, int block,
- int col, int weight) {
+ int col, int weight
+#if CONFIG_AMVR
+ ,
+ int is_integer
+#endif
+ ) {
int index = 0, ref;
int newmv_count = 0;
#if CONFIG_CB4X4
@@ -35,7 +40,11 @@
for (ref = 0; ref < 2; ++ref) {
if (candidate->ref_frame[ref] == rf[0]) {
int_mv this_refmv = get_sub_block_mv(candidate_mi, ref, col, block);
+#if CONFIG_AMVR
+ lower_mv_precision(&this_refmv.as_mv, use_hp, is_integer);
+#else
lower_mv_precision(&this_refmv.as_mv, use_hp);
+#endif
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int) break;
@@ -57,8 +66,11 @@
!unify_bsize) {
int alt_block = 3 - block;
this_refmv = get_sub_block_mv(candidate_mi, ref, col, alt_block);
+#if CONFIG_AMVR
+ lower_mv_precision(&this_refmv.as_mv, use_hp, is_integer);
+#else
lower_mv_precision(&this_refmv.as_mv, use_hp);
-
+#endif
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv.as_int) break;
@@ -85,7 +97,12 @@
for (ref = 0; ref < 2; ++ref) {
this_refmv[ref] = get_sub_block_mv(candidate_mi, ref, col, block);
+
+#if CONFIG_AMVR
+ lower_mv_precision(&this_refmv[ref].as_mv, use_hp, is_integer);
+#else
lower_mv_precision(&this_refmv[ref].as_mv, use_hp);
+#endif
}
for (index = 0; index < *refmv_count; ++index)
@@ -120,9 +137,13 @@
this_refmv[0] = get_sub_block_mv(candidate_mi, 0, col, alt_block);
this_refmv[1] = get_sub_block_mv(candidate_mi, 1, col, alt_block);
- for (ref = 0; ref < 2; ++ref)
+ for (ref = 0; ref < 2; ++ref) {
+#if CONFIG_AMVR
+ lower_mv_precision(&this_refmv[ref].as_mv, use_hp, is_integer);
+#else
lower_mv_precision(&this_refmv[ref].as_mv, use_hp);
-
+#endif
+ }
for (index = 0; index < *refmv_count; ++index)
if (ref_mv_stack[index].this_mv.as_int == this_refmv[0].as_int &&
ref_mv_stack[index].comp_mv.as_int == this_refmv[1].as_int)
@@ -202,9 +223,16 @@
*processed_rows = inc - row_offset - 1;
}
+#if CONFIG_AMVR
+ newmv_count += add_ref_mv_candidate(
+ candidate_mi, candidate, rf, refmv_count, ref_mv_stack,
+ cm->allow_high_precision_mv, len, block, col_offset + i, weight,
+ cm->cur_frame_mv_precision_level);
+#else
newmv_count += add_ref_mv_candidate(
candidate_mi, candidate, rf, refmv_count, ref_mv_stack,
cm->allow_high_precision_mv, len, block, col_offset + i, weight);
+#endif
i += len;
}
@@ -256,9 +284,16 @@
*processed_cols = inc - col_offset - 1;
}
+#if CONFIG_AMVR
+ newmv_count += add_ref_mv_candidate(
+ candidate_mi, candidate, rf, refmv_count, ref_mv_stack,
+ cm->allow_high_precision_mv, len, block, col_offset, weight,
+ cm->cur_frame_mv_precision_level);
+#else
newmv_count += add_ref_mv_candidate(
candidate_mi, candidate, rf, refmv_count, ref_mv_stack,
cm->allow_high_precision_mv, len, block, col_offset, weight);
+#endif
i += len;
}
@@ -284,9 +319,16 @@
const MB_MODE_INFO *const candidate = &candidate_mi->mbmi;
const int len = mi_size_wide[BLOCK_8X8];
+#if CONFIG_AMVR
+ newmv_count += add_ref_mv_candidate(
+ candidate_mi, candidate, rf, refmv_count, ref_mv_stack,
+ cm->allow_high_precision_mv, len, block, mi_pos.col, 2,
+ cm->cur_frame_mv_precision_level);
+#else
newmv_count += add_ref_mv_candidate(
candidate_mi, candidate, rf, refmv_count, ref_mv_stack,
cm->allow_high_precision_mv, len, block, mi_pos.col, 2);
+#endif
} // Analyze a single 8x8 block motion information.
return newmv_count;
@@ -473,8 +515,12 @@
for (ref = 0; ref < 2; ++ref) {
if (prev_frame_mvs->ref_frame[ref] == ref_frame) {
int_mv this_refmv = prev_frame_mvs->mv[ref];
+#if CONFIG_AMVR
+ lower_mv_precision(&this_refmv.as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&this_refmv.as_mv, cm->allow_high_precision_mv);
-
+#endif
if (abs(this_refmv.as_mv.row) >= 16 || abs(this_refmv.as_mv.col) >= 16)
mode_context[ref_frame] |= (1 << ZEROMV_OFFSET);
@@ -1057,14 +1103,25 @@
av1_set_ref_frame(rf, ref_frame);
zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[rf[0]],
cm->allow_high_precision_mv, bsize,
- mi_col, mi_row, 0)
+ mi_col, mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
- zeromv[1].as_int = (rf[1] != NONE_FRAME)
- ? gm_get_motion_vector(&cm->global_motion[rf[1]],
- cm->allow_high_precision_mv,
- bsize, mi_col, mi_row, 0)
- .as_int
- : 0;
+ zeromv[1].as_int =
+ (rf[1] != NONE_FRAME)
+ ? gm_get_motion_vector(&cm->global_motion[rf[1]],
+ cm->allow_high_precision_mv, bsize, mi_col,
+ mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
+ .as_int
+ : 0;
} else {
zeromv[0].as_int = zeromv[1].as_int = 0;
}
@@ -1107,11 +1164,20 @@
}
void av1_find_best_ref_mvs(int allow_hp, int_mv *mvlist, int_mv *nearest_mv,
- int_mv *near_mv) {
+ int_mv *near_mv
+#if CONFIG_AMVR
+ ,
+ int is_integer
+#endif
+ ) {
int i;
// Make sure all the candidates are properly clamped etc
for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) {
+#if CONFIG_AMVR
+ lower_mv_precision(&mvlist[i].as_mv, allow_hp, is_integer);
+#else
lower_mv_precision(&mvlist[i].as_mv, allow_hp);
+#endif
}
*nearest_mv = mvlist[0];
*near_mv = mvlist[1];
@@ -1143,7 +1209,12 @@
#if CONFIG_GLOBAL_MOTION
zeromv.as_int = gm_get_motion_vector(&cm->global_motion[rf[0]],
cm->allow_high_precision_mv,
- mi->mbmi.sb_type, mi_col, mi_row, block)
+ mi->mbmi.sb_type, mi_col, mi_row, block
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else
zeromv.as_int = 0;
diff --git a/av1/common/mvref_common.h b/av1/common/mvref_common.h
index e9e4f2b..a9dfd31 100644
--- a/av1/common/mvref_common.h
+++ b/av1/common/mvref_common.h
@@ -231,11 +231,24 @@
tile->mi_col_end - mi_col - 1);
}
-static INLINE void lower_mv_precision(MV *mv, int allow_hp) {
- if (!allow_hp) {
- if (mv->row & 1) mv->row += (mv->row > 0 ? -1 : 1);
- if (mv->col & 1) mv->col += (mv->col > 0 ? -1 : 1);
+static INLINE void lower_mv_precision(MV *mv, int allow_hp
+#if CONFIG_AMVR
+ ,
+ int is_integer
+#endif
+ ) {
+#if CONFIG_AMVR
+ if (is_integer) {
+ integer_mv_precision(mv);
+ } else {
+#endif
+ if (!allow_hp) {
+ if (mv->row & 1) mv->row += (mv->row > 0 ? -1 : 1);
+ if (mv->col & 1) mv->col += (mv->col > 0 ? -1 : 1);
+ }
+#if CONFIG_AMVR
}
+#endif
}
static INLINE uint8_t av1_get_pred_diff_ctx(const int_mv pred_mv,
@@ -396,8 +409,13 @@
// 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
// score to use as ref motion vector
+#if CONFIG_AMVR
+void av1_find_best_ref_mvs(int allow_hp, int_mv *mvlist, int_mv *nearest_mv,
+ int_mv *near_mv, int is_integer);
+#else
void av1_find_best_ref_mvs(int allow_hp, int_mv *mvlist, int_mv *nearest_mv,
int_mv *near_mv);
+#endif
void av1_append_sub8x8_mvs_for_idx(const AV1_COMMON *cm, MACROBLOCKD *xd,
int block, int ref, int mi_row, int mi_col,
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h
index 19d6e1a..1a792fb 100644
--- a/av1/common/onyxc_int.h
+++ b/av1/common/onyxc_int.h
@@ -260,6 +260,11 @@
uint8_t last_intra_only;
int allow_high_precision_mv;
+#if CONFIG_AMVR
+ int seq_mv_precision_level; // 0 the default in AOM, 1 only integer, 2
+ // adaptive
+ int cur_frame_mv_precision_level; // 0 the default in AOM, 1 only integer
+#endif
int allow_screen_content_tools;
#if CONFIG_EXT_INTER
diff --git a/av1/common/reconinter.c b/av1/common/reconinter.c
index a9d7e50..b456f0a 100644
--- a/av1/common/reconinter.c
+++ b/av1/common/reconinter.c
@@ -182,7 +182,11 @@
build_for_obmc,
#endif // CONFIG_MOTION_VAR
&final_warp_params);
- if (do_warp) {
+ if (do_warp
+#if CONFIG_AMVR
+ && xd->cur_frame_mv_precision_level == 0
+#endif
+ ) {
const struct macroblockd_plane *const pd = &xd->plane[plane];
const struct buf_2d *const pre_buf = &pd->pre[ref];
av1_warp_plane(&final_warp_params,
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index f9cb46a..fcad912 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -4562,6 +4562,17 @@
cm->ans_window_size_log2 = aom_rb_read_literal(rb, 4) + 8;
#endif // CONFIG_ANS && ANS_MAX_SYMBOLS
cm->allow_screen_content_tools = aom_rb_read_bit(rb);
+#if CONFIG_AMVR
+ if (cm->allow_screen_content_tools) {
+ if (aom_rb_read_bit(rb)) {
+ cm->seq_mv_precision_level = 2;
+ } else {
+ cm->seq_mv_precision_level = aom_rb_read_bit(rb) ? 0 : 1;
+ }
+ } else {
+ cm->seq_mv_precision_level = 0;
+ }
+#endif
#if CONFIG_TEMPMV_SIGNALING
cm->use_prev_frame_mvs = 0;
#endif
@@ -4661,6 +4672,13 @@
setup_frame_size_with_refs(cm, rb);
#endif
+#if CONFIG_AMVR
+ if (cm->seq_mv_precision_level == 2) {
+ cm->cur_frame_mv_precision_level = aom_rb_read_bit(rb) ? 0 : 1;
+ } else {
+ cm->cur_frame_mv_precision_level = cm->seq_mv_precision_level;
+ }
+#endif
cm->allow_high_precision_mv = aom_rb_read_bit(rb);
cm->interp_filter = read_frame_interp_filter(rb);
#if CONFIG_TEMPMV_SIGNALING
@@ -4831,7 +4849,9 @@
}
}
#endif
-
+#if CONFIG_AMVR
+ xd->cur_frame_mv_precision_level = cm->cur_frame_mv_precision_level;
+#endif
for (i = 0; i < MAX_SEGMENTS; ++i) {
const int qindex = cm->seg.enabled
? av1_get_qindex(&cm->seg, i, cm->base_qindex)
@@ -4974,8 +4994,14 @@
#endif // CONFIG_EXT_INTER && CONFIG_COMPOUND_SINGLEREF
#if !CONFIG_NEW_MULTISYMBOL
- for (i = 0; i < NMV_CONTEXTS; ++i)
- read_mv_probs(&fc->nmvc[i], cm->allow_high_precision_mv, &r);
+#if CONFIG_AMVR
+ if (cm->cur_frame_mv_precision_level == 0) {
+#endif
+ for (i = 0; i < NMV_CONTEXTS; ++i)
+ read_mv_probs(&fc->nmvc[i], cm->allow_high_precision_mv, &r);
+#if CONFIG_AMVR
+ }
+#endif
#endif
#if CONFIG_SUPERTX
if (!xd->lossless[0]) read_supertx_probs(fc, &r);
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c
index 4536ddf..622e075 100644
--- a/av1/decoder/decodemv.c
+++ b/av1/decoder/decodemv.c
@@ -1244,9 +1244,9 @@
}
static int read_mv_component(aom_reader *r, nmv_component *mvcomp,
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
int use_subpel,
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
int usehp) {
int mag, d, fr, hp;
#if CONFIG_NEW_MULTISYMBOL
@@ -1275,9 +1275,9 @@
mag = CLASS0_SIZE << (mv_class + 2);
}
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
if (use_subpel) {
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
// Fractional part
fr = aom_read_symbol(r, class0 ? mvcomp->class0_fp_cdf[d] : mvcomp->fp_cdf,
MV_FP_SIZE, ACCT_STR);
@@ -1292,12 +1292,12 @@
hp = usehp ? aom_read(r, class0 ? mvcomp->class0_hp : mvcomp->hp, ACCT_STR)
: 1;
#endif
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
} else {
fr = 3;
hp = 1;
}
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
// Result
mag += ((d << 3) | (fr << 1) | hp) + 1;
@@ -1314,16 +1314,16 @@
if (mv_joint_vertical(joint_type))
diff.row = read_mv_component(r, &ctx->comps[0],
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
precision > MV_SUBPEL_NONE,
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
precision > MV_SUBPEL_LOW_PRECISION);
if (mv_joint_horizontal(joint_type))
diff.col = read_mv_component(r, &ctx->comps[1],
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
precision > MV_SUBPEL_NONE,
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
precision > MV_SUBPEL_LOW_PRECISION);
av1_inc_mv(&diff, counts, precision);
@@ -1853,7 +1853,11 @@
(void)mi_row;
(void)mi_col;
(void)bsize;
-
+#if CONFIG_AMVR
+ if (cm->cur_frame_mv_precision_level) {
+ allow_hp = MV_SUBPEL_NONE;
+ }
+#endif
switch (mode) {
case NEWMV: {
FRAME_COUNTS *counts = xd->counts;
@@ -1892,12 +1896,22 @@
#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)
+ mi_col, mi_row, block
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
if (is_compound)
mv[1].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[1]],
cm->allow_high_precision_mv, bsize,
- mi_col, mi_row, block)
+ mi_col, mi_row, block
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else
mv[0].as_int = 0;
@@ -2077,11 +2091,21 @@
#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)
+ mi_col, mi_row, block
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
mv[1].as_int = gm_get_motion_vector(&cm->global_motion[ref_frame[1]],
cm->allow_high_precision_mv, bsize,
- mi_col, mi_row, block)
+ mi_col, mi_row, block
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else
mv[0].as_int = 0;
@@ -2284,21 +2308,39 @@
#if CONFIG_GLOBAL_MOTION
zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[rf[0]],
cm->allow_high_precision_mv,
- bsize, mi_col, mi_row, 0)
+ bsize, mi_col, mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
- zeromv[1].as_int = (rf[1] != NONE_FRAME)
- ? gm_get_motion_vector(&cm->global_motion[rf[1]],
- cm->allow_high_precision_mv,
- bsize, mi_col, mi_row, 0)
- .as_int
- : 0;
+ zeromv[1].as_int =
+ (rf[1] != NONE_FRAME)
+ ? gm_get_motion_vector(&cm->global_motion[rf[1]],
+ cm->allow_high_precision_mv, bsize, mi_col,
+ mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
+ .as_int
+ : 0;
#else
zeromv[0].as_int = zeromv[1].as_int = 0;
#endif
for (ref = 0; ref < 2; ++ref) {
if (rf[ref] == NONE_FRAME) continue;
+#if CONFIG_AMVR
+ lower_mv_precision(&ref_mvs[rf[ref]][0].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+ lower_mv_precision(&ref_mvs[rf[ref]][1].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&ref_mvs[rf[ref]][0].as_mv, allow_hp);
lower_mv_precision(&ref_mvs[rf[ref]][1].as_mv, allow_hp);
+#endif
if (ref_mvs[rf[ref]][0].as_int != zeromv[ref].as_int ||
ref_mvs[rf[ref]][1].as_int != zeromv[ref].as_int)
inter_mode_ctx[ref_frame] &= ~(1 << ALL_ZERO_FLAG_OFFSET);
@@ -2364,8 +2406,14 @@
#endif // CONFIG_EXT_INTER
{
for (ref = 0; ref < 1 + is_compound; ++ref) {
+#if CONFIG_AMVR
+ av1_find_best_ref_mvs(allow_hp, ref_mvs[mbmi->ref_frame[ref]],
+ &nearestmv[ref], &nearmv[ref],
+ cm->cur_frame_mv_precision_level);
+#else
av1_find_best_ref_mvs(allow_hp, ref_mvs[mbmi->ref_frame[ref]],
&nearestmv[ref], &nearmv[ref]);
+#endif
}
}
@@ -2395,8 +2443,15 @@
#endif // CONFIG_EXT_INTER
nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
- lower_mv_precision(&nearestmv[0].as_mv, allow_hp);
- lower_mv_precision(&nearestmv[1].as_mv, allow_hp);
+#if CONFIG_AMVR
+ lower_mv_precision(&nearestmv[0].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+ lower_mv_precision(&nearestmv[1].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
+ lower_mv_precision(&nearestmv[0].as_mv, allow_hp);
+ lower_mv_precision(&nearestmv[1].as_mv, allow_hp);
+#endif
#if CONFIG_EXT_INTER
} else if (mbmi->mode == NEAREST_NEWMV
#if CONFIG_COMPOUND_SINGLEREF
@@ -2405,10 +2460,21 @@
#endif // CONFIG_COMPOUND_SINGLEREF
) {
nearestmv[0] = xd->ref_mv_stack[ref_frame_type][0].this_mv;
+
+#if CONFIG_AMVR
+ lower_mv_precision(&nearestmv[0].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&nearestmv[0].as_mv, allow_hp);
+#endif
} else if (mbmi->mode == NEW_NEARESTMV) {
nearestmv[1] = xd->ref_mv_stack[ref_frame_type][0].comp_mv;
+#if CONFIG_AMVR
+ lower_mv_precision(&nearestmv[1].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&nearestmv[1].as_mv, allow_hp);
+#endif
}
#endif // CONFIG_EXT_INTER
}
@@ -2421,12 +2487,22 @@
#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 CONFIG_AMVR
+ lower_mv_precision(&nearmv[0].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
+ lower_mv_precision(&nearmv[0].as_mv, allow_hp);
+#endif
}
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_AMVR
+ lower_mv_precision(&nearmv[1].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
+ lower_mv_precision(&nearmv[1].as_mv, allow_hp);
+#endif
}
#if CONFIG_COMPOUND_SINGLEREF
} else {
@@ -2510,8 +2586,14 @@
if (have_newmv_in_inter_mode(b_mode)) {
mv_ref_list[0].as_int = nearest_sub8x8[ref].as_int;
mv_ref_list[1].as_int = near_sub8x8[ref].as_int;
+#if CONFIG_AMVR
+ av1_find_best_ref_mvs(allow_hp, mv_ref_list, &ref_mv[0][ref],
+ &ref_mv[1][ref],
+ cm->cur_frame_mv_precision_level);
+#else
av1_find_best_ref_mvs(allow_hp, mv_ref_list, &ref_mv[0][ref],
&ref_mv[1][ref]);
+#endif
}
}
#endif // CONFIG_EXT_INTER
@@ -2519,7 +2601,12 @@
for (ref = 0; ref < 1 + is_compound && b_mode != ZEROMV; ++ref) {
ref_mv_s8[ref] = nearest_sub8x8[ref];
+#if CONFIG_AMVR
+ lower_mv_precision(&ref_mv_s8[ref].as_mv, allow_hp,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&ref_mv_s8[ref].as_mv, allow_hp);
+#endif
}
#if CONFIG_EXT_INTER
(void)ref_mv_s8;
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 8910eea..4b72fb2 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -4447,6 +4447,16 @@
aom_wb_write_literal(wb, cpi->common.ans_window_size_log2 - 8, 4);
#endif // CONFIG_ANS && ANS_MAX_SYMBOLS
aom_wb_write_bit(wb, cm->allow_screen_content_tools);
+#if CONFIG_AMVR
+ if (cm->allow_screen_content_tools) {
+ if (cm->seq_mv_precision_level == 2) {
+ aom_wb_write_bit(wb, 1);
+ } else {
+ aom_wb_write_bit(wb, 0);
+ aom_wb_write_bit(wb, cm->seq_mv_precision_level == 0);
+ }
+ }
+#endif
} else {
if (!cm->show_frame) aom_wb_write_bit(wb, cm->intra_only);
if (cm->intra_only) aom_wb_write_bit(wb, cm->allow_screen_content_tools);
@@ -4534,6 +4544,11 @@
write_frame_size_with_refs(cpi, wb);
#endif
+#if CONFIG_AMVR
+ if (cm->seq_mv_precision_level == 2) {
+ aom_wb_write_bit(wb, cm->cur_frame_mv_precision_level == 0);
+ }
+#endif
aom_wb_write_bit(wb, cm->allow_high_precision_mv);
fix_interp_filter(cm, cpi->td.counts);
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index c87916d..b68b662 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -4637,7 +4637,9 @@
int segment_id = get_segment_id(cm, map, cm->sb_size, mi_row, mi_col);
seg_skip = segfeature_active(seg, segment_id, SEG_LVL_SKIP);
}
-
+#if CONFIG_AMVR
+ xd->cur_frame_mv_precision_level = cm->cur_frame_mv_precision_level;
+#endif
#if CONFIG_DELTA_Q
if (cm->delta_q_present_flag) {
// Test mode for delta quantization
diff --git a/av1/encoder/encodemv.c b/av1/encoder/encodemv.c
index 5225e8e..fa14964 100644
--- a/av1/encoder/encodemv.c
+++ b/av1/encoder/encodemv.c
@@ -66,9 +66,9 @@
}
// Fractional bits
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
if (precision > MV_SUBPEL_NONE)
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
{
aom_write_symbol(
w, fr,
@@ -130,9 +130,9 @@
const int b = c + CLASS0_BITS - 1; /* number of bits */
for (i = 0; i < b; ++i) cost += bits_cost[i][((d >> i) & 1)];
}
-#if CONFIG_INTRABC
+#if CONFIG_INTRABC || CONFIG_AMVR
if (precision > MV_SUBPEL_NONE)
-#endif // CONFIG_INTRABC
+#endif // CONFIG_INTRABC || CONFIG_AMVR
{
if (c == MV_CLASS_0) {
cost += class0_fp_cost[d][f];
@@ -166,6 +166,11 @@
nmv_context_counts *const nmv_counts) {
int i;
int nmv_ctx = 0;
+#if CONFIG_AMVR
+ if (cm->cur_frame_mv_precision_level) {
+ return;
+ }
+#endif
for (nmv_ctx = 0; nmv_ctx < NMV_CONTEXTS; ++nmv_ctx) {
nmv_context *const mvc = &cm->fc->nmvc[nmv_ctx];
nmv_context_counts *const counts = &nmv_counts[nmv_ctx];
@@ -185,6 +190,11 @@
nmv_context *mvctx, int usehp) {
const MV diff = { mv->row - ref->row, mv->col - ref->col };
const MV_JOINT_TYPE j = av1_get_mv_joint(&diff);
+#if CONFIG_AMVR
+ if (cpi->common.cur_frame_mv_precision_level) {
+ usehp = MV_SUBPEL_NONE;
+ }
+#endif
aom_write_symbol(w, j, mvctx->joint_cdf, MV_JOINTS);
if (mv_joint_vertical(j))
encode_mv_component(w, diff.row, &mvctx->comps[0], usehp);
@@ -226,7 +236,12 @@
#if 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) {
+ nmv_context_counts *nmv_counts
+#if CONFIG_AMVR
+ ,
+ MvSubpelPrecision precision
+#endif
+ ) {
int i;
PREDICTION_MODE mode = mbmi->mode;
@@ -241,7 +256,11 @@
mbmi_ext->ref_mv_stack[rf_type], i, mbmi->ref_mv_idx);
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
(void)pred_mvs;
+#if CONFIG_AMVR
+ av1_inc_mv(&diff, counts, precision);
+#else
av1_inc_mv(&diff, counts, 1);
+#endif
}
} else if (mode == NEAREST_NEWMV || mode == NEAR_NEWMV) {
const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[1]][0].as_mv;
@@ -252,7 +271,11 @@
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
mbmi_ext->ref_mv_stack[rf_type], 1, mbmi->ref_mv_idx);
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
+#if CONFIG_AMVR
+ av1_inc_mv(&diff, counts, precision);
+#else
av1_inc_mv(&diff, counts, 1);
+#endif
} else if (mode == NEW_NEARESTMV || mode == NEW_NEARMV) {
const MV *ref = &mbmi_ext->ref_mvs[mbmi->ref_frame[0]][0].as_mv;
const MV diff = { mvs[0].as_mv.row - ref->row,
@@ -262,7 +285,11 @@
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];
+#if CONFIG_AMVR
+ av1_inc_mv(&diff, counts, precision);
+#else
av1_inc_mv(&diff, counts, 1);
+#endif
#if CONFIG_COMPOUND_SINGLEREF
} else {
assert( // mode == SR_NEAREST_NEWMV ||
@@ -289,7 +316,12 @@
static void inc_mvs_sub8x8(const MODE_INFO *mi, int block, const int_mv mvs[2],
const MB_MODE_INFO_EXT *mbmi_ext,
- nmv_context_counts *nmv_counts) {
+ nmv_context_counts *nmv_counts
+#if CONFIG_AMVR
+ ,
+ MvSubpelPrecision precision
+#endif
+ ) {
int i;
PREDICTION_MODE mode = mi->bmi[block].as_mode;
const MB_MODE_INFO *mbmi = &mi->mbmi;
@@ -304,7 +336,11 @@
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
mbmi_ext->ref_mv_stack[rf_type], i, mbmi->ref_mv_idx);
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
+#if CONFIG_AMVR
+ av1_inc_mv(&diff, counts, precision);
+#else
av1_inc_mv(&diff, counts, 1);
+#endif
}
} else if (mode == NEAREST_NEWMV || mode == NEAR_NEWMV) {
const MV *ref = &mi->bmi[block].ref_mv[1].as_mv;
@@ -315,7 +351,11 @@
av1_nmv_ctx(mbmi_ext->ref_mv_count[rf_type],
mbmi_ext->ref_mv_stack[rf_type], 1, mbmi->ref_mv_idx);
nmv_context_counts *counts = &nmv_counts[nmv_ctx];
+#if CONFIG_AMVR
+ av1_inc_mv(&diff, counts, precision);
+#else
av1_inc_mv(&diff, counts, 1);
+#endif
} else if (mode == NEW_NEARESTMV || mode == NEW_NEARMV) {
const MV *ref = &mi->bmi[block].ref_mv[0].as_mv;
const MV diff = { mvs[0].as_mv.row - ref->row,
@@ -325,7 +365,11 @@
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];
+#if CONFIG_AMVR
+ av1_inc_mv(&diff, counts, precision);
+#else
av1_inc_mv(&diff, counts, 1);
+#endif
}
}
#else // !CONFIG_EXT_INTER
@@ -358,6 +402,12 @@
#else
const int unify_bsize = 0;
#endif
+#if CONFIG_AMVR
+ MvSubpelPrecision precision = 1;
+ if (xd->cur_frame_mv_precision_level) {
+ precision = MV_SUBPEL_NONE;
+ }
+#endif
if (mbmi->sb_type < BLOCK_8X8 && !unify_bsize) {
const int num_4x4_w = num_4x4_blocks_wide_lookup[mbmi->sb_type];
@@ -370,7 +420,13 @@
#if CONFIG_EXT_INTER
if (have_newmv_in_inter_mode(mi->bmi[i].as_mode))
+
+#if CONFIG_AMVR
+ inc_mvs_sub8x8(mi, i, mi->bmi[i].as_mv, mbmi_ext, td->counts->mv,
+ precision);
+#else
inc_mvs_sub8x8(mi, i, mi->bmi[i].as_mv, mbmi_ext, td->counts->mv);
+#endif
#else
if (mi->bmi[i].as_mode == NEWMV)
inc_mvs(mbmi, mbmi_ext, mi->bmi[i].as_mv, mi->bmi[i].pred_mv,
@@ -384,6 +440,12 @@
#else
if (mbmi->mode == NEWMV)
#endif // CONFIG_EXT_INTER
+
+#if CONFIG_AMVR
+ inc_mvs(mbmi, mbmi_ext, mbmi->mv, mbmi->pred_mv, td->counts->mv,
+ precision);
+#else
inc_mvs(mbmi, mbmi_ext, mbmi->mv, mbmi->pred_mv, td->counts->mv);
+#endif
}
}
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 320a8c2..858c9af 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -254,11 +254,21 @@
}
}
-static void set_high_precision_mv(AV1_COMP *cpi, int allow_high_precision_mv) {
+static void set_high_precision_mv(AV1_COMP *cpi, int allow_high_precision_mv
+#if CONFIG_AMVR
+ ,
+ int cur_frame_mv_precision_level
+#endif
+ ) {
MACROBLOCK *const mb = &cpi->td.mb;
cpi->common.allow_high_precision_mv = allow_high_precision_mv;
+#if CONFIG_AMVR
+ if (cpi->common.allow_high_precision_mv &&
+ cur_frame_mv_precision_level == 0) {
+#else
if (cpi->common.allow_high_precision_mv) {
+#endif
int i;
for (i = 0; i < NMV_CONTEXTS; ++i) {
mb->mv_cost_stack[i] = mb->nmvcost_hp[i];
@@ -998,6 +1008,11 @@
cpi->gld_fb_idx = 1;
cpi->alt_fb_idx = 2;
#endif // CONFIG_EXT_REFS
+#if CONFIG_AMVR
+ cpi->rate_index = 0;
+ cpi->rate_size = 0;
+ cpi->cur_poc = -1;
+#endif
}
static void init_config(struct AV1_COMP *cpi, AV1EncoderConfig *oxcf) {
@@ -2320,7 +2335,11 @@
set_compound_tools(cm);
#endif // CONFIG_EXT_INTER
av1_reset_segment_features(cm);
+#if CONFIG_AMVR
+ set_high_precision_mv(cpi, 0, 0);
+#else
set_high_precision_mv(cpi, 0);
+#endif
set_rc_buffer_sizes(rc, &cpi->oxcf);
@@ -2384,6 +2403,9 @@
#if CONFIG_ANS && ANS_MAX_SYMBOLS
cpi->common.ans_window_size_log2 = cpi->oxcf.ans_window_size_log2;
#endif // CONFIG_ANS && ANS_MAX_SYMBOLS
+#if CONFIG_AMVR
+ cm->seq_mv_precision_level = 2;
+#endif
}
AV1_COMP *av1_create_compressor(AV1EncoderConfig *oxcf,
@@ -3940,7 +3962,12 @@
#endif
if (!frame_is_intra_only(cm)) {
+#if CONFIG_AMVR
+ set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH,
+ cpi->common.cur_frame_mv_precision_level);
+#else
set_high_precision_mv(cpi, (*q) < HIGH_PRECISION_MV_QTHRESH);
+#endif
}
// Configure experimental use of segmentation for enhanced coding of
@@ -5829,6 +5856,123 @@
}
#endif // CONFIG_INTERNAL_STATS
+#if CONFIG_AMVR
+static int is_integer_mv(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *cur_picture,
+ const YV12_BUFFER_CONFIG *last_picture,
+ hash_table *last_hash_table) {
+ aom_clear_system_state();
+ // check use hash ME
+ int k;
+ uint32_t hash_value_1;
+ uint32_t hash_value_2;
+
+ const int block_size = 8;
+ const double threshold_current = 0.8;
+ const double threshold_average = 0.95;
+ const int max_history_size = 32;
+ int T = 0; // total block
+ int C = 0; // match with collocated block
+ int S = 0; // smooth region but not match with collocated block
+ int M = 0; // match with other block
+
+ const int pic_width = cur_picture->y_width;
+ const int pic_height = cur_picture->y_height;
+ for (int i = 0; i + block_size <= pic_height; i += block_size) {
+ for (int j = 0; j + block_size <= pic_width; j += block_size) {
+ const int x_pos = j;
+ const int y_pos = i;
+ int match = 1;
+ T++;
+
+ // check whether collocated block match with current
+ uint8_t *p_cur = cur_picture->y_buffer;
+ uint8_t *p_ref = last_picture->y_buffer;
+ int stride_cur = cur_picture->y_stride;
+ int stride_ref = last_picture->y_stride;
+ p_cur += (y_pos * stride_cur + x_pos);
+ p_ref += (y_pos * stride_ref + x_pos);
+
+ for (int tmpY = 0; tmpY < block_size && match; tmpY++) {
+ for (int tmpX = 0; tmpX < block_size && match; tmpX++) {
+ if (p_cur[tmpX] != p_ref[tmpX]) {
+ match = 0;
+ }
+ }
+ p_cur += stride_cur;
+ p_ref += stride_ref;
+ }
+
+ if (match) {
+ C++;
+ continue;
+ }
+
+ if (av1_hash_is_horizontal_perfect(cur_picture, block_size, x_pos,
+ y_pos) ||
+ av1_hash_is_vertical_perfect(cur_picture, block_size, x_pos, y_pos)) {
+ S++;
+ continue;
+ }
+
+ av1_get_block_hash_value(
+ cur_picture->y_buffer + y_pos * stride_cur + x_pos, stride_cur,
+ block_size, &hash_value_1, &hash_value_2);
+
+ if (av1_has_exact_match(last_hash_table, hash_value_1, hash_value_2)) {
+ M++;
+ }
+ }
+ }
+
+ assert(T > 0);
+ double csm_rate = ((double)(C + S + M)) / ((double)(T));
+ double m_rate = ((double)(M)) / ((double)(T));
+
+ cpi->csm_rate_array[cpi->rate_index] = csm_rate;
+ cpi->m_rate_array[cpi->rate_index] = m_rate;
+
+ cpi->rate_index = (cpi->rate_index + 1) % max_history_size;
+ cpi->rate_size++;
+ cpi->rate_size = AOMMIN(cpi->rate_size, max_history_size);
+
+ if (csm_rate < threshold_current) {
+ return 0;
+ }
+
+ if (C == T) {
+ return 1;
+ }
+
+ double csm_average = 0.0;
+ double m_average = 0.0;
+
+ for (k = 0; k < cpi->rate_size; k++) {
+ csm_average += cpi->csm_rate_array[k];
+ m_average += cpi->m_rate_array[k];
+ }
+ csm_average /= cpi->rate_size;
+ m_average /= cpi->rate_size;
+
+ if (csm_average < threshold_average) {
+ return 0;
+ }
+
+ if (M > (T - C - S) / 3) {
+ return 1;
+ }
+
+ if (csm_rate > 0.99 && m_rate > 0.01) {
+ return 1;
+ }
+
+ if (csm_average + m_average > 1.01) {
+ return 1;
+ }
+
+ return 0;
+}
+#endif
+
int av1_get_compressed_data(AV1_COMP *cpi, unsigned int *frame_flags,
size_t *size, uint8_t *dest, int64_t *time_stamp,
int64_t *time_end, int flush) {
@@ -5859,7 +6003,11 @@
aom_usec_timer_start(&cmptimer);
+#if CONFIG_AMVR
+ set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV, 0);
+#else
set_high_precision_mv(cpi, ALTREF_HIGH_PRECISION_MV);
+#endif
// Is multi-arf enabled.
// Note that at the moment multi_arf is only configured for 2 pass VBR
@@ -6161,6 +6309,22 @@
cpi->common.current_frame_id = -1;
}
#endif
+#if CONFIG_AMVR
+ cpi->cur_poc++;
+ if (oxcf->pass != 1 && cpi->common.allow_screen_content_tools) {
+ if (cpi->common.seq_mv_precision_level == 2) {
+ struct lookahead_entry *previous_entry =
+ cpi->lookahead->buf + cpi->previsous_index;
+ cpi->common.cur_frame_mv_precision_level = is_integer_mv(
+ cpi, cpi->source, &previous_entry->img, cpi->previsou_hash_table);
+ } else {
+ cpi->common.cur_frame_mv_precision_level =
+ cpi->common.seq_mv_precision_level;
+ }
+ } else {
+ cpi->common.cur_frame_mv_precision_level = 0;
+ }
+#endif
#if CONFIG_XIPHRC
if (oxcf->pass == 1) {
@@ -6250,6 +6414,23 @@
aom_free(is_block_same[k][j]);
}
}
+#if CONFIG_AMVR
+ cpi->previsou_hash_table = &cm->cur_frame->hash_table;
+ {
+ int l;
+ for (l = -MAX_PRE_FRAMES; l < cpi->lookahead->max_sz; l++) {
+ if ((cpi->lookahead->buf + l) == source) {
+ cpi->previsous_index = l;
+ break;
+ }
+ }
+
+ if (l == cpi->lookahead->max_sz) {
+ aom_internal_error(&cm->error, AOM_CODEC_MEM_ERROR,
+ "Failed to find last frame original buffer");
+ }
+ }
+#endif
}
#endif
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 9fc1f2d..df681fb 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -409,6 +409,15 @@
// For a still frame, this flag is set to 1 to skip partition search.
int partition_search_skippable_frame;
+#if CONFIG_AMVR
+ double csm_rate_array[32];
+ double m_rate_array[32];
+ int rate_size;
+ int rate_index;
+ hash_table *previsou_hash_table;
+ int previsous_index;
+ int cur_poc; // DebugInfo
+#endif
int scaled_ref_idx[TOTAL_REFS_PER_FRAME];
#if CONFIG_EXT_REFS
diff --git a/av1/encoder/mbgraph.c b/av1/encoder/mbgraph.c
index 3f5daeb..700da56 100644
--- a/av1/encoder/mbgraph.c
+++ b/av1/encoder/mbgraph.c
@@ -47,9 +47,16 @@
av1_hex_search(x, &ref_full, step_param, x->errorperbit, 0,
cond_cost_list(cpi, cost_list), &v_fn_ptr, 0, ref_mv);
- // Try sub-pixel MC
- // if (bestsme > error_thresh && bestsme < INT_MAX)
+// Try sub-pixel MC
+// if (bestsme > error_thresh && bestsme < INT_MAX)
+#if CONFIG_AMVR
+ if (cpi->common.cur_frame_mv_precision_level == 1) {
+ x->best_mv.as_mv.row *= 8;
+ x->best_mv.as_mv.col *= 8;
+ } else {
+#else
{
+#endif
int distortion;
unsigned int sse;
cpi->find_fractional_mv_step(
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index 02ac6ef..8573568 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -3275,9 +3275,13 @@
bestmv->row = maxr;
bestmv->col = maxc;
besterr = 0;
- // In the sub-pel motion search, if hp is not used, then the last bit of mv
- // has to be 0.
+// In the sub-pel motion search, if hp is not used, then the last bit of mv
+// has to be 0.
+#if CONFIG_AMVR
+ lower_mv_precision(bestmv, allow_hp, 0);
+#else
lower_mv_precision(bestmv, allow_hp);
+#endif
return besterr;
}
// Return the minimum MV.
@@ -3301,8 +3305,12 @@
bestmv->row = minr;
bestmv->col = minc;
besterr = 0;
- // In the sub-pel motion search, if hp is not used, then the last bit of mv
- // has to be 0.
+// In the sub-pel motion search, if hp is not used, then the last bit of mv
+// has to be 0.
+#if CONFIG_AMVR
+ lower_mv_precision(bestmv, allow_hp, 0);
+#else
lower_mv_precision(bestmv, allow_hp);
+#endif
return besterr;
}
diff --git a/av1/encoder/rd.c b/av1/encoder/rd.c
index dc2e7c8..8a6ce0b 100644
--- a/av1/encoder/rd.c
+++ b/av1/encoder/rd.c
@@ -607,11 +607,25 @@
set_block_thresholds(cm, rd);
for (nmv_ctx = 0; nmv_ctx < NMV_CONTEXTS; ++nmv_ctx) {
+#if CONFIG_AMVR
+ if (cm->cur_frame_mv_precision_level) {
+ av1_build_nmv_cost_table(x->nmv_vec_cost[nmv_ctx], x->nmvcost[nmv_ctx],
+ &cm->fc->nmvc[nmv_ctx], MV_SUBPEL_NONE);
+ } else {
+ av1_build_nmv_cost_table(
+ x->nmv_vec_cost[nmv_ctx],
+ cm->allow_high_precision_mv ? x->nmvcost_hp[nmv_ctx]
+ : x->nmvcost[nmv_ctx],
+ &cm->fc->nmvc[nmv_ctx], cm->allow_high_precision_mv);
+ }
+
+#else
av1_build_nmv_cost_table(
x->nmv_vec_cost[nmv_ctx],
cm->allow_high_precision_mv ? x->nmvcost_hp[nmv_ctx]
: x->nmvcost[nmv_ctx],
&cm->fc->nmvc[nmv_ctx], cm->allow_high_precision_mv);
+#endif
}
x->mvcost = x->mv_cost_stack[0];
x->nmvjointcost = x->nmv_vec_cost[0];
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index 8fff3b5..6802502 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -6270,7 +6270,12 @@
zeromv[cur_frm].as_int =
gm_get_motion_vector(&cpi->common.global_motion[ref_frames[cur_frm]],
cpi->common.allow_high_precision_mv, bsize,
- mi_col, mi_row, block)
+ mi_col, mi_row, block
+#if CONFIG_AMVR
+ ,
+ cpi->common.cur_frame_mv_precision_level
+#endif
+ )
.as_int;
}
}
@@ -6587,7 +6592,15 @@
x->mv_limits = tmp_mv_limits;
+#if CONFIG_AMVR
+ if (cpi->common.cur_frame_mv_precision_level) {
+ x->best_mv.as_mv.row *= 8;
+ x->best_mv.as_mv.col *= 8;
+ }
+ if (bestsme < INT_MAX && cpi->common.cur_frame_mv_precision_level == 0) {
+#else
if (bestsme < INT_MAX) {
+#endif
int dis; /* TODO: use dis in distortion calculation later. */
unsigned int sse;
bestsme = cpi->find_fractional_mv_step(
@@ -6972,11 +6985,16 @@
candidates, mi_row, mi_col, NULL, NULL,
mbmi_ext->mode_context);
- // Candidate refinement carried out at encoder and decoder
+// Candidate refinement carried out at encoder and decoder
+#if CONFIG_AMVR
+ av1_find_best_ref_mvs(cm->allow_high_precision_mv, candidates,
+ &frame_nearest_mv[ref_frame], &frame_near_mv[ref_frame],
+ cm->cur_frame_mv_precision_level);
+#else
av1_find_best_ref_mvs(cm->allow_high_precision_mv, candidates,
&frame_nearest_mv[ref_frame],
&frame_near_mv[ref_frame]);
-
+#endif
// Further refinement that is encode side only to test the top few candidates
// in full and choose the best as the centre point for subsequent searches.
// The current implementation doesn't support scaling.
@@ -7132,7 +7150,15 @@
x->mv_limits = tmp_mv_limits;
+#if CONFIG_AMVR
+ if (cpi->common.cur_frame_mv_precision_level) {
+ x->best_mv.as_mv.row *= 8;
+ x->best_mv.as_mv.col *= 8;
+ }
+ if (bestsme < INT_MAX && cpi->common.cur_frame_mv_precision_level == 0) {
+#else
if (bestsme < INT_MAX) {
+#endif
int dis; /* TODO: use dis in distortion calculation later. */
#if CONFIG_MOTION_VAR
switch (mbmi->motion_mode) {
@@ -7438,7 +7464,15 @@
x->mv_limits = tmp_mv_limits;
+#if CONFIG_AMVR
+ if (cpi->common.cur_frame_mv_precision_level) {
+ x->best_mv.as_mv.row *= 8;
+ x->best_mv.as_mv.col *= 8;
+ }
+ if (bestsme < INT_MAX && cpi->common.cur_frame_mv_precision_level == 0) {
+#else
if (bestsme < INT_MAX) {
+#endif
int dis; /* TODO: use dis in distortion calculation later. */
unsigned int sse;
bestsme = cpi->find_fractional_mv_step(
@@ -9129,7 +9163,12 @@
{
cur_mv[0] = mbmi_ext->ref_mv_stack[ref_frame_type][0].this_mv;
+#if CONFIG_AMVR
+ lower_mv_precision(&cur_mv[0].as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&cur_mv[0].as_mv, cm->allow_high_precision_mv);
+#endif
clamp_mv2(&cur_mv[0].as_mv, xd);
if (mv_check_bounds(&x->mv_limits, &cur_mv[0].as_mv)) return INT64_MAX;
mbmi->mv[0].as_int = cur_mv[0].as_int;
@@ -9138,7 +9177,12 @@
if (this_mode == NEW_NEARESTMV) {
cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][0].comp_mv;
+#if CONFIG_AMVR
+ lower_mv_precision(&cur_mv[1].as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&cur_mv[1].as_mv, cm->allow_high_precision_mv);
+#endif
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;
@@ -9154,7 +9198,12 @@
this_mode == NEAR_NEARMV) {
cur_mv[0] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].this_mv;
+#if CONFIG_AMVR
+ lower_mv_precision(&cur_mv[0].as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&cur_mv[0].as_mv, cm->allow_high_precision_mv);
+#endif
clamp_mv2(&cur_mv[0].as_mv, xd);
if (mv_check_bounds(&x->mv_limits, &cur_mv[0].as_mv)) return INT64_MAX;
mbmi->mv[0].as_int = cur_mv[0].as_int;
@@ -9172,7 +9221,12 @@
#endif // CONFIG_COMPOUND_SINGLEREF
cur_mv[1] = mbmi_ext->ref_mv_stack[ref_frame_type][ref_mv_idx].comp_mv;
+#if CONFIG_AMVR
+ lower_mv_precision(&cur_mv[1].as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&cur_mv[1].as_mv, cm->allow_high_precision_mv);
+#endif
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;
@@ -10409,7 +10463,12 @@
frame_mv[ZEROMV][ref_frame].as_int =
gm_get_motion_vector(&cm->global_motion[ref_frame],
cm->allow_high_precision_mv, bsize, mi_col, mi_row,
- 0)
+ 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else // CONFIG_GLOBAL_MOTION
frame_mv[ZEROMV][ref_frame].as_int = 0;
@@ -10424,7 +10483,12 @@
frame_mv[ZERO_ZEROMV][ref_frame].as_int =
gm_get_motion_vector(&cm->global_motion[ref_frame],
cm->allow_high_precision_mv, bsize, mi_col, mi_row,
- 0)
+ 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else // CONFIG_GLOBAL_MOTION
frame_mv[ZERO_ZEROMV][ref_frame].as_int = 0;
@@ -10524,7 +10588,12 @@
#if CONFIG_GLOBAL_MOTION
zeromv.as_int = gm_get_motion_vector(&cm->global_motion[ALTREF_FRAME],
cm->allow_high_precision_mv, bsize,
- mi_col, mi_row, 0)
+ mi_col, mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else
zeromv.as_int = 0;
@@ -11908,14 +11977,25 @@
#if CONFIG_GLOBAL_MOTION
zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[refs[0]],
cm->allow_high_precision_mv, bsize,
- mi_col, mi_row, 0)
+ mi_col, mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
- zeromv[1].as_int = comp_pred_mode
- ? gm_get_motion_vector(&cm->global_motion[refs[1]],
- cm->allow_high_precision_mv,
- bsize, mi_col, mi_row, 0)
- .as_int
- : 0;
+ zeromv[1].as_int =
+ comp_pred_mode
+ ? gm_get_motion_vector(&cm->global_motion[refs[1]],
+ cm->allow_high_precision_mv, bsize, mi_col,
+ mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
+ .as_int
+ : 0;
#else
zeromv[0].as_int = 0;
zeromv[1].as_int = 0;
@@ -12040,16 +12120,40 @@
best_mbmode.ref_frame[1] };
zeromv[0].as_int = gm_get_motion_vector(&cm->global_motion[refs[0]],
cm->allow_high_precision_mv,
- bsize, mi_col, mi_row, 0)
+ bsize, mi_col, mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
- zeromv[1].as_int = (refs[1] != NONE_FRAME)
- ? gm_get_motion_vector(&cm->global_motion[refs[1]],
- cm->allow_high_precision_mv,
- bsize, mi_col, mi_row, 0)
- .as_int
- : 0;
+ zeromv[1].as_int =
+ (refs[1] != NONE_FRAME)
+ ?
+#if CONFIG_AMVR
+ gm_get_motion_vector(&cm->global_motion[refs[1]],
+ cm->allow_high_precision_mv, bsize, mi_col,
+ mi_row, 0, cm->cur_frame_mv_precision_level)
+ .as_int
+ : 0;
+#else
+ gm_get_motion_vector(&cm->global_motion[refs[1]],
+ cm->allow_high_precision_mv, bsize, mi_col,
+ mi_row, 0)
+ .as_int
+ : 0;
+#endif
+
+#if CONFIG_AMVR
+ lower_mv_precision(&zeromv[0].as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+ lower_mv_precision(&zeromv[1].as_mv, cm->allow_high_precision_mv,
+ cm->cur_frame_mv_precision_level);
+#else
lower_mv_precision(&zeromv[0].as_mv, cm->allow_high_precision_mv);
lower_mv_precision(&zeromv[1].as_mv, cm->allow_high_precision_mv);
+#endif
+
#else
zeromv[0].as_int = zeromv[1].as_int = 0;
#endif // CONFIG_GLOBAL_MOTION
@@ -12219,8 +12323,12 @@
#if CONFIG_GLOBAL_MOTION
mbmi->mv[0].as_int =
gm_get_motion_vector(&cm->global_motion[mbmi->ref_frame[0]],
- cm->allow_high_precision_mv, bsize, mi_col, mi_row,
- 0)
+ cm->allow_high_precision_mv, bsize, mi_col, mi_row, 0
+#if CONFIG_AMVR
+ ,
+ cm->cur_frame_mv_precision_level
+#endif
+ )
.as_int;
#else // CONFIG_GLOBAL_MOTION
mbmi->mv[0].as_int = 0;
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index 5c1fa32..74732e7 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -291,15 +291,33 @@
x->mv_limits = tmp_mv_limits;
- // Ignore mv costing by sending NULL pointer instead of cost array
- bestsme = cpi->find_fractional_mv_step(
- x, &best_ref_mv1, cpi->common.allow_high_precision_mv, x->errorperbit,
- &cpi->fn_ptr[BLOCK_16X16], 0, mv_sf->subpel_iters_per_step,
- cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL,
-#if CONFIG_EXT_INTER
- NULL, 0, 0,
+// Ignore mv costing by sending NULL pointer instead of cost array
+#if CONFIG_AMVR
+ if (cpi->common.cur_frame_mv_precision_level == 1) {
+ const uint8_t *const src_address = x->plane[0].src.buf;
+ const int src_stride = x->plane[0].src.stride;
+ const uint8_t *const y = xd->plane[0].pre[0].buf;
+ const int y_stride = xd->plane[0].pre[0].stride;
+ const int offset = x->best_mv.as_mv.row * y_stride + x->best_mv.as_mv.col;
+
+ x->best_mv.as_mv.row *= 8;
+ x->best_mv.as_mv.col *= 8;
+
+ bestsme = cpi->fn_ptr[BLOCK_16X16].vf(y + offset, y_stride, src_address,
+ src_stride, &sse);
+ } else {
#endif
- 0, 0, 0);
+ bestsme = cpi->find_fractional_mv_step(
+ x, &best_ref_mv1, cpi->common.allow_high_precision_mv, x->errorperbit,
+ &cpi->fn_ptr[BLOCK_16X16], 0, mv_sf->subpel_iters_per_step,
+ cond_cost_list(cpi, cost_list), NULL, NULL, &distortion, &sse, NULL,
+#if CONFIG_EXT_INTER
+ NULL, 0, 0,
+#endif
+ 0, 0, 0);
+#if CONFIG_AMVR
+ }
+#endif
x->e_mbd.mi[0]->bmi[0].as_mv[0] = x->best_mv;
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index 42d2870..05934e9 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -152,6 +152,7 @@
set(CONFIG_GF_GROUPS 0 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_GLOBAL_MOTION 1 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_HASH_ME 0 CACHE NUMBER "AV1 experiment flag.")
+set(CONFIG_AMVR 0 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_INTERINTRA 1 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_INTER_STATS_ONLY 0 CACHE NUMBER "AV1 experiment flag.")
set(CONFIG_INTRABC 0 CACHE NUMBER "AV1 experiment flag.")
diff --git a/build/cmake/aom_configure.cmake b/build/cmake/aom_configure.cmake
index 148899f..a7d5f63 100644
--- a/build/cmake/aom_configure.cmake
+++ b/build/cmake/aom_configure.cmake
@@ -223,6 +223,10 @@
endif ()
endif ()
+if (CONFIG_AMVR)
+ change_config_and_warn(CONFIG_HASH_ME 1 CONFIG_AMVR)
+endif ()
+
if ("${AOM_TARGET_SYSTEM}" MATCHES "Darwin\|Linux\|Windows")
set(CONFIG_OS_SUPPORT 1)
endif ()
diff --git a/configure b/configure
index c0eae77..1af3e85 100755
--- a/configure
+++ b/configure
@@ -346,6 +346,7 @@
colorspace_headers
mfmv
jnt_comp
+ amvr
"
CONFIG_LIST="
dependency_tracking
@@ -613,6 +614,11 @@
soft_enable accounting
soft_enable inspection
fi
+ # Enable hash_me if amvr is enabled
+ if enabled amvr; then
+ log_echo "amvr requires hash_me"
+ enable_feature hash_me
+ fi
}
process_targets() {