Move mv precision decision to a separate file

STATS_CHANGED

BUG=aomedia:2534

Change-Id: Ic6a2e2b48c6b85ae870eaf91b0bc39ec210122e9
diff --git a/av1/av1.cmake b/av1/av1.cmake
index b12aca0..ad0e633 100644
--- a/av1/av1.cmake
+++ b/av1/av1.cmake
@@ -176,6 +176,8 @@
             "${AOM_ROOT}/av1/encoder/ml.c"
             "${AOM_ROOT}/av1/encoder/ml.h"
             "${AOM_ROOT}/av1/encoder/model_rd.h"
+            "${AOM_ROOT}/av1/encoder/mv_prec.c"
+            "${AOM_ROOT}/av1/encoder/mv_prec.h"
             "${AOM_ROOT}/av1/encoder/palette.c"
             "${AOM_ROOT}/av1/encoder/palette.h"
             "${AOM_ROOT}/av1/encoder/partition_strategy.h"
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 1948149..47e2704 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -65,6 +65,7 @@
 #include "av1/encoder/firstpass.h"
 #include "av1/encoder/grain_test_vectors.h"
 #include "av1/encoder/hash_motion.h"
+#include "av1/encoder/mv_prec.h"
 #include "av1/encoder/pass2_strategy.h"
 #include "av1/encoder/picklpf.h"
 #include "av1/encoder/pickrst.h"
@@ -87,9 +88,6 @@
 #define AM_SEGMENT_ID_INACTIVE 7
 #define AM_SEGMENT_ID_ACTIVE 0
 
-// Q threshold for high precision mv.
-#define HIGH_PRECISION_MV_QTHRESH 128
-
 // #define OUTPUT_YUV_REC
 #ifdef OUTPUT_YUV_SKINMAP
 FILE *yuv_skinmap_file = NULL;
@@ -453,21 +451,6 @@
   }
 }
 
-static void set_high_precision_mv(AV1_COMP *cpi, int allow_high_precision_mv,
-                                  int cur_frame_force_integer_mv) {
-  MACROBLOCK *const x = &cpi->td.mb;
-  cpi->common.allow_high_precision_mv =
-      allow_high_precision_mv && cur_frame_force_integer_mv == 0;
-  const int copy_hp =
-      cpi->common.allow_high_precision_mv && cur_frame_force_integer_mv == 0;
-  x->nmvcost[0] = &x->nmv_costs[0][MV_MAX];
-  x->nmvcost[1] = &x->nmv_costs[1][MV_MAX];
-  x->nmvcost_hp[0] = &x->nmv_costs_hp[0][MV_MAX];
-  x->nmvcost_hp[1] = &x->nmv_costs_hp[1][MV_MAX];
-  int *(*src)[2] = copy_hp ? &x->nmvcost_hp : &x->nmvcost;
-  x->mv_cost_stack = *src;
-}
-
 static BLOCK_SIZE select_sb_size(const AV1_COMP *const cpi) {
   const AV1_COMMON *const cm = &cpi->common;
 
@@ -2758,7 +2741,7 @@
   }
 
   av1_reset_segment_features(cm);
-  set_high_precision_mv(cpi, 1, 0);
+  av1_set_high_precision_mv(cpi, 1, 0);
 
   set_rc_buffer_sizes(rc, &cpi->oxcf);
 
@@ -3990,16 +3973,6 @@
 }
 #endif  // !CONFIG_REALTIME_ONLY
 
