shithub: libvpx

Download patch

ref: eea06db1782b078aacfc8e5dc06e8e29710ec0ef
parent: 7a63240c485cd702bead191f36f9bf03d193e7c5
author: Cheng Chen <chengchen@google.com>
date: Fri Jan 17 06:25:56 EST 2020

Store frame partition info

Allocate partition information for the frame, and update it
when a superblock (64x64) is encoded.

The unit size of the smallest block is 4x4.

For each 4x4 block, store the current positition (row, column),
the start positition (row_start, column_start) of the partition,
and the block width and height of the partition.

Change-Id: I11c16bbca7e89a088715a1200abd23fe2f9ca1d6

--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -3810,6 +3810,60 @@
 }
 #endif  // !CONFIG_REALTIME_ONLY
 
+#if CONFIG_RATE_CTRL
+static void store_superblock_partition_info(
+    const PC_TREE *const pc_tree, PARTITION_INFO *partition_info,
+    const int square_size_4x4, const int num_unit_rows, const int num_unit_cols,
+    const int row_start_4x4, const int col_start_4x4) {
+  const int subblock_square_size_4x4 = square_size_4x4 >> 1;
+  if (row_start_4x4 >= num_unit_rows || col_start_4x4 >= num_unit_cols) return;
+  assert(pc_tree->partitioning != PARTITION_INVALID);
+  // End node, no split.
+  if (pc_tree->partitioning == PARTITION_NONE ||
+      pc_tree->partitioning == PARTITION_HORZ ||
+      pc_tree->partitioning == PARTITION_VERT || square_size_4x4 == 1) {
+    const int block_width_4x4 = (pc_tree->partitioning == PARTITION_VERT)
+                                    ? square_size_4x4 >> 1
+                                    : square_size_4x4;
+    const int block_height_4x4 = (pc_tree->partitioning == PARTITION_HORZ)
+                                     ? square_size_4x4 >> 1
+                                     : square_size_4x4;
+    int i, j;
+    for (i = 0; i < block_height_4x4; ++i) {
+      for (j = 0; j < block_width_4x4; ++j) {
+        const int row_4x4 = row_start_4x4 + i;
+        const int col_4x4 = col_start_4x4 + j;
+        const int unit_index = row_4x4 * num_unit_cols + col_4x4;
+        partition_info[unit_index].row = row_4x4 << 2;
+        partition_info[unit_index].column = col_4x4 << 2;
+        partition_info[unit_index].row_start = row_start_4x4 << 2;
+        partition_info[unit_index].column_start = col_start_4x4 << 2;
+        partition_info[unit_index].width = block_width_4x4 << 2;
+        partition_info[unit_index].height = block_height_4x4 << 2;
+      }
+    }
+    return;
+  }
+  // recursively traverse partition tree when partition is split.
+  assert(pc_tree->partitioning == PARTITION_SPLIT);
+  store_superblock_partition_info(pc_tree->split[0], partition_info,
+                                  subblock_square_size_4x4, num_unit_rows,
+                                  num_unit_cols, row_start_4x4, col_start_4x4);
+  store_superblock_partition_info(pc_tree->split[1], partition_info,
+                                  subblock_square_size_4x4, num_unit_rows,
+                                  num_unit_cols, row_start_4x4,
+                                  col_start_4x4 + subblock_square_size_4x4);
+  store_superblock_partition_info(
+      pc_tree->split[2], partition_info, subblock_square_size_4x4,
+      num_unit_rows, num_unit_cols, row_start_4x4 + subblock_square_size_4x4,
+      col_start_4x4);
+  store_superblock_partition_info(
+      pc_tree->split[3], partition_info, subblock_square_size_4x4,
+      num_unit_rows, num_unit_cols, row_start_4x4 + subblock_square_size_4x4,
+      col_start_4x4 + subblock_square_size_4x4);
+}
+#endif  // CONFIG_RATE_CTRL
+
 #if !CONFIG_REALTIME_ONLY
 // TODO(jingning,jimbankoski,rbultje): properly skip partition types that are
 // unlikely to be selected depending on previous rate-distortion optimization
@@ -4384,6 +4438,16 @@
     int output_enabled = (bsize == BLOCK_64X64);
     encode_sb(cpi, td, tile_info, tp, mi_row, mi_col, output_enabled, bsize,
               pc_tree);
