shithub: libvpx

Download patch

ref: 71e6ed7bd12016ba7169711d3c232c10e72cc0f0
parent: 8a192ce7efa461ff15886e60a8e9752a6bc2e105
author: Marco <marpan@google.com>
date: Tue Mar 10 11:16:10 EDT 2015

Adjustments to aq-mode=3.

Factor in segment#2 and skip blocks into the postencode estimated bits,
and increase somewhat the aggressiveness of the refresh.

PSNR/SSIM Metrics on RTC set go up by ~0.8/0.5%.

Change-Id: I5d4e7cb00a3aefb25d18c88b6b24118b72dc5d51

--- a/vp9/encoder/vp9_aq_cyclicrefresh.c
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.c
@@ -30,10 +30,11 @@
   // excess of the cycle time, i.e., in the case of all zero motion, block
   // will be refreshed every (100/percent_refresh + time_for_refresh) frames.
   int time_for_refresh;
-  // // Target number of (8x8) blocks that are set for delta-q (segment 1).
+  // Target number of (8x8) blocks that are set for delta-q.
   int target_num_seg_blocks;
-  // Actual number of (8x8) blocks that were applied delta-q (segment 1).
-  int actual_num_seg_blocks;
+  // Actual number of (8x8) blocks that were applied delta-q.
+  int actual_num_seg1_blocks;
+  int actual_num_seg2_blocks;
   // RD mult. parameters for segment 1.
   int rdmult;
   // Cyclic refresh map.
@@ -48,6 +49,8 @@
   // Rate target ratio to set q delta.
   double rate_ratio_qdelta;
   double low_content_avg;
+  int qindex_delta_seg1;
+  int qindex_delta_seg2;
 };
 
 CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) {
@@ -110,7 +113,7 @@
        mv.col > cr->motion_thresh || mv.col < -cr->motion_thresh ||
        !is_inter_block(mbmi)))
     return CR_SEGMENT_ID_BASE;
-  else  if (bsize >= BLOCK_32X32 &&
+  else  if (bsize >= BLOCK_16X16 &&
             rate < cr->thresh_rate_sb &&
             is_inter_block(mbmi) &&
             mbmi->mv[0].as_int == 0)
@@ -146,15 +149,19 @@
   int num8x8bl = mbs << 2;
   // Weight for non-base segments: use actual number of blocks refreshed in
   // previous/just encoded frame. Note number of blocks here is in 8x8 units.
-  double weight_segment = (double)cr->actual_num_seg_blocks / num8x8bl;
-  // Compute delta-q that was used in the just encoded frame.
-  int deltaq = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta);
+  double weight_segment1 = (double)cr->actual_num_seg1_blocks / num8x8bl;
+  double weight_segment2 = (double)cr->actual_num_seg2_blocks / num8x8bl;
   // Take segment weighted average for estimated bits.
-  estimated_bits = (int)((1.0 - weight_segment) *
+  estimated_bits = (int)((1.0 - weight_segment1 - weight_segment2) *
       vp9_estimate_bits_at_q(cm->frame_type, cm->base_qindex, mbs,
                              correction_factor, cm->bit_depth) +
-                             weight_segment *
-      vp9_estimate_bits_at_q(cm->frame_type, cm->base_qindex + deltaq, mbs,
+                             weight_segment1 *
+      vp9_estimate_bits_at_q(cm->frame_type,
+                             cm->base_qindex + cr->qindex_delta_seg1, mbs,
+                             correction_factor, cm->bit_depth) +
+                             weight_segment2 *
+      vp9_estimate_bits_at_q(cm->frame_type,
+                             cm->base_qindex + cr->qindex_delta_seg2, mbs,
                              correction_factor, cm->bit_depth));
   return estimated_bits;
 }
@@ -170,15 +177,11 @@
   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
   int bits_per_mb;
   int num8x8bl = cm->MBs << 2;
-  // Weight for segment 1 prior to encoding: take the target number for the
-  // frame to be encoded. Number of blocks here is in 8x8 units.
-  // Note that this is called in rc_regulate_q, which is called before the
-  // cyclic_refresh_setup (which sets cr->target_num_seg_blocks). So a mismatch
-  // may occur between the cr->target_num_seg_blocks value here and the
-  // cr->target_num_seg_block set for encoding the frame. For the current use
-  // case of fixed cr->percent_refresh and cr->time_for_refresh = 0, mismatch
-  // does not occur/is very small.
-  double weight_segment = (double)cr->target_num_seg_blocks / num8x8bl;
+  // Weight for segment prior to encoding: take the average of the target
+  // number for the frame to be encoded and the actual from the previous frame.
+  double weight_segment = (double)((cr->target_num_seg_blocks +
+      cr->actual_num_seg1_blocks + cr->actual_num_seg2_blocks) >> 1) /
+      num8x8bl;
   // Compute delta-q corresponding to qindex i.
   int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta);
   // Take segment weighted average for bits per mb.
@@ -198,7 +201,8 @@
                                        int mi_row, int mi_col,
                                        BLOCK_SIZE bsize,
                                        int64_t rate,
