Correct tpl boost combination with gfu_boost in LAP

As all stats may not be available for a lower lag_in_frames,
using frames_to_key in process_tpl_stats_frame would be incorrect
in case of LAP. Using number of stats actually used, for projection
and combination of gfu_boost in LAP.

STATS_CHANGED

Change-Id: I3825a6329f1b6671f90c59597895d7d0667dbaa1
(cherry picked from commit 28742ee3c7331274da2827fa65d3852c6853650e)
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 04e2bb3..42bf1e7 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -4012,6 +4012,26 @@
 }
 
 #if !CONFIG_REALTIME_ONLY
+#define MAX_GFUBOOST_FACTOR 10.0
+#define MIN_GFUBOOST_FACTOR 4.0
+static double get_gfu_boost_projection_factor(double min_factor,
+                                              double max_factor,
+                                              int frame_count) {
+  double factor = sqrt((double)frame_count);
+  factor = AOMMIN(factor, max_factor);
+  factor = AOMMAX(factor, min_factor);
+  factor = (200.0 + 10.0 * factor);
+  return factor;
+}
+
+static int get_gfu_boost_from_r0_lap(double min_factor, double max_factor,
+                                     double r0, int frames_to_key) {
+  double factor =
+      get_gfu_boost_projection_factor(min_factor, max_factor, frames_to_key);
+  const int boost = (int)rint(factor / r0);
+  return boost;
+}
+
 static double get_kf_boost_projection_factor(int frame_count) {
   double factor = sqrt((double)frame_count);
   factor = AOMMIN(factor, 10.0);
@@ -4026,6 +4046,31 @@
   return boost;
 }
 
