shithub: libvpx

Download patch

ref: f27276f44fa3a66c07a2a92a381f31aaf8371add
parent: 8a152a55f79062a9cba249919f1689ddbabbee22
parent: 1d5ca84df600ab610d14c0356b038ad4c395a6fd
author: Jerome Jiang <jianj@google.com>
date: Tue Dec 20 16:46:43 EST 2016

Merge "vp9: Add feature to copy partition from the last frame."

--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -526,6 +526,7 @@
                                      : 1000;
       cpi->vbp_bsize_min = BLOCK_16X16;
     }
+    cpi->vbp_threshold_copy = cpi->vbp_thresholds[0] << 16;
     cpi->vbp_threshold_minmax = 15 + (q >> 3);
   }
 }
@@ -766,6 +767,93 @@
   }
 }
 
+static void copy_prev_partition(VP9_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
+                                int mi_col) {
+  VP9_COMMON *const cm = &cpi->common;
+  BLOCK_SIZE *prev_part = cpi->prev_partition;
+  int start_pos = mi_row * cm->mi_stride + mi_col;
+
+  const int bsl = b_width_log2_lookup[bsize];
+  const int bs = (1 << bsl) / 4;
+  BLOCK_SIZE subsize;
+  PARTITION_TYPE partition;
+  MODE_INFO *mi = NULL;
+
+  if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+  partition = partition_lookup[bsl][prev_part[start_pos]];
+  subsize = get_subsize(bsize, partition);
+  mi = cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col];
+
+  if (subsize < BLOCK_8X8) {
+    mi->sb_type = bsize;
+  } else {
+    switch (partition) {
+      case PARTITION_NONE: mi->sb_type = bsize; break;
+      case PARTITION_HORZ:
+        mi->sb_type = subsize;
+        if (mi_row + bs < cm->mi_rows)
+          cm->mi_grid_visible[(mi_row + bs) * cm->mi_stride + mi_col]->sb_type =
+              subsize;
+        break;
+      case PARTITION_VERT:
+        mi->sb_type = subsize;
+        if (mi_col + bs < cm->mi_cols)
+          cm->mi_grid_visible[mi_row * cm->mi_stride + mi_col + bs]->sb_type =
+              subsize;
+        break;
+      case PARTITION_SPLIT:
+        copy_prev_partition(cpi, subsize, mi_row, mi_col);
+        copy_prev_partition(cpi, subsize, mi_row + bs, mi_col);
+        copy_prev_partition(cpi, subsize, mi_row, mi_col + bs);
+        copy_prev_partition(cpi, subsize, mi_row + bs, mi_col + bs);
+        break;
+      default: assert(0);
+    }
+  }
+}
+
+static void update_prev_partition(VP9_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
+                                  int mi_col) {
+  VP9_COMMON *const cm = &cpi->common;
+  BLOCK_SIZE *prev_part = cpi->prev_partition;
+  int start_pos = mi_row * cm->mi_stride + mi_col;
+  const int bsl = b_width_log2_lookup[bsize];
+  const int bs = (1 << bsl) / 4;
+  BLOCK_SIZE subsize;
+  PARTITION_TYPE partition;
+  const MODE_INFO *mi = NULL;
+
+  if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return;
+
+  mi = cm->mi_grid_visible[start_pos];
+  partition = partition_lookup[bsl][mi->sb_type];
+  subsize = get_subsize(bsize, partition);
+  if (subsize < BLOCK_8X8) {
+    prev_part[start_pos] = bsize;
+  } else {
+    switch (partition) {
+      case PARTITION_NONE: prev_part[start_pos] = bsize; break;
+      case PARTITION_HORZ:
+        prev_part[start_pos] = subsize;
+        if (mi_row + bs < cm->mi_rows)
+          prev_part[start_pos + bs * cm->mi_stride] = subsize;
+        break;
+      case PARTITION_VERT:
+        prev_part[start_pos] = subsize;
+        if (mi_col + bs < cm->mi_cols) prev_part[start_pos + bs] = subsize;
+        break;
+      case PARTITION_SPLIT:
+        update_prev_partition(cpi, subsize, mi_row, mi_col);
+        update_prev_partition(cpi, subsize, mi_row + bs, mi_col);
+        update_prev_partition(cpi, subsize, mi_row, mi_col + bs);
+        update_prev_partition(cpi, subsize, mi_row + bs, mi_col + bs);
+        break;
+      default: assert(0);
+    }
+  }
+}
+
 static void chroma_check(VP9_COMP *cpi, MACROBLOCK *x, int bsize,
                          unsigned int y_sad, int is_key_frame) {
   int i;
@@ -828,6 +916,7 @@
   const int low_res = (cm->width <= 352 && cm->height <= 288);
   int variance4x4downsample[16];
   int segment_id;
+  int offset = cm->mi_stride * mi_row + mi_col;
 
   set_offsets(cpi, tile, x, mi_row, mi_col, BLOCK_64X64);
   segment_id = xd->mi[0]->segment_id;
@@ -861,7 +950,7 @@
     YV12_BUFFER_CONFIG *yv12 = get_ref_frame_buffer(cpi, LAST_FRAME);
 
     const YV12_BUFFER_CONFIG *yv12_g = NULL;
-    unsigned int y_sad_g, y_sad_thr;
+    unsigned int y_sad_g, y_sad_thr, y_sad_last;
     bsize = BLOCK_32X32 + (mi_col + 4 < cm->mi_cols) * 2 +
             (mi_row + 4 < cm->mi_rows);
 
@@ -901,6 +990,7 @@
     mi->interp_filter = BILINEAR;
 
     y_sad = vp9_int_pro_motion_estimation(cpi, x, bsize, mi_row, mi_col);
+    y_sad_last = y_sad;
     // Pick ref frame for partitioning, bias last frame when y_sad_g and y_sad
     // are close if short_circuit_low_temp_var is on.
     y_sad_thr = cpi->sf.short_circuit_low_temp_var ? (y_sad * 7) >> 3 : y_sad;
@@ -941,6 +1031,20 @@
         return 0;
       }
     }
