shithub: libvpx

Download patch

ref: 96d584e1b8049570e8c93cd5177d28a7d78b890c
parent: 062a43acb6b474e2663b3e639ef251ca9f3b360f
parent: b2e498000ff52b27a62cd14a5b586ba0fefc9914
author: Angie Chiang <angiebird@google.com>
date: Tue Oct 22 14:17:51 EDT 2019

Merge changes I00697e9a,I9dfc2ba3,I73619051,Ib4d37667

* changes:
  Refactor kf_group_err in find_next_key_frame
  Simplify the logics in find_next_key_frame
  Add get_gop_coding_frame_num()
  Localize zero_motion_accumulator

--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -2477,6 +2477,122 @@
 #define ARF_ABS_ZOOM_THRESH 4.0
 
 #define MAX_GF_BOOST 5400
+
+static int get_gop_coding_frame_num(
+    int *use_alt_ref, const FRAME_INFO *frame_info,
+    const FIRST_PASS_INFO *first_pass_info, const RATE_CONTROL *rc,
+    int gf_start_show_idx, int active_min_gf_interval,
+    int active_max_gf_interval, double gop_intra_factor, int kf_zeromotion_pct,
+    int lag_in_frames) {
+  double loop_decay_rate = 1.00;
+  double mv_ratio_accumulator = 0.0;
+  double this_frame_mv_in_out = 0.0;
+  double mv_in_out_accumulator = 0.0;
+  double abs_mv_in_out_accumulator = 0.0;
+  double sr_accumulator = 0.0;
+  // Motion breakout threshold for loop below depends on image size.
+  double mv_ratio_accumulator_thresh =
+      (frame_info->frame_height + frame_info->frame_width) / 4.0;
+  double zero_motion_accumulator = 1.0;
+  int gop_coding_frames;
+
+  *use_alt_ref = 1;
+  gop_coding_frames = 0;
+  while (gop_coding_frames < rc->static_scene_max_gf_interval &&
+         gop_coding_frames < rc->frames_to_key) {
+    const FIRSTPASS_STATS *next_next_frame;
+    const FIRSTPASS_STATS *next_frame;
+    int flash_detected;
+    ++gop_coding_frames;
+
+    next_frame = fps_get_frame_stats(first_pass_info,
+                                     gf_start_show_idx + gop_coding_frames);
+    if (next_frame == NULL) {
+      break;
+    }
+
+    // Test for the case where there is a brief flash but the prediction
+    // quality back to an earlier frame is then restored.
+    next_next_frame = fps_get_frame_stats(
+        first_pass_info, gf_start_show_idx + gop_coding_frames + 1);
+    flash_detected = detect_flash_from_frame_stats(next_next_frame);
+
+    // Update the motion related elements to the boost calculation.
+    accumulate_frame_motion_stats(
+        next_frame, &this_frame_mv_in_out, &mv_in_out_accumulator,
+        &abs_mv_in_out_accumulator, &mv_ratio_accumulator);
+
+    // Monitor for static sections.
+    if ((rc->frames_since_key + gop_coding_frames - 1) > 1) {
+      zero_motion_accumulator =
+          VPXMIN(zero_motion_accumulator,
+                 get_zero_motion_factor(frame_info, next_frame));
+    }
+
+    // Accumulate the effect of prediction quality decay.
+    if (!flash_detected) {
+      double last_loop_decay_rate = loop_decay_rate;
+      loop_decay_rate = get_prediction_decay_rate(frame_info, next_frame);
+
+      // Break clause to detect very still sections after motion. For example,
+      // a static image after a fade or other transition.
+      if (gop_coding_frames > rc->min_gf_interval && loop_decay_rate >= 0.999 &&
+          last_loop_decay_rate < 0.9) {
+        int still_interval = 5;
+        if (check_transition_to_still(first_pass_info,
+                                      gf_start_show_idx + gop_coding_frames,
+                                      still_interval)) {
+          *use_alt_ref = 0;
+          break;
+        }
+      }
+
+      // Update the accumulator for second ref error difference.
+      // This is intended to give an indication of how much the coded error is
+      // increasing over time.
+      if (gop_coding_frames == 1) {
+        sr_accumulator += next_frame->coded_error;
+      } else {
+        sr_accumulator +=
+            (next_frame->sr_coded_error - next_frame->coded_error);
+      }
+    }
+
+    // Break out conditions.
+    // Break at maximum of active_max_gf_interval unless almost totally
+    // static.
+    //
+    // Note that the addition of a test of rc->source_alt_ref_active is
+    // deliberate. The effect of this is that after a normal altref group even
+    // if the material is static there will be one normal length GF group
+    // before allowing longer GF groups. The reason for this is that in cases
+    // such as slide shows where slides are separated by a complex transition
+    // such as a fade, the arf group spanning the transition may not be coded
+    // at a very high quality and hence this frame (with its overlay) is a
+    // poor golden frame to use for an extended group.
+    if ((gop_coding_frames >= active_max_gf_interval) &&
+        ((zero_motion_accumulator < 0.995) || (rc->source_alt_ref_active))) {
+      break;
+    }
+    if (
+        // Don't break out with a very short interval.
+        (gop_coding_frames >= active_min_gf_interval) &&
+        // If possible dont break very close to a kf
+        ((rc->frames_to_key - gop_coding_frames) >= rc->min_gf_interval) &&
+        (gop_coding_frames & 0x01) && (!flash_detected) &&
+        ((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
+         (abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH) ||
+         (sr_accumulator > gop_intra_factor * next_frame->intra_error))) {
+      break;
+    }
+  }
+  *use_alt_ref &= zero_motion_accumulator < 0.995;
+  *use_alt_ref &= kf_zeromotion_pct < STATIC_KF_GROUP_THRESH;
+  *use_alt_ref &= gop_coding_frames < lag_in_frames;
+  *use_alt_ref &= gop_coding_frames >= rc->min_gf_interval;
+  return gop_coding_frames;
+}
+
 static void define_gf_group(VP9_COMP *cpi, int gf_start_show_idx) {
   VP9_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
@@ -2485,8 +2601,7 @@
   const FRAME_INFO *frame_info = &cpi->frame_info;
   const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info;
   const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
-  int i;
-  int j;
+  int gop_coding_frames;
 
   double gf_group_err = 0.0;
   double gf_group_raw_error = 0.0;
@@ -2496,10 +2611,9 @@
   double gf_group_inter = 0.0;
   double gf_group_motion = 0.0;
 
-  double zero_motion_accumulator = 1.0;
+  int allow_alt_ref = is_altref_enabled(cpi);
+  int use_alt_ref;
 
-  unsigned int allow_alt_ref = is_altref_enabled(cpi);
-
   int active_max_gf_interval;
   int active_min_gf_interval;
   int64_t gf_group_bits;
@@ -2565,6 +2679,7 @@
   if (cpi->multi_layer_arf) {
     int layers = 0;
     int max_layers = VPXMIN(MAX_ARF_LAYERS, cpi->oxcf.enable_auto_arf);
+    int i;
 
     // Adapt the intra_error factor to active_max_gf_interval limit.
     for (i = active_max_gf_interval; i > 0; i >>= 1) ++layers;
@@ -2573,120 +2688,28 @@
     gop_intra_factor += (layers * 0.25);
   }
 
-  i = 0;
   {
-    double loop_decay_rate = 1.00;
-    double mv_ratio_accumulator = 0.0;
-    double this_frame_mv_in_out = 0.0;
-    double mv_in_out_accumulator = 0.0;
-    double abs_mv_in_out_accumulator = 0.0;
-    double sr_accumulator = 0.0;
-    // Motion breakout threshold for loop below depends on image size.
-    double mv_ratio_accumulator_thresh =
-        (cpi->initial_height + cpi->initial_width) / 4.0;
-
-    while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) {
-      const FIRSTPASS_STATS *next_next_frame;
-      const FIRSTPASS_STATS *next_frame;
-      int flash_detected;
-      ++i;
-
-      next_frame = fps_get_frame_stats(first_pass_info, gf_start_show_idx + i);
-      if (next_frame == NULL) {
-        break;
-      }
-
-      // Test for the case where there is a brief flash but the prediction
-      // quality back to an earlier frame is then restored.
-      next_next_frame =
-          fps_get_frame_stats(first_pass_info, gf_start_show_idx + i + 1);
-      flash_detected = detect_flash_from_frame_stats(next_next_frame);
-
-      // Update the motion related elements to the boost calculation.
-      accumulate_frame_motion_stats(
-          next_frame, &this_frame_mv_in_out, &mv_in_out_accumulator,
-          &abs_mv_in_out_accumulator, &mv_ratio_accumulator);
-
-      // Monitor for static sections.
-      if ((rc->frames_since_key + i - 1) > 1) {
-        zero_motion_accumulator =
-            VPXMIN(zero_motion_accumulator,
-                   get_zero_motion_factor(frame_info, next_frame));
-      }
-
-      // Accumulate the effect of prediction quality decay.
-      if (!flash_detected) {
-        double last_loop_decay_rate = loop_decay_rate;
-        loop_decay_rate = get_prediction_decay_rate(frame_info, next_frame);
-
-        // Break clause to detect very still sections after motion. For example,
-        // a static image after a fade or other transition.
-        if (i > rc->min_gf_interval && loop_decay_rate >= 0.999 &&
-            last_loop_decay_rate < 0.9) {
-          int still_interval = 5;
-          if (check_transition_to_still(first_pass_info, gf_start_show_idx + i,
-                                        still_interval)) {
-            allow_alt_ref = 0;
-            break;
-          }
-        }
-
-        // Update the accumulator for second ref error difference.
-        // This is intended to give an indication of how much the coded error is
-        // increasing over time.
-        if (i == 1) {
-          sr_accumulator += next_frame->coded_error;
-        } else {
-          sr_accumulator +=
-              (next_frame->sr_coded_error - next_frame->coded_error);
-        }
-      }
-
-      // Break out conditions.
-      // Break at maximum of active_max_gf_interval unless almost totally
-      // static.
-      //
-      // Note that the addition of a test of rc->source_alt_ref_active is
-      // deliberate. The effect of this is that after a normal altref group even
-      // if the material is static there will be one normal length GF group
-      // before allowing longer GF groups. The reason for this is that in cases
-      // such as slide shows where slides are separated by a complex transition
-      // such as a fade, the arf group spanning the transition may not be coded
-      // at a very high quality and hence this frame (with its overlay) is a
-      // poor golden frame to use for an extended group.
-      if ((i >= active_max_gf_interval) &&
-          ((zero_motion_accumulator < 0.995) || (rc->source_alt_ref_active))) {
-        break;
-      }
-      if (
-          // Don't break out with a very short interval.
-          (i >= active_min_gf_interval) &&
-          // If possible dont break very close to a kf
-          ((rc->frames_to_key - i) >= rc->min_gf_interval) && (i & 0x01) &&
-          (!flash_detected) &&
-          ((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
-           (abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH) ||
-           (sr_accumulator > gop_intra_factor * next_frame->intra_error))) {
-        break;
-      }
-    }
+    gop_coding_frames = get_gop_coding_frame_num(
+        &use_alt_ref, frame_info, first_pass_info, rc, gf_start_show_idx,
+        active_min_gf_interval, active_max_gf_interval, gop_intra_factor,
+        twopass->kf_zeromotion_pct, cpi->oxcf.lag_in_frames);
+    use_alt_ref &= allow_alt_ref;
   }
 
   // Was the group length constrained by the requirement for a new KF?
-  rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0;
+  rc->constrained_gf_group = (gop_coding_frames >= rc->frames_to_key) ? 1 : 0;
 
   // Should we use the alternate reference frame.
-  if ((zero_motion_accumulator < 0.995) && allow_alt_ref &&
-      (twopass->kf_zeromotion_pct < STATIC_KF_GROUP_THRESH) &&
-      (i < cpi->oxcf.lag_in_frames) && (i >= rc->min_gf_interval)) {
-    const int f_frames = (rc->frames_to_key - i >= i - 1)
-                             ? i - 1
-                             : VPXMAX(0, rc->frames_to_key - i);
-    const int b_frames = i - 1;
+  if (use_alt_ref) {
+    const int f_frames =
+        (rc->frames_to_key - gop_coding_frames >= gop_coding_frames - 1)
+            ? gop_coding_frames - 1
+            : VPXMAX(0, rc->frames_to_key - gop_coding_frames);
+    const int b_frames = gop_coding_frames - 1;
     const int avg_inter_frame_qindex = rc->avg_frame_qindex[INTER_FRAME];
     // TODO(angiebird): figure out why arf's location is assigned this way
-    const int arf_show_idx =
-        VPXMIN(gf_start_show_idx + i + 1, fps_get_num_frames(first_pass_info));
+    const int arf_show_idx = VPXMIN(gf_start_show_idx + gop_coding_frames + 1,
+                                    fps_get_num_frames(first_pass_info));
 
     // Calculate the boost for alt ref.
     rc->gfu_boost =
@@ -2694,7 +2717,7 @@
                           b_frames, avg_inter_frame_qindex);
     rc->source_alt_ref_pending = 1;
   } else {
-    const int f_frames = i - 1;
+    const int f_frames = gop_coding_frames - 1;
     const int b_frames = 0;
     const int avg_inter_frame_qindex = rc->avg_frame_qindex[INTER_FRAME];
     // TODO(angiebird): figure out why arf's location is assigned this way
@@ -2718,16 +2741,18 @@
       rc->arf_active_best_quality_adjustment_factor =
           LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR +
           (1.0 - LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR) *
-              (rc->frames_to_key - i) /
-              (VPXMAX(1, ((rc->frames_to_key + rc->frames_since_key) / 2 - i)));
+              (rc->frames_to_key - gop_coding_frames) /
+              (VPXMAX(1, ((rc->frames_to_key + rc->frames_since_key) / 2 -
+                          gop_coding_frames)));
       rc->arf_increase_active_best_quality = 1;
-    } else if ((rc->frames_to_key - i) > 0) {
+    } else if ((rc->frames_to_key - gop_coding_frames) > 0) {
       // Reduce the active best quality in the first half of key frame interval.
       rc->arf_active_best_quality_adjustment_factor =
           LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR +
           (1.0 - LAST_ALR_ACTIVE_BEST_QUALITY_ADJUSTMENT_FACTOR) *
-              (rc->frames_since_key + i) /
-              (VPXMAX(1, (rc->frames_to_key + rc->frames_since_key) / 2 + i));
+              (rc->frames_since_key + gop_coding_frames) /
+              (VPXMAX(1, (rc->frames_to_key + rc->frames_since_key) / 2 +
+                             gop_coding_frames));
       rc->arf_increase_active_best_quality = -1;
     }
   }
@@ -2734,9 +2759,9 @@
 
 #ifdef AGGRESSIVE_VBR
   // Limit maximum boost based on interval length.
-  rc->gfu_boost = VPXMIN((int)rc->gfu_boost, i * 140);
+  rc->gfu_boost = VPXMIN((int)rc->gfu_boost, gop_coding_frames * 140);
 #else
-  rc->gfu_boost = VPXMIN((int)rc->gfu_boost, i * 200);
+  rc->gfu_boost = VPXMIN((int)rc->gfu_boost, gop_coding_frames * 200);
 #endif
 
   // Cap the ARF boost when perceptual quality AQ mode is enabled. This is
@@ -2746,7 +2771,7 @@
   if (oxcf->aq_mode == PERCEPTUAL_AQ)
     rc->gfu_boost = VPXMIN(rc->gfu_boost, MIN_ARF_GF_BOOST);
 
-  rc->baseline_gf_interval = i - rc->source_alt_ref_pending;
+  rc->baseline_gf_interval = gop_coding_frames - rc->source_alt_ref_pending;
 
   if (rc->source_alt_ref_pending)
     is_alt_ref_flash = detect_flash(twopass, rc->baseline_gf_interval);
@@ -2757,8 +2782,8 @@
     // If the first frame is a key frame or the overlay from a previous arf then
     // the error score / cost of this frame has already been accounted for.
     int start_idx = arf_active_or_kf ? 1 : 0;
-    int num_coding_frames = i;
-    for (j = start_idx; j < num_coding_frames; ++j) {
+    int j;
+    for (j = start_idx; j < gop_coding_frames; ++j) {
       int show_idx = gf_start_show_idx + j;
       const FIRSTPASS_STATS *frame_stats =
           fps_get_frame_stats(first_pass_info, show_idx);
@@ -3030,13 +3055,15 @@
 #define MAX_KF_TOT_BOOST 5400
 #endif
 
-static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame) {
+static void find_next_key_frame(VP9_COMP *cpi, FIRSTPASS_STATS *this_frame,
+                                int kf_show_idx) {
   int i, j;
   RATE_CONTROL *const rc = &cpi->rc;
   TWO_PASS *const twopass = &cpi->twopass;
   GF_GROUP *const gf_group = &twopass->gf_group;
   const VP9EncoderConfig *const oxcf = &cpi->oxcf;
-  const FIRSTPASS_STATS first_frame = *this_frame;
+  const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info;
+  const FRAME_INFO *frame_info = &cpi->frame_info;
   const FIRSTPASS_STATS *const start_position = twopass->stats_in;
   FIRSTPASS_STATS next_frame;
   FIRSTPASS_STATS last_frame;
@@ -3058,6 +3085,7 @@
   double sr_accumulator = 0.0;
   double abs_mv_in_out_accumulator = 0.0;
   const double av_err = get_distribution_av_err(cpi, twopass);
+  const double mean_mod_score = twopass->mean_mod_score;
   vp9_zero(next_frame);
 
   cpi->common.frame_type = KEY_FRAME;
@@ -3092,10 +3120,6 @@
   i = 0;
   while (twopass->stats_in < twopass->stats_in_end &&
          rc->frames_to_key < cpi->oxcf.key_freq) {
-    // Accumulate kf group error.
-    kf_group_err +=
-        calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
-
     // Load the next frame's stats.
     last_frame = *this_frame;
     input_stats(twopass, this_frame);
@@ -3128,14 +3152,8 @@
         break;
 
       // Step on to the next frame.
-      ++rc->frames_to_key;
-
-      // If we don't have a real key frame within the next two
-      // key_freq intervals then break out of the loop.
-      if (rc->frames_to_key >= 2 * cpi->oxcf.key_freq) break;
-    } else {
-      ++rc->frames_to_key;
     }
+    ++rc->frames_to_key;
     ++i;
   }
 
@@ -3143,35 +3161,19 @@
   // We already breakout of the loop above at 2x max.
   // This code centers the extra kf if the actual natural interval
   // is between 1x and 2x.
-  if (cpi->oxcf.auto_key && rc->frames_to_key > cpi->oxcf.key_freq) {
-    FIRSTPASS_STATS tmp_frame = first_frame;
-
-    rc->frames_to_key /= 2;
-
-    // Reset to the start of the group.
-    reset_fpf_position(twopass, start_position);
-
-    kf_group_err = 0.0;
-
-    // Rescan to get the correct error data for the forced kf group.
-    for (i = 0; i < rc->frames_to_key; ++i) {
-      kf_group_err +=
-          calculate_norm_frame_score(cpi, twopass, oxcf, &tmp_frame, av_err);
-      input_stats(twopass, &tmp_frame);
-    }
+  if (twopass->stats_in == twopass->stats_in_end ||
+      rc->frames_to_key >= cpi->oxcf.key_freq) {
     rc->next_key_frame_forced = 1;
-  } else if (twopass->stats_in == twopass->stats_in_end ||
-             rc->frames_to_key >= cpi->oxcf.key_freq) {
-    rc->next_key_frame_forced = 1;
   } else {
     rc->next_key_frame_forced = 0;
   }
 
-  // Special case for the last key frame of the file.
-  if (twopass->stats_in >= twopass->stats_in_end) {
+  for (i = 0; i < rc->frames_to_key; ++i) {
+    const FIRSTPASS_STATS *frame_stats =
+        fps_get_frame_stats(first_pass_info, kf_show_idx + i);
     // Accumulate kf group error.
-    kf_group_err +=
-        calculate_norm_frame_score(cpi, twopass, oxcf, this_frame, av_err);
+    kf_group_err += calc_norm_frame_score(oxcf, frame_info, frame_stats,
+                                          mean_mod_score, av_err);
   }
 
   // Calculate the number of bits that should be assigned to the kf group.
@@ -3349,6 +3351,7 @@
   TWO_PASS *const twopass = &cpi->twopass;
   GF_GROUP *const gf_group = &twopass->gf_group;
   FIRSTPASS_STATS this_frame;
+  const int show_idx = cm->current_video_frame;
 
   if (!twopass->stats_in) return;
 
@@ -3434,7 +3437,7 @@
     FIRSTPASS_STATS this_frame_copy;
     this_frame_copy = this_frame;
     // Define next KF group and assign bits to it.
-    find_next_key_frame(cpi, &this_frame);
+    find_next_key_frame(cpi, &this_frame, show_idx);
     this_frame = this_frame_copy;
   } else {
     cm->frame_type = INTER_FRAME;
@@ -3442,8 +3445,7 @@
 
   // Define a new GF/ARF group. (Should always enter here for key frames).
   if (rc->frames_till_gf_update_due == 0) {
-    const int gf_start_show_idx = cm->current_video_frame;
-    define_gf_group(cpi, gf_start_show_idx);
+    define_gf_group(cpi, show_idx);
 
     rc->frames_till_gf_update_due = rc->baseline_gf_interval;