Two-steps scaling in VP9 encoder dynamic resizing.
authorjackychen <jackychen@google.com>
Thu, 1 Oct 2015 21:03:22 +0000 (14:03 -0700)
committerjackychen <jackychen@google.com>
Fri, 2 Oct 2015 01:18:49 +0000 (18:18 -0700)
Dynamic resizing now support two-steps scaling: first go down to
3/4 and then 1/2. This feature is under a flag which controls the
switch between two-steps scaling and one-step scaling (1/2 only).

Change-Id: I3a6c1d3d5668cf8e016a0a02aeca737565604a0f

vp9/encoder/vp9_encoder.c
vp9/encoder/vp9_ratectrl.c
vp9/encoder/vp9_ratectrl.h

index e67ce88..0615369 100644 (file)
@@ -3130,26 +3130,19 @@ static void set_frame_size(VP9_COMP *cpi) {
   if (oxcf->pass == 0 &&
       oxcf->rc_mode == VPX_CBR &&
       !cpi->use_svc &&
-      oxcf->resize_mode == RESIZE_DYNAMIC) {
-      if (cpi->resize_pending == 1) {
-        oxcf->scaled_frame_width =
-            (cm->width * cpi->resize_scale_num) / cpi->resize_scale_den;
-        oxcf->scaled_frame_height =
-            (cm->height * cpi->resize_scale_num) /cpi->resize_scale_den;
-      } else if (cpi->resize_pending == -1) {
-        // Go back up to original size.
-        oxcf->scaled_frame_width = oxcf->width;
-        oxcf->scaled_frame_height = oxcf->height;
-      }
-      if (cpi->resize_pending != 0) {
-        // There has been a change in frame size.
-        vp9_set_size_literal(cpi,
-                             oxcf->scaled_frame_width,
-                             oxcf->scaled_frame_height);
-
-        // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
-        set_mv_search_params(cpi);
-      }
+      oxcf->resize_mode == RESIZE_DYNAMIC &&
+      cpi->resize_pending != 0) {
+    oxcf->scaled_frame_width =
+        (oxcf->width * cpi->resize_scale_num) / cpi->resize_scale_den;
+    oxcf->scaled_frame_height =
+        (oxcf->height * cpi->resize_scale_num) /cpi->resize_scale_den;
+    // There has been a change in frame size.
+    vp9_set_size_literal(cpi,
+                         oxcf->scaled_frame_width,
+                         oxcf->scaled_frame_height);
+
+    // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
+    set_mv_search_params(cpi);
   }
 
   if ((oxcf->pass == 2) &&
index 973cde8..4fe5561 100644 (file)
@@ -1820,7 +1820,7 @@ void vp9_set_target_rate(VP9_COMP *cpi) {
 int vp9_resize_one_pass_cbr(VP9_COMP *cpi) {
   const VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
-  int resize_now = 0;
+  RESIZE_ACTION resize_action = NO_RESIZE;
   cpi->resize_scale_num = 1;
   cpi->resize_scale_den = 1;
   // Don't resize on key frame; reset the counters on key frame.
@@ -1840,18 +1840,32 @@ int vp9_resize_one_pass_cbr(VP9_COMP *cpi) {
     // Check for resize action every "window" frames.
     if (cpi->resize_count >= window) {
       int avg_qp = cpi->resize_avg_qp / cpi->resize_count;
-      // Resize down if buffer level has underflowed sufficent amount in past
-      // window, and we are at original resolution.
+      // Resize down if buffer level has underflowed sufficient amount in past
+      // window, and we are at original or 3/4 of original resolution.
       // Resize back up if average QP is low, and we are currently in a resized
-      // down state.
-      if (cpi->resize_state == 0 &&
-          cpi->resize_buffer_underflow > (cpi->resize_count >> 2)) {
-        resize_now = 1;
-        cpi->resize_state = 1;
-      } else if (cpi->resize_state == 1 &&
-                 avg_qp < 50 * cpi->rc.worst_quality / 100) {
-        resize_now = -1;
-        cpi->resize_state = 0;
+      // down state, i.e. 1/2 or 3/4 of original resolution.
+      // Currently, use a flag to turn 3/4 resizing feature on/off.
+      if (cpi->resize_buffer_underflow > (cpi->resize_count >> 1)) {
+        resize_action = DOWN_ONEHALF;
+        cpi->resize_state = ONE_HALF;
+      } else if (cpi->resize_buffer_underflow > (cpi->resize_count >> 2)) {
+        if (cpi->resize_state == THREE_QUARTER || ONEHALFONLY_RESIZE) {
+          resize_action = DOWN_ONEHALF;
+          cpi->resize_state = ONE_HALF;
+        } else if (cpi->resize_state == ORIG) {
+          resize_action = DOWN_THREEFOUR;
+          cpi->resize_state = THREE_QUARTER;
+        }
+      } else if (avg_qp < 60 * cpi->rc.worst_quality / 100) {
+        if (cpi->resize_state == THREE_QUARTER ||
+            avg_qp < 40 * cpi->rc.worst_quality / 100 ||
+            ONEHALFONLY_RESIZE) {
+          resize_action = UP_ORIG;
+          cpi->resize_state = ORIG;
+        } else if (cpi->resize_state == ONE_HALF) {
+          resize_action = UP_THREEFOUR;
+          cpi->resize_state = THREE_QUARTER;
+        }
       }
       // Reset for next window measurement.
       cpi->resize_avg_qp = 0;
@@ -1861,14 +1875,21 @@ int vp9_resize_one_pass_cbr(VP9_COMP *cpi) {
   }
   // If decision is to resize, reset some quantities, and check is we should
   // reduce rate correction factor,
-  if (resize_now != 0) {
+  if (resize_action != NO_RESIZE) {
     int target_bits_per_frame;
     int active_worst_quality;
     int qindex;
     int tot_scale_change;
-    // For now, resize is by 1/2 x 1/2.
-    cpi->resize_scale_num = 1;
-    cpi->resize_scale_den = 2;
+    if (resize_action == DOWN_THREEFOUR || resize_action == UP_THREEFOUR) {
+      cpi->resize_scale_num = 3;
+      cpi->resize_scale_den = 4;
+    } else if (resize_action == DOWN_ONEHALF) {
+      cpi->resize_scale_num = 1;
+      cpi->resize_scale_den = 2;
+    } else {  // UP_ORIG or anything else
+      cpi->resize_scale_num = 1;
+      cpi->resize_scale_den = 1;
+    }
     tot_scale_change = (cpi->resize_scale_den * cpi->resize_scale_den) /
         (cpi->resize_scale_num * cpi->resize_scale_num);
     // Reset buffer level to optimal, update target size.
@@ -1880,7 +1901,7 @@ int vp9_resize_one_pass_cbr(VP9_COMP *cpi) {
       vp9_cyclic_refresh_reset_resize(cpi);
     // Get the projected qindex, based on the scaled target frame size (scaled
     // so target_bits_per_mb in vp9_rc_regulate_q will be correct target).
-    target_bits_per_frame = (resize_now == 1) ?
+    target_bits_per_frame = (resize_action >= 0) ?
         rc->this_frame_target * tot_scale_change :
         rc->this_frame_target / tot_scale_change;
     active_worst_quality = calc_active_worst_quality_one_pass_cbr(cpi);
@@ -1891,19 +1912,19 @@ int vp9_resize_one_pass_cbr(VP9_COMP *cpi) {
     // If resize is down, check if projected q index is close to worst_quality,
     // and if so, reduce the rate correction factor (since likely can afford
     // lower q for resized frame).
-    if (resize_now == 1 &&
+    if (resize_action > 0 &&
         qindex > 90 * cpi->rc.worst_quality / 100) {
       rc->rate_correction_factors[INTER_NORMAL] *= 0.85;
     }
     // If resize is back up, check if projected q index is too much above the
     // current base_qindex, and if so, reduce the rate correction factor
     // (since prefer to keep q for resized frame at least close to previous q).
-    if (resize_now == -1 &&
+    if (resize_action < 0 &&
        qindex > 130 * cm->base_qindex / 100) {
       rc->rate_correction_factors[INTER_NORMAL] *= 0.9;
     }
   }
-  return resize_now;
+  return resize_action;
 }
 
 // Compute average source sad (temporal sad: between current source and
index 11dfa35..eb7c793 100644 (file)
@@ -26,6 +26,7 @@ extern "C" {
 
 #define MIN_GF_INTERVAL     4
 #define MAX_GF_INTERVAL     16
+#define ONEHALFONLY_RESIZE  1
 
 typedef enum {
   INTER_NORMAL = 0,
@@ -43,6 +44,20 @@ typedef enum {
   FRAME_SCALE_STEPS
 } FRAME_SCALE_LEVEL;
 
+typedef enum {
+  NO_RESIZE = 0,
+  DOWN_THREEFOUR = 1,  // From orig to 3/4.
+  DOWN_ONEHALF = 2,    // From orig or 3/4 to 1/2.
+  UP_THREEFOUR = -1,   // From 1/2 to 3/4.
+  UP_ORIG = -2,        // From 1/2 or 3/4 to orig.
+} RESIZE_ACTION;
+
+typedef enum {
+  ORIG = 0,
+  THREE_QUARTER = 1,
+  ONE_HALF = 2
+} RESIZE_STATE;
+
 // Frame dimensions multiplier wrt the native frame size, in 1/16ths,
 // specified for the scale-up case.
 // e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is