+static int get_projected_prior_gfu_boost(AV1_COMP *cpi) {
+  int num_stats_used_for_gfu_boost = cpi->rc.num_stats_used_for_gfu_boost;
+  int frames_to_project = cpi->rc.num_stats_required_for_gfu_boost;
+
+  /*
+   * If frames_to_project is equal to num_stats_used_for_gfu_boost,
+   * it means that gfu_boost was calculated over frames_to_project to
+   * begin with(ie; all stats required were available), hence return
+   * the original boost.
+   */
+  if (num_stats_used_for_gfu_boost >= frames_to_project)
+    return cpi->rc.gfu_boost;
+
+  double min_boost_factor = sqrt(cpi->rc.baseline_gf_interval);
+  // Get the current tpl factor (number of frames = frames_to_project).
+  double tpl_factor = get_gfu_boost_projection_factor(
+      min_boost_factor, MAX_GFUBOOST_FACTOR, frames_to_project);
+  // Get the tpl factor when number of frames = num_stats_used_for_prior_boost.
+  double tpl_factor_num_stats = get_gfu_boost_projection_factor(
+      min_boost_factor, MAX_GFUBOOST_FACTOR, num_stats_used_for_gfu_boost);
+  int projected_gfu_boost =
+      (int)rint((tpl_factor * cpi->rc.gfu_boost) / tpl_factor_num_stats);
+  return projected_gfu_boost;
+}
+
 static int get_projected_prior_boost(AV1_COMP *cpi) {
   /*
    * If num_stats_used_for_kf_boost >= frames_to_key, then
@@ -4046,13 +4091,18 @@
 }
 #endif
 
-int combine_prior_with_tpl_boost(int prior_boost, int tpl_boost,
+#define MIN_BOOST_COMBINE_FACTOR 4.0
+#define MAX_BOOST_COMBINE_FACTOR 12.0
+int combine_prior_with_tpl_boost(double min_factor, double max_factor,
+                                 int prior_boost, int tpl_boost,
                                  int frames_to_key) {
   double factor = sqrt((double)frames_to_key);
-  factor = AOMMIN(factor, 12.0);
-  factor = AOMMAX(factor, 4.0);
-  factor -= 4.0;
-  int boost = (int)((factor * prior_boost + (8.0 - factor) * tpl_boost) / 8.0);
+  double range = max_factor - min_factor;
+  factor = AOMMIN(factor, max_factor);
+  factor = AOMMAX(factor, min_factor);
+  factor -= min_factor;
+  int boost =
+      (int)((factor * prior_boost + (range - factor) * tpl_boost) / range);
   return boost;
 }
 
@@ -4102,9 +4152,23 @@
       cpi->rd.r0 = (double)intra_cost_base / mc_dep_cost_base;
       if (is_frame_arf_and_tpl_eligible(gf_group)) {
         cpi->rd.arf_r0 = cpi->rd.r0;
-        const int gfu_boost = (int)(200.0 / cpi->rd.r0);
-        cpi->rc.gfu_boost = combine_prior_with_tpl_boost(
-            cpi->rc.gfu_boost, gfu_boost, cpi->rc.frames_to_key);
+        if (cpi->lap_enabled) {
+          double min_boost_factor = sqrt(cpi->rc.baseline_gf_interval);
+          const int gfu_boost = get_gfu_boost_from_r0_lap(
+              min_boost_factor, MAX_GFUBOOST_FACTOR, cpi->rd.arf_r0,
+              cpi->rc.num_stats_required_for_gfu_boost);
+          const int prior_boost = get_projected_prior_gfu_boost(cpi);
+          // printf("old boost %d new boost %d\n", prior_boost,
+          //        gfu_boost);
+          cpi->rc.gfu_boost = combine_prior_with_tpl_boost(
+              min_boost_factor, MAX_BOOST_COMBINE_FACTOR, prior_boost,
+              gfu_boost, cpi->rc.num_stats_used_for_gfu_boost);
+        } else {
+          const int gfu_boost = (int)(200.0 / cpi->rd.r0);
+          cpi->rc.gfu_boost = combine_prior_with_tpl_boost(
+              MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR,
+              cpi->rc.gfu_boost, gfu_boost, cpi->rc.frames_to_key);
+        }
       } else if (frame_is_intra_only(cm)) {
         // TODO(debargha): Turn off q adjustment for kf temporarily to
         // reduce impact on speed of encoding. Need to investigate how
@@ -4115,10 +4179,12 @@
           if (cpi->lap_enabled) {
             const int projected_prior_boost = get_projected_prior_boost(cpi);
             cpi->rc.kf_boost = combine_prior_with_tpl_boost(
+                MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR,
                 projected_prior_boost, kf_boost,
                 cpi->rc.num_stats_used_for_kf_boost);
           } else {
             cpi->rc.kf_boost = combine_prior_with_tpl_boost(
+                MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR,
                 cpi->rc.kf_boost, kf_boost, cpi->rc.frames_to_key);
           }
         }
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c
index 6889c83..210e894 100644
--- a/av1/encoder/gop_structure.c
+++ b/av1/encoder/gop_structure.c
@@ -47,8 +47,8 @@
       gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
       gf_group->frame_disp_idx[*frame_ind] = start;
       gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS;
-      gf_group->arf_boost[*frame_ind] =
-          av1_calc_arf_boost(twopass, rc, frame_info, start, end - start, 0);
+      gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
+          twopass, rc, frame_info, start, end - start, 0, NULL);
       gf_group->max_layer_depth =
           AOMMAX(gf_group->max_layer_depth, layer_depth);
       ++(*frame_ind);
@@ -64,8 +64,8 @@
     gf_group->layer_depth[*frame_ind] = layer_depth;
 
     // Get the boost factor for intermediate ARF frames.
-    gf_group->arf_boost[*frame_ind] =
-        av1_calc_arf_boost(twopass, rc, frame_info, m, end - m, m - start);
+    gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
+        twopass, rc, frame_info, m, end - m, m - start, NULL);
     ++(*frame_ind);
 
     // Frames displayed before this internal ARF.
diff --git a/av1/encoder/gop_structure.h b/av1/encoder/gop_structure.h
index 4637930..e76ba21 100644
--- a/av1/encoder/gop_structure.h
+++ b/av1/encoder/gop_structure.h
@@ -34,7 +34,7 @@
 
 int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc,
                        FRAME_INFO *frame_info, int offset, int f_frames,
-                       int b_frames);
+                       int b_frames, int *num_fpstats_used);
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 67d19e8..195f578 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -461,7 +461,7 @@
 #define MIN_DECAY_FACTOR 0.01
 int av1_calc_arf_boost(const TWO_PASS *twopass, const RATE_CONTROL *rc,
                        FRAME_INFO *frame_info, int offset, int f_frames,
-                       int b_frames) {
+                       int b_frames, int *num_fpstats_used) {
   int i;
   double boost_score = (double)NORMAL_BOOST;
   double mv_ratio_accumulator = 0.0;
@@ -471,6 +471,7 @@
   double abs_mv_in_out_accumulator = 0.0;
   int arf_boost;
   int flash_detected = 0;
+  if (num_fpstats_used) *num_fpstats_used = 0;
 
   // Search forward from the proposed arf/next gf position.
   for (i = 0; i < f_frames; ++i) {
@@ -498,6 +499,7 @@
     boost_score += decay_accumulator *
                    calc_frame_boost(rc, frame_info, this_frame,
                                     this_frame_mv_in_out, GF_MAX_BOOST);
+    if (num_fpstats_used) (*num_fpstats_used)++;
   }
 
   arf_boost = (int)boost_score;
@@ -536,6 +538,7 @@
     boost_score += decay_accumulator *
                    calc_frame_boost(rc, frame_info, this_frame,
                                     this_frame_mv_in_out, GF_MAX_BOOST);
+    if (num_fpstats_used) (*num_fpstats_used)++;
   }
   arf_boost += (int)boost_score;
 
@@ -1582,15 +1585,19 @@
                                    : AOMMAX(0, rc->frames_to_key - i);
 
     // Calculate the boost for alt ref.
-    rc->gfu_boost = av1_calc_arf_boost(twopass, rc, frame_info, alt_offset,
-                                       forward_frames, (i - 1));
+    rc->gfu_boost =
+        av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, forward_frames,
+                           (i - 1), &rc->num_stats_used_for_gfu_boost);
+    rc->num_stats_required_for_gfu_boost = (forward_frames + i - 1);
     rc->source_alt_ref_pending = 1;
     gf_group->max_layer_depth_allowed = cpi->oxcf.gf_max_pyr_height;
   } else {
     reset_fpf_position(twopass, start_pos);
-    rc->gfu_boost = AOMMIN(
-        MAX_GF_BOOST,
-        av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, (i - 1), 0));
+    rc->gfu_boost =
+        AOMMIN(MAX_GF_BOOST,
+               av1_calc_arf_boost(twopass, rc, frame_info, alt_offset, (i - 1),
+                                  0, &rc->num_stats_used_for_gfu_boost));
+    rc->num_stats_required_for_gfu_boost = (i - 1);
     rc->source_alt_ref_pending = 0;
     gf_group->max_layer_depth_allowed = 0;
   }
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 038eac8..05f11fb 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -175,6 +175,10 @@
 
   // Total number of stats used only for kf_boost calculation.
   int num_stats_used_for_kf_boost;
+  // Total number of stats used only for gfu_boost calculation.
+  int num_stats_used_for_gfu_boost;
+  // Total number of stats required by gfu_boost calculation.
+  int num_stats_required_for_gfu_boost;
 } RATE_CONTROL;
 
 struct AV1_COMP;