Adjust the boost for the intermediate arf.

This CL considers the fact that with constraints in reference frames,
the intermediate arf may be more impotant than previously
estimated. It changes to using a new strategy that counts the number
of frames that uses it as reference.

BUG=b/260859962

Change-Id: I2db227f40dddf2958c71eeed17232886c8df2ef6
diff --git a/av1/qmode_rc/ratectrl_qmode.cc b/av1/qmode_rc/ratectrl_qmode.cc
index 34b2782..f4b4887 100644
--- a/av1/qmode_rc/ratectrl_qmode.cc
+++ b/av1/qmode_rc/ratectrl_qmode.cc
@@ -1445,6 +1445,97 @@
   }
 }
 
+// Check whether a frame (with index frame_index) uses candidate_reference as a
+// reference frame.
+bool CheckFrameUseReference(
+    int frame_index, const GopFrame &frame, const GopFrame &candidate_reference,
+    const std::vector<RefFrameTable> &ref_frame_table_list) {
+  if (frame.update_type == GopFrameType::kOverlay ||
+      frame.update_type == GopFrameType::kIntermediateOverlay) {
+    return false;
+  }
+  for (const auto &ref_frame : frame.ref_frame_list) {
+    if (ref_frame_table_list[frame_index][ref_frame.index].global_coding_idx ==
+        candidate_reference.global_coding_idx) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Returns the number of frames that use this_frame as reference in the
+// current and next subGop.
+int CountUsedAsReference(const GopStruct &gop_struct,
+                         const std::vector<LookaheadStats> &lookahead_stats,
+                         const std::vector<RefFrameTable> &ref_frame_table_list,
+                         const GopFrame &this_frame) {
+  int num = 0;
+  const int frame_count = static_cast<int>(gop_struct.gop_frame_list.size());
+  // Check frames in this gop
+  for (int i = 0; i < frame_count; ++i) {
+    if (CheckFrameUseReference(i, gop_struct.gop_frame_list[i], this_frame,
+                               ref_frame_table_list)) {
+      ++num;
+    }
+  }
+  // Check frames in the next gop
+  if (!lookahead_stats.empty()) {
+    const auto &next_gop_frame_list =
+        lookahead_stats[0].gop_struct[0].gop_frame_list;
+    const int next_gop_frame_count =
+        static_cast<int>(next_gop_frame_list.size());
+    for (int i = 0; i < next_gop_frame_count; ++i) {
+      if (CheckFrameUseReference(frame_count + i, next_gop_frame_list[i],
+                                 this_frame, ref_frame_table_list)) {
+        ++num;
+      }
+    }
+  }
+  return num;
+}
+
+int GetIntArfQ(const GopStruct &gop_struct,
+               const std::vector<LookaheadStats> &lookahead_stats,
+               const std::vector<RefFrameTable> &ref_frame_table_list,
+               const GopFrame &arf_frame, const GopFrame &int_arf_frame,
+               int active_best_quality, int active_worst_quality) {
+  if (!arf_frame.is_valid) return active_best_quality;
+  assert(int_arf_frame.is_valid);
+
+  // Check whether this is the first intermediate arf
+  bool is_first_int_arf = false;
+  for (const auto &gop_frame : gop_struct.gop_frame_list) {
+    if (gop_frame.update_type == GopFrameType::kIntermediateArf) {
+      is_first_int_arf =
+          gop_frame.global_coding_idx == int_arf_frame.global_coding_idx;
+      break;
+    }
+  }
+  if (is_first_int_arf) {
+    // int_arf_frame is the first intermediate arf in the subGop
+    int arf_as_ref = CountUsedAsReference(gop_struct, lookahead_stats,
+                                          ref_frame_table_list, arf_frame);
+    int int_arf_as_ref = CountUsedAsReference(
+        gop_struct, lookahead_stats, ref_frame_table_list, int_arf_frame);
+    int arf_adjusted =
+        arf_as_ref + static_cast<int>(int_arf_as_ref * kIntArfAdjFactor);
+    if (arf_adjusted <= int_arf_as_ref) {
+      return active_best_quality;
+    } else {
+      assert(arf_adjusted > 0);
+      return active_best_quality +
+             (active_worst_quality - active_best_quality) *
+                 (arf_adjusted - int_arf_as_ref) / arf_adjusted;
+    }
+  } else {
+    // int_arf_frame is not the first intermediate arf in the subGop
+    assert(int_arf_frame.layer_depth >= 1);
+    const int depth_factor = 1 << (int_arf_frame.layer_depth - 1);
+    return (active_worst_quality * (depth_factor - 1) + active_best_quality) /
+           depth_factor;
+  }
+}
+
 StatusOr<GopEncodeInfo> AV1RateControlQMode::GetGopEncodeInfoWithNoStats(
     const GopStruct &gop_struct) {
   GopEncodeInfo gop_encode_info;
@@ -1479,7 +1570,13 @@
 
 StatusOr<GopEncodeInfo> AV1RateControlQMode::GetGopEncodeInfoWithFp(
     const GopStruct &gop_struct, const FirstpassInfo &firstpass_info,
-    const std::vector<LookaheadStats> &lookahead_stats) {
+    const std::vector<LookaheadStats> &lookahead_stats,
+    const RefFrameTable &ref_frame_table_snapshot_init) {
+  const std::vector<RefFrameTable> ref_frame_table_list = GetRefFrameTableList(
+      gop_struct, lookahead_stats, ref_frame_table_snapshot_init);
+  GopEncodeInfo gop_encode_info;
+  gop_encode_info.final_snapshot = ref_frame_table_list.back();
+
   const int stats_size = static_cast<int>(firstpass_info.stats_list.size());
   const FirstpassInfo analyzed_fp_info =
       AnalyzeFpStats(std::move(firstpass_info));
@@ -1496,7 +1593,7 @@
     return status;
   }
 
-  GopEncodeInfo gop_encode_info;
+  GopFrame arf_frame = GopFrameInvalid();
   const int frame_count = static_cast<int>(gop_struct.gop_frame_list.size());
   const int active_worst_quality = rc_param_.base_q_index;
   int active_best_quality = rc_param_.base_q_index;
@@ -1605,13 +1702,14 @@
                                                        qstep_ratio, AOM_BITS_8);
       if (rc_param_.base_q_index) param.q_index = std::max(param.q_index, 1);
       active_best_quality = param.q_index;
+
+      if (gop_frame.update_type == GopFrameType::kRegularArf) {
+        arf_frame = gop_frame;
+      }
     } else {
-      // Intermediate ARFs
-      assert(gop_frame.layer_depth >= 1);
-      const int depth_factor = 1 << (gop_frame.layer_depth - 1);
-      param.q_index =
-          (active_worst_quality * (depth_factor - 1) + active_best_quality) /
-          depth_factor;
+      param.q_index = GetIntArfQ(gop_struct, lookahead_stats,
+                                 ref_frame_table_list, arf_frame, gop_frame,
+                                 active_best_quality, active_worst_quality);
     }
     param.rdmult = GetRDMult(gop_frame, param.q_index);
     gop_encode_info.param_list.push_back(param);
@@ -1717,6 +1815,7 @@
         }
       }
     } else {
+      // TODO(b/259601830): Also consider using GetIntArfQ here.
       // Intermediate ARFs
       assert(gop_frame.layer_depth >= 1);
       const int depth_factor = 1 << (gop_frame.layer_depth - 1);
diff --git a/av1/qmode_rc/ratectrl_qmode.h b/av1/qmode_rc/ratectrl_qmode.h
index be99db2..375305f 100644
--- a/av1/qmode_rc/ratectrl_qmode.h
+++ b/av1/qmode_rc/ratectrl_qmode.h
@@ -25,6 +25,7 @@
 constexpr int kLayerDepthOffset = 1;
 constexpr int kMinIntervalToAddArf = 3;
 constexpr int kMinArfInterval = (kMinIntervalToAddArf + 1) / 2;
+constexpr double kIntArfAdjFactor = 0.5;
 
 struct TplUnitDepStats {
   double propagation_cost;
@@ -137,7 +138,8 @@
       const GopStruct &gop_struct);
   StatusOr<GopEncodeInfo> GetGopEncodeInfoWithFp(
       const GopStruct &gop_struct, const FirstpassInfo &firstpass_info,
-      const std::vector<LookaheadStats> &lookahead_stats);
+      const std::vector<LookaheadStats> &lookahead_stats,
+      const RefFrameTable &ref_frame_table_snapshot_init);
   StatusOr<GopEncodeInfo> GetGopEncodeInfoWithTpl(
       const GopStruct &gop_struct, const TplGopStats &tpl_gop_stats,
       const std::vector<LookaheadStats> &lookahead_stats,