shithub: libvpx

Download patch

ref: 2be0ee5f05b3dc0782626b8b10894d5d920bcb96
parent: b2850357277af3dfb6e0a300793bc5ae4264c463
parent: 9d377ff930d42ee080333ade5c983c0edff5b1e0
author: Angie Chiang <angiebird@google.com>
date: Wed Oct 16 14:32:19 EDT 2019

Merge changes I1d71908a,Id1b41c3b,I07722c81,I31cf7889

* changes:
  Localize last_loop_decay_rate
  Make get_zero_mtion_factor avoid using cpi
  Add check_transition_to_still()
  Add compute_arf_boost()

--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -1784,10 +1784,11 @@
 
 // This function gives an estimate of how badly we believe the prediction
 // quality is decaying from frame to frame.
-static double get_zero_motion_factor(const VP9_COMP *cpi,
-                                     const FIRSTPASS_STATS *frame) {
-  const double zero_motion_pct = frame->pcnt_inter - frame->pcnt_motion;
-  double sr_decay = get_sr_decay_rate(&cpi->frame_info, frame);
+static double get_zero_motion_factor(const FRAME_INFO *frame_info,
+                                     const FIRSTPASS_STATS *frame_stats) {
+  const double zero_motion_pct =
+      frame_stats->pcnt_inter - frame_stats->pcnt_motion;
+  double sr_decay = get_sr_decay_rate(frame_info, frame_stats);
   return VPXMIN(sr_decay, zero_motion_pct);
 }
 
@@ -1804,15 +1805,38 @@
                 (sr_decay_rate + ((1.0 - sr_decay_rate) * zero_motion_factor)));
 }
 
+static int get_show_idx(const TWO_PASS *twopass) {
+  return (int)(twopass->stats_in - twopass->stats_in_start);
+}
 // Function to test for a condition where a complex transition is followed
 // by a static section. For example in slide shows where there is a fade
 // between slides. This is to help with more optimal kf and gf positioning.
+static int check_transition_to_still(const FIRST_PASS_INFO *first_pass_info,
+                                     int show_idx, int still_interval) {
+  int j;
+  int num_frames = fps_get_num_frames(first_pass_info);
+  if (show_idx + still_interval > num_frames) {
+    return 0;
+  }
+
+  // Look ahead a few frames to see if static condition persists...
+  for (j = 0; j < still_interval; ++j) {
+    const FIRSTPASS_STATS *stats =
+        fps_get_frame_stats(first_pass_info, show_idx + j);
+    if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break;
+  }
+
+  // Only if it does do we signal a transition to still.
+  return j == still_interval;
+}
+
 static int detect_transition_to_still(VP9_COMP *cpi, int frame_interval,
                                       int still_interval,
                                       double loop_decay_rate,
                                       double last_decay_rate) {
-  TWO_PASS *const twopass = &cpi->twopass;
+  const TWO_PASS *const twopass = &cpi->twopass;
   RATE_CONTROL *const rc = &cpi->rc;
+  int show_idx = get_show_idx(twopass);
 
   // Break clause to detect very still sections after motion
   // For example a static image after a fade or other transition
@@ -1819,18 +1843,8 @@
   // instead of a clean scene cut.
   if (frame_interval > rc->min_gf_interval && loop_decay_rate >= 0.999 &&
       last_decay_rate < 0.9) {
-    int j;
-
-    // Look ahead a few frames to see if static condition persists...
-    for (j = 0; j < still_interval; ++j) {
-      const FIRSTPASS_STATS *stats = &twopass->stats_in[j];
-      if (stats >= twopass->stats_in_end) break;
-
-      if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break;
-    }
-
-    // Only if it does do we signal a transition to still.
-    return j == still_interval;
+    return check_transition_to_still(&twopass->first_pass_info, show_idx,
+                                     still_interval);
   }
 
   return 0;
@@ -1962,10 +1976,10 @@
   return VPXMIN(frame_boost, max_boost * boost_q_correction);
 }
 
