shithub: libvpx

Download patch

ref: df66f8e830eef4e95323f87cc0a3697168a512e7
parent: efb56ec3ff6c8bfdeb1b29c97374017e1556aa16
author: Marco <marpan@google.com>
date: Thu Oct 6 12:01:04 EDT 2016

vp8: Change default gf behavior for 1 pass cbr.

In 1 pass CBR, with error_resilience off, allow for
special logic to change the default gf behaviour.
In this CL: boost is turned off and the gf period
is set to a multiple of cyclic refresh period.

Change only affect 1 pass CBR mode, i.e, when the flag
gf_update_onepass_cbr is set.

Including the previous change (3ec8e11: to allow cyclic refresh
for error_resilience off), comparing metrics on RTC set for
error_resilience off vs on: avgPSNR/SSIM up by ~6%.

Change-Id: Id5b3fb62a4f04de5a805bd1b418f2b349574e0bc

--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -1467,6 +1467,12 @@
   cpi->baseline_gf_interval =
       cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL;
 
+  // GF behavior for 1 pass CBR, used when error_resilience is off.
+  if (!cpi->oxcf.error_resilient_mode &&
+      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
+      cpi->oxcf.Mode == MODE_REALTIME)
+    cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
+
 #if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
   cpi->oxcf.token_partitions = 3;
 #endif
@@ -1784,6 +1790,23 @@
   }
   cpi->cyclic_refresh_mode_index = 0;
   cpi->cyclic_refresh_q = 32;
+
+  // GF behavior for 1 pass CBR, used when error_resilience is off.
+  cpi->gf_update_onepass_cbr = 0;
+  cpi->gf_noboost_onepass_cbr = 0;
+  if (!cpi->oxcf.error_resilient_mode &&
+      cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER && cpi->oxcf.Mode <= 2) {
+    cpi->gf_update_onepass_cbr = 1;
+    cpi->gf_noboost_onepass_cbr = 1;
+    cpi->gf_interval_onepass_cbr =
+        cpi->cyclic_refresh_mode_max_mbs_perframe > 0
+            ? (2 * (cpi->common.mb_rows * cpi->common.mb_cols) /
+               cpi->cyclic_refresh_mode_max_mbs_perframe)
+            : 10;
+    cpi->gf_interval_onepass_cbr =
+        VPXMIN(40, VPXMAX(6, cpi->gf_interval_onepass_cbr));
+    cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
+  }
 
   if (cpi->cyclic_refresh_mode_enabled) {
     CHECK_MEM_ERROR(cpi->cyclic_refresh_map,
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -501,6 +501,11 @@
 
   int force_maxqp;
 
+  // GF update for 1 pass cbr.
+  int gf_update_onepass_cbr;
+  int gf_interval_onepass_cbr;
+  int gf_noboost_onepass_cbr;
+
 #if CONFIG_MULTITHREAD
   /* multithread data */
   int *mt_current_mb_col;
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -885,61 +885,61 @@
   /* Adjust target frame size for Golden Frames: */
   if (cpi->oxcf.error_resilient_mode == 0 &&
       (cpi->frames_till_gf_update_due == 0) && !cpi->drop_frame) {
-    int Q =
-        (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q;
+    if (!cpi->gf_update_onepass_cbr) {
+      int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME]
+                                      : cpi->oxcf.fixed_q;
 
-    int gf_frame_useage = 0; /* Golden frame useage since last GF */
-    int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] +
-                  cpi->recent_ref_frame_usage[LAST_FRAME] +
-                  cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
-                  cpi->recent_ref_frame_usage[ALTREF_FRAME];
+      int gf_frame_useage = 0; /* Golden frame useage since last GF */
+      int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] +
+                    cpi->recent_ref_frame_usage[LAST_FRAME] +
+                    cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
+                    cpi->recent_ref_frame_usage[ALTREF_FRAME];
 
-    int pct_gf_active = (100 * cpi->gf_active_count) /
-                        (cpi->common.mb_rows * cpi->common.mb_cols);
+      int pct_gf_active = (100 * cpi->gf_active_count) /
+                          (cpi->common.mb_rows * cpi->common.mb_cols);
 
-    if (tot_mbs) {
-      gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
-                         cpi->recent_ref_frame_usage[ALTREF_FRAME]) *
-                        100 / tot_mbs;
-    }
+      if (tot_mbs) {
+        gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
+                           cpi->recent_ref_frame_usage[ALTREF_FRAME]) *
+                          100 / tot_mbs;
+      }
 
-    if (pct_gf_active > gf_frame_useage) gf_frame_useage = pct_gf_active;
+      if (pct_gf_active > gf_frame_useage) gf_frame_useage = pct_gf_active;
 
