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() {