Adaptive Motion Vector Resolution

Change-Id: Ic3c93a5d2e427ce1ed578389196a265245063821
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;