-    /* Is a fixed manual GF frequency being used */
-    if (cpi->auto_gold) {
-      /* For one pass throw a GF if recent frame intra useage is
-       * low or the GF useage is high
-       */
-      if ((cpi->pass == 0) &&
-          (cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) {
-        cpi->common.refresh_golden_frame = 1;
+      /* Is a fixed manual GF frequency being used */
+      if (cpi->auto_gold) {
+        /* For one pass throw a GF if recent frame intra useage is
+         * low or the GF useage is high
+         */
+        if ((cpi->pass == 0) &&
+            (cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) {
+          cpi->common.refresh_golden_frame = 1;
 
-        /* Two pass GF descision */
-      } else if (cpi->pass == 2) {
-        cpi->common.refresh_golden_frame = 1;
+          /* Two pass GF descision */
+        } else if (cpi->pass == 2) {
+          cpi->common.refresh_golden_frame = 1;
+        }
       }
-    }
 
 #if 0
 
-        /* Debug stats */
-        if (0)
-        {
-            FILE *f;
+          /* Debug stats */
+          if (0) {
+              FILE *f;
 
-            f = fopen("gf_useaget.stt", "a");
-            fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n",
-                    cpi->common.current_video_frame,  cpi->gfu_boost, GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage);
-            fclose(f);
-        }
+              f = fopen("gf_useaget.stt", "a");
+              fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n",
+                      cpi->common.current_video_frame,  cpi->gfu_boost,
+                      GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage);
+              fclose(f);
+          }
 
 #endif
 
-    if (cpi->common.refresh_golden_frame == 1) {
+      if (cpi->common.refresh_golden_frame == 1) {
 #if 0
 
-            if (0)
-            {
+            if (0) {
                 FILE *f;
 
                 f = fopen("GFexit.stt", "a");
@@ -949,61 +949,70 @@
 
 #endif
 
-      if (cpi->auto_adjust_gold_quantizer) {
-        calc_gf_params(cpi);
-      }
+        if (cpi->auto_adjust_gold_quantizer) {
+          calc_gf_params(cpi);
+        }
 
-      /* If we are using alternate ref instead of gf then do not apply the
-       * boost It will instead be applied to the altref update Jims
-       * modified boost
-       */
-      if (!cpi->source_alt_ref_active) {
-        if (cpi->oxcf.fixed_q < 0) {
-          if (cpi->pass == 2) {
-            /* The spend on the GF is defined in the two pass
-             * code for two pass encodes
-             */
-            cpi->this_frame_target = cpi->per_frame_bandwidth;
-          } else {
-            int Boost = cpi->last_boost;
-            int frames_in_section = cpi->frames_till_gf_update_due + 1;
-            int allocation_chunks = (frames_in_section * 100) + (Boost - 100);
-            int bits_in_section = cpi->inter_frame_target * frames_in_section;
+        /* If we are using alternate ref instead of gf then do not apply the
+         * boost It will instead be applied to the altref update Jims
+         * modified boost
+         */
+        if (!cpi->source_alt_ref_active) {
+          if (cpi->oxcf.fixed_q < 0) {
+            if (cpi->pass == 2) {
+              /* The spend on the GF is defined in the two pass
+               * code for two pass encodes
+               */
+              cpi->this_frame_target = cpi->per_frame_bandwidth;
+            } else {
+              int Boost = cpi->last_boost;
+              int frames_in_section = cpi->frames_till_gf_update_due + 1;
+              int allocation_chunks = (frames_in_section * 100) + (Boost - 100);
+              int bits_in_section = cpi->inter_frame_target * frames_in_section;
 
-            /* Normalize Altboost and allocations chunck down to
-             * prevent overflow
-             */
-            while (Boost > 1000) {
-              Boost /= 2;
-              allocation_chunks /= 2;
-            }
+              /* Normalize Altboost and allocations chunck down to
+               * prevent overflow
+               */
+              while (Boost > 1000) {
+                Boost /= 2;
+                allocation_chunks /= 2;
+              }
 
-            /* Avoid loss of precision but avoid overflow */
-            if ((bits_in_section >> 7) > allocation_chunks) {
-              cpi->this_frame_target =
-                  Boost * (bits_in_section / allocation_chunks);
-            } else {
-              cpi->this_frame_target =
-                  (Boost * bits_in_section) / allocation_chunks;
+              /* Avoid loss of precision but avoid overflow */
+              if ((bits_in_section >> 7) > allocation_chunks) {
+                cpi->this_frame_target =
+                    Boost * (bits_in_section / allocation_chunks);
+              } else {
+                cpi->this_frame_target =
+                    (Boost * bits_in_section) / allocation_chunks;
+              }
             }
+          } else {
+            cpi->this_frame_target =
+                (estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) *
+                 cpi->last_boost) /
+                100;
           }
         } else {
-          cpi->this_frame_target =
-              (estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) *
-               cpi->last_boost) /
-              100;
+          /* If there is an active ARF at this location use the minimum
+           * bits on this frame even if it is a contructed arf.
+           * The active maximum quantizer insures that an appropriate
+           * number of bits will be spent if needed for contstructed ARFs.
+          */
+          cpi->this_frame_target = 0;
         }
 
+        cpi->current_gf_interval = cpi->frames_till_gf_update_due;
       }
-      /* If there is an active ARF at this location use the minimum
-       * bits on this frame even if it is a contructed arf.
-       * The active maximum quantizer insures that an appropriate
-       * number of bits will be spent if needed for contstructed ARFs.
-       */
-      else {
-        cpi->this_frame_target = 0;
-      }
-
+    } else {
+      // Special case for 1 pass CBR: for now no boost and fixed gf period.
+      // TODO(marpan): Adjust this boost/interval logic.
+      cpi->gf_noboost_onepass_cbr = 1;
+      cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
+      // Skip this update if the zero_mvcount is low.
+      if (cpi->zeromv_count > (cpi->common.MBs >> 1))
+        cpi->common.refresh_golden_frame = 1;
+      cpi->frames_till_gf_update_due = cpi->baseline_gf_interval;
       cpi->current_gf_interval = cpi->frames_till_gf_update_due;
     }
   }
@@ -1025,8 +1034,9 @@
   if (cpi->common.frame_type == KEY_FRAME) {
     rate_correction_factor = cpi->key_frame_rate_correction_factor;
   } else {
-    if (cpi->oxcf.number_of_layers == 1 && (cpi->common.refresh_alt_ref_frame ||
-                                            cpi->common.refresh_golden_frame)) {
+    if (cpi->oxcf.number_of_layers == 1 && !cpi->gf_noboost_onepass_cbr &&
+        (cpi->common.refresh_alt_ref_frame ||
+         cpi->common.refresh_golden_frame)) {
       rate_correction_factor = cpi->gf_rate_correction_factor;
     } else {
       rate_correction_factor = cpi->rate_correction_factor;
@@ -1102,8 +1112,9 @@
   if (cpi->common.frame_type == KEY_FRAME) {
     cpi->key_frame_rate_correction_factor = rate_correction_factor;
   } else {
-    if (cpi->oxcf.number_of_layers == 1 && (cpi->common.refresh_alt_ref_frame ||
-                                            cpi->common.refresh_golden_frame)) {
+    if (cpi->oxcf.number_of_layers == 1 && !cpi->gf_noboost_onepass_cbr &&
+        (cpi->common.refresh_alt_ref_frame ||
+         cpi->common.refresh_golden_frame)) {
       cpi->gf_rate_correction_factor = rate_correction_factor;
     } else {
       cpi->rate_correction_factor = rate_correction_factor;
@@ -1118,7 +1129,6 @@
     cpi->active_worst_quality = cpi->worst_quality;
     return cpi->worst_quality;
   }
-
   /* Reset Zbin OQ value */
   cpi->mb.zbin_over_quant = 0;
 
@@ -1128,10 +1138,12 @@
     if (cpi->common.frame_type == KEY_FRAME) {
       Q = cpi->oxcf.key_q;
     } else if (cpi->oxcf.number_of_layers == 1 &&
-               cpi->common.refresh_alt_ref_frame) {
+               cpi->common.refresh_alt_ref_frame &&
+               !cpi->gf_noboost_onepass_cbr) {
       Q = cpi->oxcf.alt_q;
     } else if (cpi->oxcf.number_of_layers == 1 &&
-               cpi->common.refresh_golden_frame) {
+               cpi->common.refresh_golden_frame &&
+               !cpi->gf_noboost_onepass_cbr) {
       Q = cpi->oxcf.gold_q;
     }
   } else {
@@ -1145,7 +1157,7 @@
     if (cpi->common.frame_type == KEY_FRAME) {
       correction_factor = cpi->key_frame_rate_correction_factor;
     } else {
-      if (cpi->oxcf.number_of_layers == 1 &&
+      if (cpi->oxcf.number_of_layers == 1 && !cpi->gf_noboost_onepass_cbr &&
           (cpi->common.refresh_alt_ref_frame ||
            cpi->common.refresh_golden_frame)) {
         correction_factor = cpi->gf_rate_correction_factor;
@@ -1199,6 +1211,7 @@
       if (cpi->common.frame_type == KEY_FRAME) {
         zbin_oqmax = 0;
       } else if (cpi->oxcf.number_of_layers == 1 &&
+                 !cpi->gf_noboost_onepass_cbr &&
                  (cpi->common.refresh_alt_ref_frame ||
                   (cpi->common.refresh_golden_frame &&
                    !cpi->source_alt_ref_active))) {