-                                       int64_t dist) {
+                                       int64_t dist,
+                                       int skip) {
   const VP9_COMMON *const cm = &cpi->common;
   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
   const int bw = num_8x8_blocks_wide_lookup[bsize];
@@ -214,8 +218,12 @@
 
   // If this block is labeled for refresh, check if we should reset the
   // segment_id.
-  if (cyclic_refresh_segment_id_boosted(mbmi->segment_id))
+  if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) {
     mbmi->segment_id = refresh_this_block;
+    // Reset segment_id if will be skipped.
+    if (skip)
+      mbmi->segment_id = CR_SEGMENT_ID_BASE;
+  }
 
   // Update the cyclic refresh map, to be used for setting segmentation map
   // for the next frame. If the block  will be refreshed this frame, mark it
@@ -250,12 +258,16 @@
   CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
   unsigned char *const seg_map = cpi->segmentation_map;
   int mi_row, mi_col;
-  cr->actual_num_seg_blocks = 0;
+  cr->actual_num_seg1_blocks = 0;
+  cr->actual_num_seg2_blocks = 0;
   for (mi_row = 0; mi_row < cm->mi_rows; mi_row++)
     for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) {
-      if (cyclic_refresh_segment_id_boosted(
-              seg_map[mi_row * cm->mi_cols + mi_col]))
-        cr->actual_num_seg_blocks++;
+      if (cyclic_refresh_segment_id(
+          seg_map[mi_row * cm->mi_cols + mi_col]) == CR_SEGMENT_ID_BOOST1)
+        cr->actual_num_seg1_blocks++;
+      else if (cyclic_refresh_segment_id(
+          seg_map[mi_row * cm->mi_cols + mi_col]) == CR_SEGMENT_ID_BOOST2)
+        cr->actual_num_seg2_blocks++;
     }
 }
 
@@ -413,7 +425,7 @@
     cr->time_for_refresh = 0;
     // Set rate threshold to some multiple (set to 2 for now) of the target
     // rate (target is given by sb64_target_rate and scaled by 256).
-    cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 1;
+    cr->thresh_rate_sb = ((int64_t)(rc->sb64_target_rate) << 8) << 2;
     // Distortion threshold, quadratic in Q, scale factor to be adjusted.
     // q will not exceed 457, so (q * q) is within 32bit; see:
     // vp9_convert_qindex_to_q(), vp9_ac_quant(), ac_qlookup*[].
@@ -442,9 +454,11 @@
 
     // Set the q delta for segment BOOST1.
     qindex_delta = compute_deltaq(cpi, cm->base_qindex, cr->rate_ratio_qdelta);
+    cr->qindex_delta_seg1 = qindex_delta;
 
     // Compute rd-mult for segment BOOST1.
     qindex2 = clamp(cm->base_qindex + cm->y_dc_delta_q + qindex_delta, 0, MAXQ);
+
     cr->rdmult = vp9_compute_rd_mult(cpi, qindex2);
 
     vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta);
@@ -453,6 +467,7 @@
     qindex_delta = compute_deltaq(cpi, cm->base_qindex,
                                   MIN(CR_MAX_RATE_TARGET_RATIO,
                                       CR_BOOST2_FAC * cr->rate_ratio_qdelta));
+    cr->qindex_delta_seg2 = qindex_delta;
     vp9_set_segdata(seg, CR_SEGMENT_ID_BOOST2, SEG_LVL_ALT_Q, qindex_delta);
 
     // Update the segmentation and refresh map.
--- a/vp9/encoder/vp9_aq_cyclicrefresh.h
+++ b/vp9/encoder/vp9_aq_cyclicrefresh.h
@@ -55,7 +55,7 @@
 void vp9_cyclic_refresh_update_segment(struct VP9_COMP *const cpi,
                                        MB_MODE_INFO *const mbmi,
                                        int mi_row, int mi_col, BLOCK_SIZE bsize,
-                                       int64_t rate, int64_t dist);
+                                       int64_t rate, int64_t dist, int skip);
 
 // Update the segmentation map, and related quantities: cyclic refresh map,
 // refresh sb_index, and target number of blocks to be refreshed.
@@ -81,6 +81,15 @@
 static INLINE int cyclic_refresh_segment_id_boosted(int segment_id) {
   return segment_id == CR_SEGMENT_ID_BOOST1 ||
          segment_id == CR_SEGMENT_ID_BOOST2;
+}
+
+static INLINE int cyclic_refresh_segment_id(int segment_id) {
+  if (segment_id == CR_SEGMENT_ID_BOOST1)
+    return CR_SEGMENT_ID_BOOST1;
+  else if (segment_id == CR_SEGMENT_ID_BOOST2)
+    return CR_SEGMENT_ID_BOOST2;
+  else
+    return CR_SEGMENT_ID_BASE;
 }
 
 #ifdef __cplusplus
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -868,7 +868,8 @@
     // and then update the quantizer.
     if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
       vp9_cyclic_refresh_update_segment(cpi, &xd->mi[0].src_mi->mbmi, mi_row,
-                                        mi_col, bsize, ctx->rate, ctx->dist);
+                                        mi_col, bsize, ctx->rate, ctx->dist,
+                                        x->skip);
     }
   }
 
@@ -1557,7 +1558,7 @@
     } else {
     // Setting segmentation map for cyclic_refresh.
       vp9_cyclic_refresh_update_segment(cpi, mbmi, mi_row, mi_col, bsize,
-                                        ctx->rate, ctx->dist);
+                                        ctx->rate, ctx->dist, x->skip);
     }
     vp9_init_plane_quantizers(cpi, x);
   }