Separate gf length from define_gf_group.

The gf group length decision is now separated from the
define_gf_group function. Also we can now determine the length
in batch, and store them for future use. This enables lookahead
in future commits.

Change-Id: Ifc13c21c20e06a93dd7db871a178dfdab05bc8f7
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 573b65d..7c8cfe5 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -782,12 +782,177 @@
 }
 
 #define ARF_ABS_ZOOM_THRESH 4.4
+static INLINE int detect_gf_cut(AV1_COMP *cpi, int frame_index, int cur_start,
+                                int flash_detected, double loop_decay_rate,
+                                double last_loop_decay_rate,
+                                int active_max_gf_interval,
+                                int active_min_gf_interval,
+                                double zero_motion_accumulator,
+                                double mv_ratio_accumulator,
+                                double abs_mv_in_out_accumulator) {
+  RATE_CONTROL *const rc = &cpi->rc;
+  TWO_PASS *const twopass = &cpi->twopass;
+  // Motion breakout threshold for loop below depends on image size.
+  const double mv_ratio_accumulator_thresh =
+      (cpi->initial_height + cpi->initial_width) / 4.0;
+
+  if (!flash_detected) {
+    // 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, frame_index - cur_start, 5,
+                                   loop_decay_rate, last_loop_decay_rate)) {
+      return 1;
+    }
+  }
+
+  // Some conditions to breakout after min interval.
+  if (frame_index - cur_start >= active_min_gf_interval &&
+      // If possible don't break very close to a kf
+      (rc->frames_to_key - frame_index >= rc->min_gf_interval) &&
+      ((frame_index - cur_start) & 0x01) && !flash_detected &&
+      (mv_ratio_accumulator > mv_ratio_accumulator_thresh ||
+       abs_mv_in_out_accumulator > ARF_ABS_ZOOM_THRESH)) {
+    return 1;
+  }
+
+  // If almost totally static, we will not use the the max GF length later,
+  // so we can continue for more frames.
+  if (((frame_index - cur_start) >= active_max_gf_interval + 1) &&
+      !is_almost_static(zero_motion_accumulator, twopass->kf_zeromotion_pct)) {
+    return 1;
+  }
+  return 0;
+}
+
 #define GROUP_ADAPTIVE_MAXQ 1
 #if GROUP_ADAPTIVE_MAXQ
 #define RC_FACTOR_MIN 0.75
 #define RC_FACTOR_MAX 1.25
 #endif  // GROUP_ADAPTIVE_MAXQ
 #define MIN_FWD_KF_INTERVAL 8
+// This function decides the gf group length of future frames in batch
+// rc->gf_intervals is modified to store the group lengths
+static void calculate_gf_length(AV1_COMP *cpi) {
+  RATE_CONTROL *const rc = &cpi->rc;
+  AV1EncoderConfig *const oxcf = &cpi->oxcf;
+  TWO_PASS *const twopass = &cpi->twopass;
+  FIRSTPASS_STATS next_frame;
+  const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+  FRAME_INFO *frame_info = &cpi->frame_info;
+  int i;
+
+  double mv_ratio_accumulator = 0.0;
+  double zero_motion_accumulator = 1.0;
+
+  double this_frame_mv_in_out = 0.0;
+  double mv_in_out_accumulator = 0.0;
+  double abs_mv_in_out_accumulator = 0.0;
+
+  int flash_detected;
+  double loop_decay_rate = 1.00;
+  double last_loop_decay_rate = 1.00;
+
+  aom_clear_system_state();
+  av1_zero(next_frame);
+
+  if (has_no_stats_stage(cpi)) {
+    for (i = 0; i < NUM_GF_INTERVALS; i++) {
+      rc->gf_intervals[i] = MAX_GF_INTERVAL;
+    }
+    rc->cur_gf_index = 0;
+    rc->intervals_till_gf_calculate_due = NUM_GF_INTERVALS;
+    return;
+  }
+
+  // TODO(urvang): Try logic to vary min and max interval based on q.
+  const int active_min_gf_interval = rc->min_gf_interval;
+  const int active_max_gf_interval =
+      AOMMIN(rc->max_gf_interval, get_fixed_gf_length(oxcf->gf_max_pyr_height));
+
+  i = 0;
+  const int max_intervals = NUM_GF_INTERVALS;
+  int cut_pos[NUM_GF_INTERVALS + 1] = { 0 };
+  int count_cuts = 1;
+  int cur_start = 0, cur_last;
+  int cut_here;
+  while (count_cuts < max_intervals + 1) {
+    ++i;
+
+    // reaches next key frame, break here
+    if (i >= rc->frames_to_key) {
+      cut_pos[count_cuts] = i - 1;
+      count_cuts++;
+      break;
+    }
+
+    // reached maximum len, but nothing special yet (almost static)
+    // let's look at the next interval
+    if (i - cur_start >= rc->static_scene_max_gf_interval) {
+      cut_here = 1;
+    } else {
+      // reaches last frame, break
+      if (EOF == input_stats(twopass, &next_frame)) {
+        cut_pos[count_cuts] = i - 1;
+        count_cuts++;
+        break;
+      }
+      // 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);
+
+      // Test for the case where there is a brief flash but the prediction
+      // quality back to an earlier frame is then restored.
+      flash_detected = detect_flash(twopass, 0);
+      // Monitor for static sections.
+      if (!flash_detected) {
+        last_loop_decay_rate = loop_decay_rate;
+        loop_decay_rate = get_prediction_decay_rate(frame_info, &next_frame);
+
+        if ((rc->frames_since_key + i - 1) > 1) {
+          zero_motion_accumulator =
+              AOMMIN(zero_motion_accumulator,
+                     get_zero_motion_factor(frame_info, &next_frame));
+        }
+      }
+      cut_here =
+          detect_gf_cut(cpi, i, cur_start, flash_detected, loop_decay_rate,
+                        last_loop_decay_rate, active_max_gf_interval,
+                        active_min_gf_interval, zero_motion_accumulator,
+                        mv_ratio_accumulator, abs_mv_in_out_accumulator);
+    }
+    if (cut_here) {
+      cur_last = i - 1;  // the current last frame in the gf group
+
+      cut_pos[count_cuts] = cur_last;
+      count_cuts++;
+
+      // reset pointers to the shrinked location
+      twopass->stats_in = start_pos + cur_last;
+      cur_start = cur_last;
+      i = cur_last;
+
+      // reset accumulators
+      mv_ratio_accumulator = 0.0;
+      zero_motion_accumulator = 1.0;
+
+      this_frame_mv_in_out = 0.0;
+      mv_in_out_accumulator = 0.0;
+      abs_mv_in_out_accumulator = 0.0;
+
+      loop_decay_rate = 1.00;
+      last_loop_decay_rate = 1.00;
+    }
+  }
+
+  // save intervals
+  rc->intervals_till_gf_calculate_due = count_cuts - 1;
+  for (int n = 1; n < count_cuts; n++) {
+    rc->gf_intervals[n - 1] = cut_pos[n] + 1 - cut_pos[n - 1];
+  }
+  rc->cur_gf_index = 0;
+  twopass->stats_in = start_pos;
+}
 
 static void define_gf_group_pass0(AV1_COMP *cpi,
                                   const EncodeFrameParams *const frame_params) {
@@ -795,10 +960,13 @@
   GF_GROUP *const gf_group = &cpi->gf_group;
   int target;
 
-  if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ)
+  if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) {
     av1_cyclic_refresh_set_golden_update(cpi);
-  else
-    rc->baseline_gf_interval = MAX_GF_INTERVAL;
+  } else {
+    rc->baseline_gf_interval = rc->gf_intervals[rc->cur_gf_index];
+    rc->intervals_till_gf_calculate_due--;
+    rc->cur_gf_index++;
+  }
 
   if (rc->baseline_gf_interval > rc->frames_to_key)
     rc->baseline_gf_interval = rc->frames_to_key;
