shithub: libvpx

Download patch

ref: 7cbeb910f2e1aed1f53686afca10460a19565292
parent: 2b06bf20ce7e6ead8ea43dc9ad5bcc6674fee8d8
parent: fc0b33182b119d5d5efab964dba9367537b74e4d
author: Marco Paniconi <marpan@google.com>
date: Thu Mar 27 04:48:22 EDT 2014

Merge "aq_mode=3: Set target seg_map in sb-block order."

--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -20,17 +20,18 @@
 #include "vp9/encoder/vp9_segmentation.h"
 
 struct CYCLIC_REFRESH {
-  // Target percentage of blocks per frame that are cyclicly refreshed.
-  int max_mbs_perframe;
+  // Percentage of super-blocks per frame that are targeted as candidates
+  // for cyclic refresh.
+  int max_sbs_perframe;
   // Maximum q-delta as percentage of base q.
   int max_qdelta_perc;
   // Block size below which we don't apply cyclic refresh.
   BLOCK_SIZE min_block_size;
-  // Macroblock starting index (unit of 8x8) for cycling through the frame.
-  int mb_index;
+  // Superblock starting index for cycling through the frame.
+  int sb_index;
   // Controls how long a block will need to wait to be refreshed again.
   int time_for_refresh;
-  // Actual number of blocks that were applied delta-q (segment 1).
+  // Actual number of (8x8) blocks that were applied delta-q (segment 1).
   int num_seg_blocks;
   // Actual encoding bits for segment 1.
   int actual_seg_bits;
@@ -77,7 +78,13 @@
   const int number_blocks = cm->mi_rows  * cm->mi_cols;
   // The condition below corresponds to turning off at target bitrates:
   // ~24kbps for CIF, 72kbps for VGA (at 30fps).
-  return rc->av_per_frame_bandwidth >= factor * number_blocks;
+  // Also turn off at very small frame sizes, to avoid too large fraction of
+  // superblocks to be refreshed per frame. Threshold below is less than QCIF.
+  if (rc->av_per_frame_bandwidth < factor * number_blocks ||
+      number_blocks / 64 < 5)
+    return 0;
+  else
+    return 1;
 }
 
 // Check if this coding block, of size bsize, should be considered for refresh
@@ -184,19 +191,18 @@
     vpx_memset(seg_map, 0, cm->mi_rows * cm->mi_cols);
     vp9_disable_segmentation(&cm->seg);
     if (cm->frame_type == KEY_FRAME)
-      cr->mb_index = 0;
+      cr->sb_index = 0;
     return;
   } else {
-    const int mbs_in_frame = cm->mi_rows * cm->mi_cols;
     int qindex_delta = 0;
-    int i, x, y, block_count;
-    int mi_row, mi_col, qindex2;
+    int i, block_count, bl_index, sb_rows, sb_cols, sbs_in_frame;
+    int xmis, ymis, x, y, qindex2;
 
     // Rate target ratio to set q delta.
     const float rate_ratio_qdelta = 2.0;
     vp9_clear_system_state();
     // Some of these parameters may be set via codec-control function later.
-    cr->max_mbs_perframe = 10;
+    cr->max_sbs_perframe = 10;
     cr->max_qdelta_perc = 50;
     cr->min_block_size = BLOCK_16X16;
     cr->time_for_refresh = 1;
@@ -248,52 +254,62 @@
     cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);
 
     vp9_set_segdata(seg, 1, SEG_LVL_ALT_Q, qindex_delta);