+#if CONFIG_RATE_CTRL
+    // Store partition info.
+    if (output_enabled) {
+      const int num_unit_rows = get_num_unit_4x4(cpi->frame_info.frame_height);
+      const int num_unit_cols = get_num_unit_4x4(cpi->frame_info.frame_width);
+      store_superblock_partition_info(
+          pc_tree, cpi->partition_info, num_4x4_blocks_wide_lookup[BLOCK_64X64],
+          num_unit_rows, num_unit_cols, mi_row << 1, mi_col << 1);
+    }
+#endif  // CONFIG_RATE_CTRL
   }
 
   if (bsize == BLOCK_64X64) {
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -1021,6 +1021,10 @@
   vpx_free(cpi->mi_ssim_rdmult_scaling_factors);
   cpi->mi_ssim_rdmult_scaling_factors = NULL;
 
+#if CONFIG_RATE_CTRL
+  free_partition_info(cpi);
+#endif
+
   vp9_free_ref_frame_buffers(cm->buffer_pool);
 #if CONFIG_VP9_POSTPROC
   vp9_free_postproc_buffers(cm);
@@ -2649,6 +2653,7 @@
 
 #if CONFIG_RATE_CTRL
   encode_command_init(&cpi->encode_command);
+  partition_info_init(cpi);
 #endif
 
   return cpi;
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -523,6 +523,15 @@
   int external_quantize_index;
 } ENCODE_COMMAND;
 
+typedef struct PARTITION_INFO {
+  int row;           // row pixel offset of current 4x4 block
+  int column;        // column pixel offset of current 4x4 block
+  int row_start;     // row pixel offset of the start of the prediction block
+  int column_start;  // column pixel offset of the start of the prediction block
+  int width;         // prediction block width
+  int height;        // prediction block height
+} PARTITION_INFO;
+
 static INLINE void encode_command_init(ENCODE_COMMAND *encode_command) {
   vp9_zero(*encode_command);
   encode_command->use_external_quantize_index = 0;
@@ -540,6 +549,10 @@
   encode_command->use_external_quantize_index = 0;
   encode_command->external_quantize_index = -1;
 }
+
+// Returns number of units in size of 4, if not multiple not a multiple of 4,
+// round it up. For example, size is 7, return 3.
+static INLINE int get_num_unit_4x4(int size) { return (size + 3) >> 2; }
 #endif  // CONFIG_RATE_CTRL
 
 typedef struct VP9_COMP {
@@ -848,8 +861,32 @@
   vpx_roi_map_t roi;
 #if CONFIG_RATE_CTRL
   ENCODE_COMMAND encode_command;
+  PARTITION_INFO *partition_info;
 #endif
 } VP9_COMP;
+
+#if CONFIG_RATE_CTRL
+// Allocates memory for the partition information.
+// The unit size is each 4x4 block.
+// Only called once in vp9_create_compressor().
+static INLINE void partition_info_init(struct VP9_COMP *cpi) {
+  VP9_COMMON *const cm = &cpi->common;
+  const int unit_width = get_num_unit_4x4(cpi->frame_info.frame_width);
+  const int unit_height = get_num_unit_4x4(cpi->frame_info.frame_height);
+  CHECK_MEM_ERROR(cm, cpi->partition_info,
+                  (PARTITION_INFO *)vpx_calloc(unit_width * unit_height,
+                                               sizeof(PARTITION_INFO)));
+  memset(cpi->partition_info, 0,
+         unit_width * unit_height * sizeof(PARTITION_INFO));
+}
+
+// Frees memory of the partition information.
+// Only called once in dealloc_compressor_data().
+static INLINE void free_partition_info(struct VP9_COMP *cpi) {
+  vpx_free(cpi->partition_info);
+  cpi->partition_info = NULL;
+}
+#endif  // CONFIG_RATE_CTRL
 
 typedef struct ENCODE_FRAME_RESULT {
   int show_idx;
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -616,7 +616,7 @@
 
 uint64_t SimpleEncode::GetFramePixelCount() const {
   assert(frame_width_ % 2 == 0);
-  assert(frame_heigh_ % 2 == 0);
+  assert(frame_height_ % 2 == 0);
   switch (impl_ptr_->img_fmt) {
     case VPX_IMG_FMT_I420: return frame_width_ * frame_height_ * 3 / 2;
     case VPX_IMG_FMT_I422: return frame_width_ * frame_height_ * 2;