-static int calc_arf_boost(VP9_COMP *cpi, int f_frames, int b_frames) {
-  const FRAME_INFO *frame_info = &cpi->frame_info;
-  TWO_PASS *const twopass = &cpi->twopass;
-  const int avg_inter_frame_qindex = cpi->rc.avg_frame_qindex[INTER_FRAME];
+static int compute_arf_boost(const FRAME_INFO *frame_info,
+                             const FIRST_PASS_INFO *first_pass_info,
+                             int arf_show_idx, int f_frames, int b_frames,
+                             int avg_frame_qindex) {
   int i;
   double boost_score = 0.0;
   double mv_ratio_accumulator = 0.0;
@@ -1978,8 +1992,10 @@
 
   // Search forward from the proposed arf/next gf position.
   for (i = 0; i < f_frames; ++i) {
-    const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i);
-    const FIRSTPASS_STATS *next_frame = read_frame_stats(twopass, i + 1);
+    const FIRSTPASS_STATS *this_frame =
+        fps_get_frame_stats(first_pass_info, arf_show_idx + i);
+    const FIRSTPASS_STATS *next_frame =
+        fps_get_frame_stats(first_pass_info, arf_show_idx + i + 1);
     if (this_frame == NULL) break;
 
     // Update the motion related elements to the boost calculation.
@@ -2000,7 +2016,7 @@
                               : decay_accumulator;
     }
     boost_score += decay_accumulator * calc_frame_boost(frame_info, this_frame,
-                                                        avg_inter_frame_qindex,
+                                                        avg_frame_qindex,
                                                         this_frame_mv_in_out);
   }
 
@@ -2016,8 +2032,10 @@
 
   // Search backward towards last gf position.
   for (i = -1; i >= -b_frames; --i) {
-    const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i);
-    const FIRSTPASS_STATS *next_frame = read_frame_stats(twopass, i + 1);
+    const FIRSTPASS_STATS *this_frame =
+        fps_get_frame_stats(first_pass_info, arf_show_idx + i);
+    const FIRSTPASS_STATS *next_frame =
+        fps_get_frame_stats(first_pass_info, arf_show_idx + i + 1);
     if (this_frame == NULL) break;
 
     // Update the motion related elements to the boost calculation.
@@ -2038,7 +2056,7 @@
                               : decay_accumulator;
     }
     boost_score += decay_accumulator * calc_frame_boost(frame_info, this_frame,
-                                                        avg_inter_frame_qindex,
+                                                        avg_frame_qindex,
                                                         this_frame_mv_in_out);
   }
   arf_boost += (int)boost_score;
@@ -2050,6 +2068,15 @@
   return arf_boost;
 }
 
+static int calc_arf_boost(VP9_COMP *cpi, int f_frames, int b_frames) {
+  const FRAME_INFO *frame_info = &cpi->frame_info;
+  TWO_PASS *const twopass = &cpi->twopass;
+  const int avg_inter_frame_qindex = cpi->rc.avg_frame_qindex[INTER_FRAME];
+  int arf_show_idx = get_show_idx(twopass);
+  return compute_arf_boost(frame_info, &twopass->first_pass_info, arf_show_idx,
+                           f_frames, b_frames, avg_inter_frame_qindex);
+}
+
 // Calculate a section intra ratio used in setting max loop filter.
 static int calculate_section_intra_ratio(const FIRSTPASS_STATS *begin,
                                          const FIRSTPASS_STATS *end,
@@ -2450,7 +2477,7 @@
 #define ARF_ABS_ZOOM_THRESH 4.0
 
 #define MAX_GF_BOOST 5400
-static void define_gf_group(VP9_COMP *cpi) {
+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;
   VP9EncoderConfig *const oxcf = &cpi->oxcf;
@@ -2457,9 +2484,7 @@
   TWO_PASS *const twopass = &cpi->twopass;
   const FRAME_INFO *frame_info = &cpi->frame_info;
   const FIRST_PASS_INFO *first_pass_info = &twopass->first_pass_info;
-  FIRSTPASS_STATS next_frame;
   const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
-  const int gf_start_show_idx = cm->current_video_frame;
   int i;
   int j;
 
@@ -2474,7 +2499,6 @@
   double mv_ratio_accumulator = 0.0;
   double zero_motion_accumulator = 1.0;
   double loop_decay_rate = 1.00;
-  double last_loop_decay_rate = 1.00;
 
   double this_frame_mv_in_out = 0.0;
   double mv_in_out_accumulator = 0.0;
@@ -2507,7 +2531,6 @@
   }
 
   vpx_clear_system_state();
-  vp9_zero(next_frame);
 
   // Motion breakout threshold for loop below depends on image size.
   mv_ratio_accumulator_thresh =
@@ -2569,38 +2592,47 @@
   i = 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;
     ++i;
 
-    if (EOF == input_stats(twopass, &next_frame)) break;
+    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 = read_frame_stats(twopass, 0);
+    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,
+        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(cpi, &next_frame));
+      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) {
-      last_loop_decay_rate = loop_decay_rate;
-      loop_decay_rate =
-          get_prediction_decay_rate(&cpi->frame_info, &next_frame);
+      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 (detect_transition_to_still(cpi, i, 5, loop_decay_rate,
-                                     last_loop_decay_rate)) {
-        allow_alt_ref = 0;
-        break;
+      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.
@@ -2607,9 +2639,10 @@
       // 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;
+        sr_accumulator += next_frame->coded_error;
       } else {
-        sr_accumulator += (next_frame.sr_coded_error - next_frame.coded_error);
+        sr_accumulator +=
+            (next_frame->sr_coded_error - next_frame->coded_error);
       }
     }
 
