From eca93642e28102e5e30d6499f9661b89e8fdc27b Mon Sep 17 00:00:00 2001
From: Pengchong Jin <pengchong@google.com>
Date: Wed, 13 Aug 2014 20:07:39 -0700
Subject: [PATCH] Add a speed feature to give the tighter search range

Add a speed feature to give the tighter partition search
range. Before partition search, calculate the histogram
of the partition sizes of the left, above and previous
co-located blocks of the current block. If the variance of
observed partition sizes is small enough, adjust the search
range around the mean partition size, which will be tigher.

The feature is currently turned on at speed 2. Experiments on
sample youtube clips show on average the runtime is reduced
by 3-7%.

For hard stdhd clips:
park_joy_1080p @ 15000kbps:       509251 ms -> 491953 ms (3.3%)
pedestrian_area_1080p @ 2000kbps: 223941 ms -> 214226 ms (4.3%)

The PSNR performance is changed:
derf: -0.112%
yt:   -0.099%
hd:   -0.090%
stdhd:-0.102%

Change-Id: Ie205ec5325bf92ec5676c243e30ba9d0adca10f2
---
 vp9/encoder/vp9_encodeframe.c    | 43 +++++++++++++++++++++++++++++---
 vp9/encoder/vp9_speed_features.c |  2 +-
 vp9/encoder/vp9_speed_features.h |  3 ++-
 3 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c
