Select full-pel search method based on quantizer

For speed 1 and 2, full pixel motion search method is selected based on
the frame quantizer and resolution. Two new search methods are
introduced, NSTEP_8PT and CLAMPED_DIAMOND. The search is made more
aggressive for high quantizers, and the search window is reduced for
lower resolutions at high quantizers.

          Instruction Count        BD-Rate Loss(%)
cpu-used    Reduction(%)     avg.psnr  ovr.psnr   ssim
   1          3.247           0.0273    0.0206    0.0373
   2          4.111           0.0542    0.0539    0.1566

STATS_CHANGED

Change-Id: I557a944a7c35ccaa34e82a18e86502f7dfe7c103
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 639d914..9bdab9d 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1773,13 +1773,14 @@
 
 // Function pointer to search site config initialization
 // of different search method functions.
-typedef void (*av1_init_search_site_config)(search_site_config *cfg,
-                                            int stride);
+typedef void (*av1_init_search_site_config)(search_site_config *cfg, int stride,
+                                            int level);
 
 av1_init_search_site_config
     av1_init_motion_compensation[NUM_DISTINCT_SEARCH_METHODS] = {
-      av1_init_dsmotion_compensation, av1_init_motion_compensation_nstep,
-      av1_init_motion_compensation_hex, av1_init_motion_compensation_bigdia,
+      av1_init_dsmotion_compensation,     av1_init_motion_compensation_nstep,
+      av1_init_motion_compensation_nstep, av1_init_dsmotion_compensation,
+      av1_init_motion_compensation_hex,   av1_init_motion_compensation_bigdia,
       av1_init_motion_compensation_square
     };
 
@@ -1809,10 +1810,12 @@
 
   // Initialization of search_site_cfg for NUM_DISTINCT_SEARCH_METHODS.
   for (SEARCH_METHODS i = DIAMOND; i < NUM_DISTINCT_SEARCH_METHODS; i++) {
+    const int level = ((i == NSTEP_8PT) || (i == CLAMPED_DIAMOND)) ? 1 : 0;
     av1_init_motion_compensation[i](
-        &mv_search_params->search_site_cfg[SS_CFG_SRC][i], y_stride);
+        &mv_search_params->search_site_cfg[SS_CFG_SRC][i], y_stride, level);
     av1_init_motion_compensation[i](
-        &mv_search_params->search_site_cfg[SS_CFG_LOOKAHEAD][i], y_stride_src);
+        &mv_search_params->search_site_cfg[SS_CFG_LOOKAHEAD][i], y_stride_src,
+        level);
   }
 
   // First pass search site config initialization.