+
+    // If the y_sad is small enough, copy the partition of the superblock in the
+    // last frame to current frame only if the last frame is not a keyframe.
+    // TODO(jianj) : tune the threshold.
+    if (cpi->sf.copy_partition_flag && cpi->rc.frames_since_key > 1 &&
+        segment_id == CR_SEGMENT_ID_BASE &&
+        cpi->prev_segment_id[offset] == CR_SEGMENT_ID_BASE &&
+        y_sad_last < cpi->vbp_threshold_copy) {
+      if (cpi->prev_partition != NULL) {
+        copy_prev_partition(cpi, BLOCK_64X64, mi_row, mi_col);
+        chroma_check(cpi, x, bsize, y_sad, is_key_frame);
+        return 0;
+      }
+    }
   } else {
     d = VP9_VAR_OFFS;
     dp = 0;
@@ -1133,6 +1237,11 @@
         }
       }
     }
+  }
+
+  if (cm->frame_type != KEY_FRAME && cpi->sf.copy_partition_flag) {
+    update_prev_partition(cpi, BLOCK_64X64, mi_row, mi_col);
+    cpi->prev_segment_id[offset] = segment_id;
   }
 
   if (cpi->sf.short_circuit_low_temp_var) {
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -439,6 +439,12 @@
   cpi->nmvsadcosts_hp[0] = NULL;
   cpi->nmvsadcosts_hp[1] = NULL;
 
+  vpx_free(cpi->prev_partition);
+  cpi->prev_partition = NULL;
+
+  vpx_free(cpi->prev_segment_id);
+  cpi->prev_segment_id = NULL;
+
   vp9_cyclic_refresh_free(cpi->cyclic_refresh);
   cpi->cyclic_refresh = NULL;
 
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -594,6 +594,8 @@
   int64_t vbp_thresholds[4];
   int64_t vbp_threshold_minmax;
   int64_t vbp_threshold_sad;
+  // Threshold used for partition copy
+  int64_t vbp_threshold_copy;
   BLOCK_SIZE vbp_bsize_min;
 
   // Multi-threading
@@ -605,6 +607,10 @@
 
   int keep_level_stats;
   Vp9LevelInfo level_info;
+
+  // Previous Partition Info
+  BLOCK_SIZE *prev_partition;
+  int8_t *prev_segment_id;
 } VP9_COMP;
 
 void vp9_initialize_enc(void);
--- a/vp9/encoder/vp9_speed_features.c
+++ b/vp9/encoder/vp9_speed_features.c
@@ -311,6 +311,7 @@
   sf->allow_exhaustive_searches = 0;
   sf->exhaustive_searches_thresh = INT_MAX;
   sf->allow_acl = 0;
+  sf->copy_partition_flag = 0;
 
   if (speed >= 1) {
     sf->allow_txfm_domain_distortion = 1;
@@ -496,6 +497,18 @@
 
   if (speed >= 8) {
     sf->adaptive_rd_thresh = 4;
+    // Disabled for now until the threshold is tuned.
+    sf->copy_partition_flag = 0;
+    if (sf->copy_partition_flag) {
+      if (cpi->prev_partition == NULL) {
+        cpi->prev_partition = (BLOCK_SIZE *)vpx_calloc(
+            cm->mi_stride * cm->mi_rows, sizeof(BLOCK_SIZE));
+      }
+      if (cpi->prev_segment_id == NULL) {
+        cpi->prev_segment_id =
+            (int8_t *)vpx_calloc(cm->mi_stride * cm->mi_rows, sizeof(int8_t));
+      }
+    }
     sf->mv.subpel_force_stop = (content == VP9E_CONTENT_SCREEN) ? 3 : 2;
     if (content == VP9E_CONTENT_SCREEN) sf->lpf_pick = LPF_PICK_MINIMAL_LPF;
     // Only keep INTRA_DC mode for speed 8.
--- a/vp9/encoder/vp9_speed_features.h
+++ b/vp9/encoder/vp9_speed_features.h
@@ -474,6 +474,9 @@
   // Bias to use base mv and skip 1/4 subpel search when use base mv in
   // enhancement layer.
   int base_mv_aggressive;
+
+  // Global flag to enable partition copy from the previous frame.
+  int copy_partition_flag;
 } SPEED_FEATURES;
 
 struct VP9_COMP;