index b20b662f30..ae6256a7da 100644
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -1724,7 +1724,8 @@ static const BLOCK_SIZE max_partition_size[BLOCK_SIZES] = {
 // function so repeat calls can accumulate a min and max of more than one sb64.
 static void get_sb_partition_size_range(MACROBLOCKD *xd, MODE_INFO **mi_8x8,
                                         BLOCK_SIZE *min_block_size,
-                                        BLOCK_SIZE *max_block_size ) {
+                                        BLOCK_SIZE *max_block_size,
+                                        int bs_hist[BLOCK_SIZES]) {
   int sb_width_in_blocks = MI_BLOCK_SIZE;
   int sb_height_in_blocks  = MI_BLOCK_SIZE;
   int i, j;
@@ -1735,6 +1736,7 @@ static void get_sb_partition_size_range(MACROBLOCKD *xd, MODE_INFO **mi_8x8,
     for (j = 0; j < sb_width_in_blocks; ++j) {
       MODE_INFO * mi = mi_8x8[index+j];
       BLOCK_SIZE sb_type = mi ? mi->mbmi.sb_type : 0;
+      bs_hist[sb_type]++;
       *min_block_size = MIN(*min_block_size, sb_type);
       *max_block_size = MAX(*max_block_size, sb_type);
     }
@@ -1767,6 +1769,9 @@ static void rd_auto_partition_range(VP9_COMP *cpi, const TileInfo *const tile,
   int bh, bw;
   BLOCK_SIZE min_size = BLOCK_4X4;
   BLOCK_SIZE max_size = BLOCK_64X64;
+  int i = 0;
+  int bs_hist[BLOCK_SIZES] = {0};
+
   // Trap case where we do not have a prediction.
   if (left_in_image || above_in_image || cm->frame_type != KEY_FRAME) {
     // Default "min to max" and "max to min"
@@ -1779,22 +1784,51 @@ static void rd_auto_partition_range(VP9_COMP *cpi, const TileInfo *const tile,
     if (cm->frame_type != KEY_FRAME) {
       MODE_INFO **const prev_mi =
           &cm->prev_mi_grid_visible[mi_row * xd->mi_stride + mi_col];
-      get_sb_partition_size_range(xd, prev_mi, &min_size, &max_size);
+      get_sb_partition_size_range(xd, prev_mi, &min_size, &max_size, bs_hist);
     }
     // Find the min and max partition sizes used in the left SB64
     if (left_in_image) {
       MODE_INFO **left_sb64_mi = &mi[-MI_BLOCK_SIZE];
-      get_sb_partition_size_range(xd, left_sb64_mi, &min_size, &max_size);
+      get_sb_partition_size_range(xd, left_sb64_mi, &min_size, &max_size,
+                                  bs_hist);
     }
     // Find the min and max partition sizes used in the above SB64.
     if (above_in_image) {
       MODE_INFO **above_sb64_mi = &mi[-xd->mi_stride * MI_BLOCK_SIZE];
-      get_sb_partition_size_range(xd, above_sb64_mi, &min_size, &max_size);
+      get_sb_partition_size_range(xd, above_sb64_mi, &min_size, &max_size,
+                                  bs_hist);
     }
+
     // adjust observed min and max
     if (cpi->sf.auto_min_max_partition_size == RELAXED_NEIGHBORING_MIN_MAX) {
       min_size = min_partition_size[min_size];
       max_size = max_partition_size[max_size];
+    } else if (cpi->sf.auto_min_max_partition_size ==
+               CONSTRAIN_NEIGHBORING_MIN_MAX) {
+      // adjust the search range based on the histogram of the observed
+      // partition sizes from left, above the previous co-located blocks
+      int sum = 0;
+      int first_moment = 0;
+      int second_moment = 0;
+      int var_unnormalized = 0;
+
+      for (i = 0; i < BLOCK_SIZES; i++) {
+        sum += bs_hist[i];
+        first_moment += bs_hist[i] * i;
+        second_moment += bs_hist[i] * i * i;
+      }
+
+      // if variance is small enough,
+      // adjust the range around its mean size, which gives a tighter range
+      var_unnormalized = second_moment - first_moment * first_moment / sum;
+      if (var_unnormalized <= 4 * sum) {
+        int mean = first_moment / sum;
+        min_size = min_partition_size[mean];
+        max_size = max_partition_size[mean];
+      } else {
+        min_size = min_partition_size[min_size];
+        max_size = max_partition_size[max_size];
+      }
     }
   }
 
@@ -1811,6 +1845,7 @@ static void rd_auto_partition_range(VP9_COMP *cpi, const TileInfo *const tile,
       next_square_size[max_size] < min_size) {
      min_size = next_square_size[max_size];
   }
+
   *min_block_size = min_size;
   *max_block_size = max_size;
 }
diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c
index f2e99cf22a..e0fd2ba22b 100644
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -102,7 +102,7 @@ static void set_good_speed_feature(VP9_COMP *cpi, VP9_COMMON *cm,
                                  FLAG_SKIP_INTRA_LOWVAR;
     sf->disable_filter_search_var_thresh = 100;
     sf->comp_inter_joint_search_thresh = BLOCK_SIZES;
-    sf->auto_min_max_partition_size = RELAXED_NEIGHBORING_MIN_MAX;
+    sf->auto_min_max_partition_size = CONSTRAIN_NEIGHBORING_MIN_MAX;
     sf->use_lastframe_partitioning = LAST_FRAME_PARTITION_LOW_MOTION;
     sf->adjust_partitioning_from_last_frame = 1;
   }
diff --git a/vp9/encoder/vp9_speed_features.h b/vp9/encoder/vp9_speed_features.h
index de731cee1a..300b86822d 100644
--- a/vp9/encoder/vp9_speed_features.h
+++ b/vp9/encoder/vp9_speed_features.h
@@ -63,7 +63,8 @@ typedef enum {
 typedef enum {
   NOT_IN_USE = 0,
   RELAXED_NEIGHBORING_MIN_MAX = 1,
-  STRICT_NEIGHBORING_MIN_MAX = 2
+  CONSTRAIN_NEIGHBORING_MIN_MAX = 2,
+  STRICT_NEIGHBORING_MIN_MAX = 3
 } AUTO_MIN_MAX_MODE;
 
 typedef enum {
-- 
GitLab