-static int determine_frame_high_precision_mv(const AV1_COMP *cpi, int qindex) {
-  (void)cpi;
-  if (cpi->sf.hl_sf.reduce_high_precision_mv_usage == 2)
-    return 0;
-  else if (cpi->sf.hl_sf.reduce_high_precision_mv_usage == 1)
-    return qindex < HIGH_PRECISION_MV_QTHRESH / 2;
-  else
-    return qindex < HIGH_PRECISION_MV_QTHRESH;
-}
-
 static void set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index,
                                     int *top_index) {
   AV1_COMMON *const cm = &cpi->common;
@@ -4019,13 +3992,6 @@
   *q = av1_rc_pick_q_and_bounds(cpi, &cpi->rc, cm->width, cm->height,
                                 cpi->gf_group.index, bottom_index, top_index);
 
-  if (!frame_is_intra_only(cm)) {
-    const int use_hp = cpi->common.cur_frame_force_integer_mv
-                           ? 0
-                           : determine_frame_high_precision_mv(cpi, *q);
-    set_high_precision_mv(cpi, use_hp, cpi->common.cur_frame_force_integer_mv);
-  }
-
   // Configure experimental use of segmentation for enhanced coding of
   // static regions if indicated.
   // Only allowed in the second pass of a two pass encode, as it requires
@@ -5140,6 +5106,12 @@
 #if CONFIG_COLLECT_COMPONENT_TIMING
     start_timing(cpi, av1_encode_frame_time);
 #endif
+    // Set the motion vector precision based on mv stats from the last coded
+    // frame.
+    if (!frame_is_intra_only(cm)) {
+      av1_pick_and_set_high_precision_mv(cpi, q);
+    }
+
     // transform / motion compensation build reconstruction frame
     av1_encode_frame(cpi);
 #if CONFIG_COLLECT_COMPONENT_TIMING
@@ -5158,8 +5130,10 @@
     if (do_dummy_pack) {
       finalize_encoded_frame(cpi);
       int largest_tile_id = 0;  // Output from bitstream: unused here
-      if (av1_pack_bitstream(cpi, dest, size, &largest_tile_id) != AOM_CODEC_OK)
+      if (av1_pack_bitstream(cpi, dest, size, &largest_tile_id) !=
+          AOM_CODEC_OK) {
         return AOM_CODEC_ERROR;
+      }
 
       rc->projected_frame_size = (int)(*size) << 3;
     }
@@ -6452,7 +6426,7 @@
   struct aom_usec_timer cmptimer;
   aom_usec_timer_start(&cmptimer);
 #endif
-  set_high_precision_mv(cpi, 1, 0);
+  av1_set_high_precision_mv(cpi, 1, 0);
 
   // Normal defaults
   cm->refresh_frame_context = oxcf->frame_parallel_decoding_mode
diff --git a/av1/encoder/mv_prec.c b/av1/encoder/mv_prec.c
new file mode 100644
index 0000000..fb6d478
--- /dev/null
+++ b/av1/encoder/mv_prec.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+#include "av1/encoder/mv_prec.h"
+
+void av1_pick_and_set_high_precision_mv(AV1_COMP *cpi, int qindex) {
+  int use_hp = qindex < HIGH_PRECISION_MV_QTHRESH;
+
+  if (cpi->sf.hl_sf.high_precision_mv_usage == QTR_ONLY) {
+    use_hp = 0;
+  }
+
+  av1_set_high_precision_mv(cpi, use_hp,
+                            cpi->common.cur_frame_force_integer_mv);
+}
diff --git a/av1/encoder/mv_prec.h b/av1/encoder/mv_prec.h
new file mode 100644
index 0000000..eec0016
--- /dev/null
+++ b/av1/encoder/mv_prec.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#ifndef AOM_AV1_ENCODER_MV_PREC_H_
+#define AOM_AV1_ENCODER_MV_PREC_H_
+
+#include "av1/encoder/encoder.h"
+#include "av1/encoder/speed_features.h"
+
+// Q threshold for high precision mv.
+#define HIGH_PRECISION_MV_QTHRESH 128
+
+static AOM_INLINE void av1_set_high_precision_mv(
+    AV1_COMP *cpi, int allow_high_precision_mv,
+    int cur_frame_force_integer_mv) {
+  MACROBLOCK *const x = &cpi->td.mb;
+  cpi->common.allow_high_precision_mv =
+      allow_high_precision_mv && cur_frame_force_integer_mv == 0;
+  const int copy_hp =
+      cpi->common.allow_high_precision_mv && cur_frame_force_integer_mv == 0;
+  x->nmvcost[0] = &x->nmv_costs[0][MV_MAX];
+  x->nmvcost[1] = &x->nmv_costs[1][MV_MAX];
+  x->nmvcost_hp[0] = &x->nmv_costs_hp[0][MV_MAX];
+  x->nmvcost_hp[1] = &x->nmv_costs_hp[1][MV_MAX];
+  int *(*src)[2] = copy_hp ? &x->nmvcost_hp : &x->nmvcost;
+  x->mv_cost_stack = *src;
+}
+
+void av1_pick_and_set_high_precision_mv(AV1_COMP *cpi, int qindex);
+
+#endif  // AOM_AV1_ENCODER_MV_PREC_H_
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 54d29e5..33f073a 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -833,12 +833,12 @@
   // best quality defaults
   hl_sf->frame_parameter_update = 1;
   hl_sf->recode_loop = ALLOW_RECODE;
-  hl_sf->reduce_high_precision_mv_usage = 0;
   hl_sf->disable_overlay_frames = 0;
   // TODO(yunqing): turn it on for speed 0 if there is gain.
   hl_sf->adaptive_overlay_encoding = 1;
   // Recode loop tolerance %.
   hl_sf->recode_tolerance = 25;
+  hl_sf->high_precision_mv_usage = CURRENT_Q;
 }
 
 static AOM_INLINE void init_tpl_sf(TPL_SPEED_FEATURES *tpl_sf) {
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 7a416103..e9b5ffc 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -261,6 +261,12 @@
   ADAPT_PRED
 } UENUM1BYTE(MAX_PART_PRED_MODE);
 
+enum {
+  LAST_MV_DATA,  // Not implemented yet
+  CURRENT_Q,
+  QTR_ONLY,
+} UENUM1BYTE(MV_PREC_LOGIC);
+
 typedef struct HIGH_LEVEL_SPEED_FEATURES {
   // Frame level coding parameter update
   int frame_parameter_update;
@@ -271,11 +277,11 @@
   // recode a frame. It has no meaning if recode is disabled.
   int recode_tolerance;
 
-  // Use reduced 1/8th pel mv usage, in the range 0 - 2, where
-  // 0: maximizes quality and does not reduce mv precision
-  // 1: more aggressive reduced usage of high precision MV
-  // 2: use only quarter pel motion
-  int reduce_high_precision_mv_usage;
+  // Determine how motion vector precision is chosen. The possibilities are:
+  // LAST_MV_DATA: use the mv data from the last coded frame
+  // CURRENT_Q: use the current q as a threshold
+  // QTR_ONLY: use quarter pel precision only.
+  MV_PREC_LOGIC high_precision_mv_usage;
 
   // Whether to disable overlay frames for filtered Altref frames,
   // overiding oxcf->enable_overlay flag set as 1.