@@ -2636,7 +2669,7 @@
         (!flash_detected) &&
         ((mv_ratio_accumulator > mv_ratio_accumulator_thresh) ||
          (abs_mv_in_out_accumulator > abs_mv_in_out_thresh) ||
-         (sr_accumulator > gop_intra_factor * next_frame.intra_error))) {
+         (sr_accumulator > gop_intra_factor * next_frame->intra_error))) {
       break;
     }
   }
@@ -2648,12 +2681,19 @@
   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 forward_frames = (rc->frames_to_key - i >= i - 1)
-                                   ? i - 1
-                                   : VPXMAX(0, rc->frames_to_key - i);
+    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;
+    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));
 
     // Calculate the boost for alt ref.
-    rc->gfu_boost = calc_arf_boost(cpi, forward_frames, (i - 1));
+    rc->gfu_boost =
+        compute_arf_boost(frame_info, first_pass_info, arf_show_idx, f_frames,
+                          b_frames, avg_inter_frame_qindex);
     rc->source_alt_ref_pending = 1;
   } else {
     reset_fpf_position(twopass, start_pos);
@@ -3192,8 +3232,9 @@
       // Monitor for static sections.
       // First frame in kf group the second ref indicator is invalid.
       if (i > 0) {
-        zero_motion_accumulator = VPXMIN(
-            zero_motion_accumulator, get_zero_motion_factor(cpi, &next_frame));
+        zero_motion_accumulator =
+            VPXMIN(zero_motion_accumulator,
+                   get_zero_motion_factor(&cpi->frame_info, &next_frame));
       } else {
         zero_motion_accumulator =
             next_frame.pcnt_inter - next_frame.pcnt_motion;
@@ -3396,7 +3437,8 @@
 
   // Define a new GF/ARF group. (Should always enter here for key frames).
   if (rc->frames_till_gf_update_due == 0) {
-    define_gf_group(cpi);
+    const int gf_start_show_idx = cm->current_video_frame;
+    define_gf_group(cpi, gf_start_show_idx);
 
     rc->frames_till_gf_update_due = rc->baseline_gf_interval;
 
--- a/vp9/encoder/vp9_firstpass.h
+++ b/vp9/encoder/vp9_firstpass.h
@@ -158,6 +158,10 @@
   first_pass_info->num_frames = num_frames;
 }
 
+static INLINE int fps_get_num_frames(const FIRST_PASS_INFO *first_pass_info) {
+  return first_pass_info->num_frames;
+}
+
 static INLINE const FIRSTPASS_STATS *fps_get_frame_stats(
     const FIRST_PASS_INFO *first_pass_info, int show_idx) {
   if (show_idx >= first_pass_info->num_frames) {