-    // Number of target macroblocks to get the q delta (segment 1).
-    block_count = cr->max_mbs_perframe * mbs_in_frame / 100;
-    // Set the segmentation map: cycle through the macroblocks, starting at
+
+    sb_cols = (cm->mi_cols + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
+    sb_rows = (cm->mi_rows + MI_BLOCK_SIZE - 1) / MI_BLOCK_SIZE;
+    sbs_in_frame = sb_cols * sb_rows;
+    // Number of target superblocks to get the q delta (segment 1).
+    block_count = cr->max_sbs_perframe * sbs_in_frame / 100;
+    // Set the segmentation map: cycle through the superblocks, starting at
     // cr->mb_index, and stopping when either block_count blocks have been found
     // to be refreshed, or we have passed through whole frame.
-    // Note the setting of seg_map below is done in two steps (one over 8x8)
-    // and then another over SB, in order to keep the value constant over SB.
-    // TODO(marpan): Do this in one pass in SB order.
-    assert(cr->mb_index < mbs_in_frame);
-    i = cr->mb_index;
+    assert(cr->sb_index < sbs_in_frame);
+    i = cr->sb_index;
     do {
-      // If the macroblock is as a candidate for clean up then mark it
-      // for possible boost/refresh (segment 1). The segment id may get reset to
-      // 0 later if the macroblock gets coded anything other than ZEROMV.
-      if (cr->map[i] == 0) {
-        seg_map[i] = 1;
-        block_count--;
-      } else if (cr->map[i] < 0) {
-        cr->map[i]++;
+      int sum_map = 0;
+      // Get the mi_row/mi_col corresponding to superblock index i.
+      int sb_row_index = (i / sb_cols);
+      int sb_col_index = i - sb_row_index * sb_cols;
+      int mi_row = sb_row_index * MI_BLOCK_SIZE;
+      int mi_col = sb_col_index * MI_BLOCK_SIZE;
+      assert(mi_row >= 0 && mi_row < cm->mi_rows);
+      assert(mi_col >= 0 && mi_col < cm->mi_cols);
+      bl_index = mi_row * cm->mi_cols + mi_col;
+      // Loop through all 8x8 blocks in superblock and update map.
+      xmis = MIN(cm->mi_cols - mi_col,
+                 num_8x8_blocks_wide_lookup[BLOCK_64X64]);
+      ymis = MIN(cm->mi_rows - mi_row,
+                 num_8x8_blocks_high_lookup[BLOCK_64X64]);
+      for (y = 0; y < ymis; y++) {
+        for (x = 0; x < xmis; x++) {
+          const int bl_index2 = bl_index + y * cm->mi_cols + x;
+          // If the block is as a candidate for clean up then mark it
+          // for possible boost/refresh (segment 1). The segment id may get
+          // reset to 0 later if block gets coded anything other than ZEROMV.
+          if (cr->map[bl_index2] == 0) {
+            seg_map[bl_index2] = 1;
+            sum_map++;
+          } else if (cr->map[bl_index2] < 0) {
+            cr->map[bl_index2]++;
+          }
+        }
       }
-      i++;
-      if (i == mbs_in_frame) {
-        i = 0;
-      }
-    } while (block_count && i != cr->mb_index);
-    cr->mb_index = i;
-    // Enforce constant segment map over superblock.
-    for (mi_row = 0; mi_row < cm->mi_rows; mi_row +=  MI_BLOCK_SIZE)
-      for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE) {
-        const int bl_index = mi_row * cm->mi_cols + mi_col;
-        const int xmis = MIN(cm->mi_cols - mi_col,
-                             num_8x8_blocks_wide_lookup[BLOCK_64X64]);
-        const int ymis = MIN(cm->mi_rows - mi_row,
-                             num_8x8_blocks_high_lookup[BLOCK_64X64]);
-        int sum_map = 0;
+      // Enforce constant segment over superblock.
+      // If segment is partial over superblock, reset to either all 1 or 0.
+      if (sum_map > 0 && sum_map < xmis * ymis) {
+        const int new_value = (sum_map >= xmis * ymis / 2);
         for (y = 0; y < ymis; y++)
           for (x = 0; x < xmis; x++)
-            sum_map += seg_map[bl_index + y * cm->mi_cols + x];
-        // If segment is partial over superblock, reset.
-        if (sum_map > 0 && sum_map < xmis * ymis) {
-          const int new_value = (sum_map >= xmis * ymis / 2);
-          for (y = 0; y < ymis; y++)
-            for (x = 0; x < xmis; x++)
-              seg_map[bl_index + y * cm->mi_cols + x] = new_value;
-        }
+            seg_map[bl_index + y * cm->mi_cols + x] = new_value;
       }
+      i++;
+      if (i == sbs_in_frame) {
+        i = 0;
+      }
+      if (sum_map >= xmis * ymis /2)
+        block_count--;
+    } while (block_count && i != cr->sb_index);
+    cr->sb_index = i;
   }
 }