@@ -918,9 +1086,6 @@
     gf_group_skip_pct -= this_frame->intra_skip_pct;
     gf_group_inactive_zone_rows -= this_frame->inactive_zone_rows;
   }
-  // Motion breakout threshold for loop below depends on image size.
-  const double mv_ratio_accumulator_thresh =
-      (cpi->initial_height + cpi->initial_width) / 4.0;
 
   // TODO(urvang): Try logic to vary min and max interval based on q.
   const int active_min_gf_interval = rc->min_gf_interval;
@@ -941,7 +1106,8 @@
   int non_zero_stdev_count = 0;
 
   i = 0;
-  while (i < rc->static_scene_max_gf_interval && i < rc->frames_to_key) {
+  // get the determined gf group length from rc->gf_intervals
+  while (i < rc->gf_intervals[rc->cur_gf_index]) {
     ++i;
 
     // Accumulate error score of frames in this gf group.
@@ -995,29 +1161,12 @@
       if (detect_transition_to_still(cpi, i, 5, loop_decay_rate,
                                      last_loop_decay_rate)) {
         allow_alt_ref = 0;
-        break;
       }
     }
-
-    // If almost totally static, we will not use the the max GF length later,
-    // so we can continue for more frames.
-    if ((i >= active_max_gf_interval + 1) &&
-        !is_almost_static(zero_motion_accumulator,
-                          twopass->kf_zeromotion_pct)) {
-      break;
-    }
-
-    // Some conditions to breakout after min interval.
-    if (i >= active_min_gf_interval &&
-        // If possible don't 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)) {
-      break;
-    }
     *this_frame = next_frame;
   }
+  rc->intervals_till_gf_calculate_due--;
+  rc->cur_gf_index++;
 
   // Was the group length constrained by the requirement for a new KF?
   rc->constrained_gf_group = (i >= rc->frames_to_key) ? 1 : 0;
@@ -1439,6 +1588,7 @@
 
   // KF is always a GF so clear frames till next gf counter.
   rc->frames_till_gf_update_due = 0;
+  rc->intervals_till_gf_calculate_due = 0;
 
   rc->frames_to_key = 1;
 
@@ -1871,6 +2021,10 @@
   if (rc->frames_till_gf_update_due == 0) {
     assert(cpi->common.current_frame.frame_number == 0 ||
            gf_group->index == gf_group->size);
+    if (rc->intervals_till_gf_calculate_due == 0) {
+      calculate_gf_length(cpi);
+    }
+
     define_gf_group(cpi, &this_frame, frame_params);
     rc->frames_till_gf_update_due = rc->baseline_gf_interval;
     cpi->num_gf_group_show_frames = 0;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 72e473d..cc95e97 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -48,6 +48,8 @@
 #define MAX_GF_INTERVAL 16
 #define FIXED_GF_INTERVAL 8  // Used in some testing modes only
 
+#define NUM_GF_INTERVALS 150
+
 typedef struct {
   int resize_width;
   int resize_height;
@@ -95,6 +97,14 @@
 
   int frames_since_golden;
   int frames_till_gf_update_due;
+
+  // number of determined gf group length left
+  int intervals_till_gf_calculate_due;
+  // stores gf group length intervals
+  int gf_intervals[NUM_GF_INTERVALS];
+  // the current index in gf_intervals
+  int cur_gf_index;
+
   int min_gf_interval;
   int max_gf_interval;
   int static_scene_max_gf_interval;