diff --git a/av1/encoder/mcomp.c b/av1/encoder/mcomp.c
index b21e2f0..e5c7c924 100644
--- a/av1/encoder/mcomp.c
+++ b/av1/encoder/mcomp.c
@@ -65,7 +65,9 @@
   //  5. FAST_HEX \approx FAST_DIAMOND
   switch (search_method) {
     case NSTEP: return DIAMOND;
+    case NSTEP_8PT: return DIAMOND;
     case DIAMOND: return BIGDIA;
+    case CLAMPED_DIAMOND: return BIGDIA;
     case BIGDIA: return HEX;
     case SQUARE: return HEX;
     case HEX: return FAST_HEX;
@@ -313,7 +315,10 @@
 #define MAX_PATTERN_CANDIDATES 8  // max number of candidates per scale
 #define PATTERN_CANDIDATES_REF 3  // number of refinement candidates
 
-void av1_init_dsmotion_compensation(search_site_config *cfg, int stride) {
+// Search site initialization for DIAMOND / CLAMPED_DIAMOND search methods.
+// level = 0: DIAMOND, level = 1: CLAMPED_DIAMOND.
+void av1_init_dsmotion_compensation(search_site_config *cfg, int stride,
+                                    int level) {
   int num_search_steps = 0;
   int stage_index = MAX_MVSEARCH_STEPS - 1;
 
@@ -321,7 +326,10 @@
   cfg->site[stage_index][0].offset = 0;
   cfg->stride = stride;
 
-  for (int radius = MAX_FIRST_STEP; radius > 0; radius /= 2) {
+  // Choose the initial step size depending on level.
+  const int first_step = (level > 0) ? (MAX_FIRST_STEP / 4) : MAX_FIRST_STEP;
+
+  for (int radius = first_step; radius > 0;) {
     int num_search_pts = 8;
 
     const FULLPEL_MV search_site_mvs[13] = {
@@ -338,6 +346,8 @@
     }
     cfg->searches_per_step[stage_index] = num_search_pts;
     cfg->radius[stage_index] = radius;
+    // Update the search radius based on level.
+    if (!level || ((stage_index < 9) && level)) radius /= 2;
     --stage_index;
     ++num_search_steps;
   }
@@ -388,16 +398,19 @@
   cfg->num_search_steps = num_search_steps;
 }
 
-// Search site initialization for NSTEP search method.
-void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride) {
+// Search site initialization for NSTEP / NSTEP_8PT search methods.
+// level = 0: NSTEP, level = 1: NSTEP_8PT.
+void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride,
+                                        int level) {
   int num_search_steps = 0;
   int stage_index = 0;
   cfg->stride = stride;
   int radius = 1;
-  for (stage_index = 0; stage_index < 15; ++stage_index) {
+  const int num_stages = (level > 0) ? 16 : 15;
+  for (stage_index = 0; stage_index < num_stages; ++stage_index) {
     int tan_radius = AOMMAX((int)(0.41 * radius), 1);
     int num_search_pts = 12;
-    if (radius <= 5) {
+    if ((radius <= 5) || (level > 0)) {
       tan_radius = radius;
       num_search_pts = 8;
     }
@@ -433,7 +446,9 @@
 
 // Search site initialization for BIGDIA / FAST_BIGDIA / FAST_DIAMOND
 // search methods.
-void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride,
+                                         int level) {
+  (void)level;
   cfg->stride = stride;
   // First scale has 4-closest points, the rest have 8 points in diamond
   // shape at increasing scales
@@ -486,7 +501,9 @@
 }
 
 // Search site initialization for SQUARE search method.
-void av1_init_motion_compensation_square(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_square(search_site_config *cfg, int stride,
+                                         int level) {
+  (void)level;
   cfg->stride = stride;
   // All scales have 8 closest points in square shape.
   static const int square_num_candidates[MAX_PATTERN_SCALES] = {
@@ -538,7 +555,9 @@
 }
 
 // Search site initialization for HEX / FAST_HEX search methods.
-void av1_init_motion_compensation_hex(search_site_config *cfg, int stride) {
+void av1_init_motion_compensation_hex(search_site_config *cfg, int stride,
+                                      int level) {
+  (void)level;
   cfg->stride = stride;
   // First scale has 8-closest points, the rest have 6 points in hex shape
   // at increasing scales.
@@ -1664,7 +1683,9 @@
           bigdia_search(start_mv, ms_params, step_param, 1, cost_list, best_mv);
       break;
     case NSTEP:
+    case NSTEP_8PT:
     case DIAMOND:
+    case CLAMPED_DIAMOND:
       var = full_pixel_diamond(start_mv, ms_params, step_param, cost_list,
                                best_mv, second_best_mv);
       break;
@@ -1672,7 +1693,8 @@
   }
 
   // Should we allow a follow on exhaustive search?
-  if (!run_mesh_search && search_method == NSTEP) {
+  if (!run_mesh_search &&
+      ((search_method == NSTEP) || (search_method == NSTEP_8PT))) {
     int exhaustive_thr = ms_params->force_mesh_thresh;
     exhaustive_thr >>=
         10 - (mi_size_wide_log2[bsize] + mi_size_high_log2[bsize]);
diff --git a/av1/encoder/mcomp.h b/av1/encoder/mcomp.h
index 2519cc8..8905e92 100644
--- a/av1/encoder/mcomp.h
+++ b/av1/encoder/mcomp.h
@@ -135,22 +135,27 @@
   // Search 12-points in the radius/tan_radius grid around center,
   // up to 15 search stages.
   NSTEP = 1,
+  // Search 8-points in the radius grid around center, up to 16 search stages.
+  NSTEP_8PT = 2,
+  // Search 8-points in the radius grid around center, upto 11 search stages
+  // with clamping of search radius.
+  CLAMPED_DIAMOND = 3,
   // Search maximum 8-points in the radius grid around center,
   // up to 11 search stages. First stage consists of 8 search points
   // and the rest with 6 search points each in hex shape.
-  HEX = 2,
+  HEX = 4,
   // Search maximum 8-points in the radius grid around center,
   // up to 11 search stages. First stage consists of 4 search
   // points and the rest with 8 search points each.
-  BIGDIA = 3,
+  BIGDIA = 5,
   // Search 8-points in the square grid around center, up to 11 search stages.
-  SQUARE = 4,
+  SQUARE = 6,
   // HEX search with up to 2 stages.
-  FAST_HEX = 5,
+  FAST_HEX = 7,
   // BIGDIA search with up to 2 stages.
-  FAST_DIAMOND = 6,
+  FAST_DIAMOND = 8,
   // BIGDIA search with up to 3 stages.
-  FAST_BIGDIA = 7,
+  FAST_BIGDIA = 9,
   // Total number of search methods.
   NUM_SEARCH_METHODS,
   // Number of distinct search methods.
@@ -204,19 +209,24 @@
     const search_site_config search_sites[NUM_SEARCH_METHODS],
     int fine_search_interval);
 
-// Sets up configs for fullpixel diamond search method.
-void av1_init_dsmotion_compensation(search_site_config *cfg, int stride);
+// Sets up configs for fullpixel DIAMOND / CLAMPED_DIAMOND search method.
+void av1_init_dsmotion_compensation(search_site_config *cfg, int stride,
+                                    int level);
 // Sets up configs for firstpass motion search.
 void av1_init_motion_fpf(search_site_config *cfg, int stride);
-// Sets up configs for all other types of motion search method.
-void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride);
+// Sets up configs for NSTEP / NSTEP_8PT motion search method.
+void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride,
+                                        int level);
 // Sets up configs for BIGDIA / FAST_DIAMOND / FAST_BIGDIA
 // motion search method.
-void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride,
+                                         int level);
 // Sets up configs for HEX or FAST_HEX motion search method.
-void av1_init_motion_compensation_hex(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_hex(search_site_config *cfg, int stride,
+                                      int level);
 // Sets up configs for SQUARE motion search method.
-void av1_init_motion_compensation_square(search_site_config *cfg, int stride);
+void av1_init_motion_compensation_square(search_site_config *cfg, int stride,
+                                         int level);
 
 // Mv beyond the range do not produce new/different prediction block.
 static INLINE void av1_set_mv_search_method(
@@ -226,14 +236,16 @@
   // Array to inform which all search methods are having
   // same candidates and different in number of search steps.
   static const SEARCH_METHODS search_method_lookup[NUM_SEARCH_METHODS] = {
-    DIAMOND,  // DIAMOND
-    NSTEP,    // NSTEP
-    HEX,      // HEX
-    BIGDIA,   // BIGDIA
-    SQUARE,   // SQUARE
-    HEX,      // FAST_HEX
-    BIGDIA,   // FAST_DIAMOND
-    BIGDIA    // FAST_BIGDIA
+    DIAMOND,          // DIAMOND
+    NSTEP,            // NSTEP
+    NSTEP_8PT,        // NSTEP_8PT
+    CLAMPED_DIAMOND,  // CLAMPED_DIAMOND
+    HEX,              // HEX
+    BIGDIA,           // BIGDIA
+    SQUARE,           // SQUARE
+    HEX,              // FAST_HEX
+    BIGDIA,           // FAST_DIAMOND
+    BIGDIA            // FAST_BIGDIA
   };
 
   ms_params->search_method = search_method;
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 1c17568..c38d240 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -122,6 +122,20 @@
   INTER_REFS_PER_FRAME, INTER_REFS_PER_FRAME - 2, INTER_REFS_PER_FRAME - 3, 0
 };
 
+// Qindex threshold levels used for selecting full-pel motion search.
+// ms_qthresh[i][j][k] indicates the qindex boundary value for 'k'th qindex band
+// for resolution index 'j' for aggressiveness level 'i'.
+// i = 0: conservative, i = 1: aggressive.
+// j = 0: lower than 720p resolution, j = 1: 720p or larger resolution.
+// Currently invoked only for speed 1 and 2.
+static int ms_qindex_thresh[2][2][2] = { { { 170, 50 }, { MAXQ, 200 } },
+                                         { { 170, 40 }, { 200, 40 } } };
+
+// Full-pel search methods for aggressive search based on qindex.
+// Index 0 is for resolutions lower than 720p, index 1 for 720p or larger
+// resolutions. Currently invoked only for speed 1 and 2.
+static SEARCH_METHODS motion_search_method[2] = { CLAMPED_DIAMOND, DIAMOND };
+
 // Intra only frames, golden frames (except alt ref overlays) and
 // alt ref frames tend to be coded at a higher than ambient quality
 static int frame_is_boosted(const AV1_COMP *cpi) {
@@ -433,6 +447,7 @@
 
     // TODO(any, yunqing): move this feature to speed 0.
     sf->tpl_sf.skip_alike_starting_mv = 1;
+    sf->tpl_sf.search_method = NSTEP_8PT;
   }
 
   if (speed >= 2) {
@@ -1425,4 +1440,23 @@
       sf->part_sf.ext_partition_eval_thresh = BLOCK_128X128;
     }
   }
+
+  if (cpi->oxcf.mode == GOOD && ((speed == 1) || (speed == 2))) {
+    if (!is_stat_generation_stage(cpi)) {
+      // Use faster full-pel motion search for high quantizers.
+      // Also use reduced total search range for low resolutions at high
+      // quantizers.
+      const int aggr = (speed == 1) ? 0 : 1;
+      const int qindex_thresh1 = ms_qindex_thresh[aggr][is_720p_or_larger][0];
+      const int qindex_thresh2 = ms_qindex_thresh[aggr][is_720p_or_larger][1];
+      const SEARCH_METHODS search_method =
+          motion_search_method[is_720p_or_larger];
+      if (cm->quant_params.base_qindex > qindex_thresh1) {
+        sf->mv_sf.search_method = search_method;
+        sf->tpl_sf.search_method = search_method;
+      } else if (cm->quant_params.base_qindex > qindex_thresh2) {
+        sf->mv_sf.search_method = NSTEP_8PT;
+      }
+    }
+  }
 }