Extend selective_ref_frame sf to prune LAST2 ref frame

LAST2 reference frame is pruned based on the temporal
distance and first-pass stats.

         Instruction Count       BD-Rate Loss(%)
cpu-used   Reduction(%)    avg.psnr  ovr.psnr  ssim
   6          2.739        0.1308    0.1272    0.0697

STATS_CHANGED for speed 6

Change-Id: I53a943a876da1e0c0bf76d26793a5acd2621e9c7
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index c121d27..c119924 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1562,7 +1562,9 @@
   }
 
   av1_setup_frame_buf_refs(cm);
-  enforce_max_ref_frames(cpi, &cpi->ref_frame_flags);
+  enforce_max_ref_frames(cpi, &cpi->ref_frame_flags,
+                         cm->cur_frame->ref_display_order_hint,
+                         cm->current_frame.display_order_hint);
   set_rel_frame_dist(&cpi->common, &cpi->ref_frame_dist_info,
                      cpi->ref_frame_flags);
   av1_setup_frame_sign_bias(cm);
diff --git a/av1/encoder/encodeframe_utils.h b/av1/encoder/encodeframe_utils.h
index 55318aa..d1146f5 100644
--- a/av1/encoder/encodeframe_utils.h
+++ b/av1/encoder/encodeframe_utils.h
@@ -320,6 +320,92 @@
                            const TileInfo *const tile_info, const int mi_row,
                            const int mi_col);
 
+// This function will compute the number of reference frames to be disabled
+// based on selective_ref_frame speed feature.
+static AOM_INLINE unsigned int get_num_refs_to_disable(
+    const AV1_COMP *cpi, const int *ref_frame_flags,
+    const unsigned int *ref_display_order_hint,
+    unsigned int cur_frame_display_index) {
+  unsigned int num_refs_to_disable = 0;
+  if (cpi->sf.inter_sf.selective_ref_frame >= 3) {
+    num_refs_to_disable++;
+    if (cpi->sf.inter_sf.selective_ref_frame >= 5 &&
+        *ref_frame_flags & av1_ref_frame_flag_list[LAST2_FRAME]) {
+      const OrderHintInfo *const order_hint_info =
+          &cpi->common.seq_params.order_hint_info;
+      const int last2_frame_dist = av1_encoder_get_relative_dist(
+          order_hint_info, ref_display_order_hint[LAST2_FRAME - LAST_FRAME],
+          cur_frame_display_index);
+      // Disable LAST2_FRAME if it is a temporally distant frame
+      if (abs(last2_frame_dist) > 2) {
+        num_refs_to_disable++;
+      }
+#if !CONFIG_REALTIME_ONLY
+      else if (is_stat_consumption_stage_twopass(cpi)) {
+        const FIRSTPASS_STATS *const this_frame_stats =
+            read_one_frame_stats(&cpi->twopass, cur_frame_display_index);
+        const double coded_error_per_mb =
+            this_frame_stats->coded_error / cpi->frame_info.num_mbs;
+        // Disable LAST2_FRAME if the coded error of the current frame based on
+        // first pass stats is very low.
+        if (coded_error_per_mb < 100.0) num_refs_to_disable++;
+      }
+#endif  // CONFIG_REALTIME_ONLY
+    }
+  }
+  return num_refs_to_disable;
+}
+
+static INLINE int get_max_allowed_ref_frames(
+    const AV1_COMP *cpi, const int *ref_frame_flags,
+    const unsigned int *ref_display_order_hint,
+    unsigned int cur_frame_display_index) {
+  const unsigned int max_reference_frames =
+      cpi->oxcf.ref_frm_cfg.max_reference_frames;
+  const unsigned int num_refs_to_disable = get_num_refs_to_disable(
+      cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
+  const unsigned int max_allowed_refs_for_given_speed =
+      INTER_REFS_PER_FRAME - num_refs_to_disable;
+  return AOMMIN(max_allowed_refs_for_given_speed, max_reference_frames);
+}
+
+// Enforce the number of references for each arbitrary frame based on user
+// options and speed.
+static AOM_INLINE void enforce_max_ref_frames(
+    AV1_COMP *cpi, int *ref_frame_flags,
+    const unsigned int *ref_display_order_hint,
+    unsigned int cur_frame_display_index) {
+  MV_REFERENCE_FRAME ref_frame;
+  int total_valid_refs = 0;
+
+  for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
+    if (*ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
+      total_valid_refs++;
+    }
+  }
+
+  const int max_allowed_refs = get_max_allowed_ref_frames(
+      cpi, ref_frame_flags, ref_display_order_hint, cur_frame_display_index);
+
+  for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) {
+    const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i];
+
+    if (!(*ref_frame_flags & av1_ref_frame_flag_list[ref_frame_to_disable])) {
+      continue;
+    }
+
+    switch (ref_frame_to_disable) {
+      case LAST3_FRAME: *ref_frame_flags &= ~AOM_LAST3_FLAG; break;
+      case LAST2_FRAME: *ref_frame_flags &= ~AOM_LAST2_FLAG; break;
+      case ALTREF2_FRAME: *ref_frame_flags &= ~AOM_ALT2_FLAG; break;
+      case GOLDEN_FRAME: *ref_frame_flags &= ~AOM_GOLD_FLAG; break;
+      default: assert(0);
+    }
+    --total_valid_refs;
+  }
+  assert(total_valid_refs <= max_allowed_refs);
+}
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index da11708..e1d0142 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -3050,14 +3050,6 @@
   GOLDEN_FRAME,
 };
 
-static INLINE int get_max_allowed_ref_frames(
-    int selective_ref_frame, unsigned int max_reference_frames) {
-  const unsigned int max_allowed_refs_for_given_speed =
-      (selective_ref_frame >= 3) ? INTER_REFS_PER_FRAME - 1
-                                 : INTER_REFS_PER_FRAME;
-  return AOMMIN(max_allowed_refs_for_given_speed, max_reference_frames);
-}
-
 static const MV_REFERENCE_FRAME
     ref_frame_priority_order[INTER_REFS_PER_FRAME] = {
       LAST_FRAME,    ALTREF_FRAME, BWDREF_FRAME, GOLDEN_FRAME,
@@ -3092,42 +3084,6 @@
   return flags;
 }
 
-// Enforce the number of references for each arbitrary frame based on user
-// options and speed.
-static AOM_INLINE void enforce_max_ref_frames(AV1_COMP *cpi,
-                                              int *ref_frame_flags) {
-  MV_REFERENCE_FRAME ref_frame;
-  int total_valid_refs = 0;
-
-  for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
-    if (*ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
-      total_valid_refs++;
-    }
-  }
-
-  const int max_allowed_refs =
-      get_max_allowed_ref_frames(cpi->sf.inter_sf.selective_ref_frame,
-                                 cpi->oxcf.ref_frm_cfg.max_reference_frames);
-
-  for (int i = 0; i < 4 && total_valid_refs > max_allowed_refs; ++i) {
-    const MV_REFERENCE_FRAME ref_frame_to_disable = disable_order[i];
-
-    if (!(*ref_frame_flags & av1_ref_frame_flag_list[ref_frame_to_disable])) {
-      continue;
-    }
-
-    switch (ref_frame_to_disable) {
-      case LAST3_FRAME: *ref_frame_flags &= ~AOM_LAST3_FLAG; break;
-      case LAST2_FRAME: *ref_frame_flags &= ~AOM_LAST2_FLAG; break;
-      case ALTREF2_FRAME: *ref_frame_flags &= ~AOM_ALT2_FLAG; break;
-      case GOLDEN_FRAME: *ref_frame_flags &= ~AOM_GOLD_FLAG; break;
-      default: assert(0);
-    }
-    --total_valid_refs;
-  }
-  assert(total_valid_refs <= max_allowed_refs);
-}
-
 // Returns a Sequence Header OBU stored in an aom_fixed_buf_t, or NULL upon
 // failure. When a non-NULL aom_fixed_buf_t pointer is returned by this
 // function, the memory must be freed by the caller. Both the buf member of the
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 52fd85b..8e6dc70 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -681,6 +681,7 @@
   if (speed >= 6) {
     sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 0 : 3;
     sf->inter_sf.prune_nearmv_using_neighbors = 1;
+    sf->inter_sf.selective_ref_frame = 5;
 
     sf->part_sf.prune_rectangular_split_based_on_qidx =
         boosted || allow_screen_content_tools ? 0 : 1;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index f3425b3..04df3d8 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -581,8 +581,8 @@
   int prune_inter_modes_if_skippable;
 
   // Drop less likely to be picked reference frames in the RD search.
-  // Has five levels for now: 0, 1, 2, 3 and 4, where higher levels prune more
-  // aggressively than lower ones. (0 means no pruning).
+  // Has six levels for now: 0, 1, 2, 3, 4 and 5, where higher levels prune
+  // more aggressively than lower ones. (0 means no pruning).
   int selective_ref_frame;
 
   // Prune reference frames for rectangular partitions.
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index aa6fa6a..b72ee68 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -26,6 +26,7 @@
 
 #include "av1/encoder/encoder.h"
 #include "av1/encoder/ethread.h"
+#include "av1/encoder/encodeframe_utils.h"
 #include "av1/encoder/encode_strategy.h"
 #include "av1/encoder/hybrid_fwd_txfm.h"
 #include "av1/encoder/rd.h"
@@ -800,7 +801,8 @@
   ref_frame_flags = get_ref_frame_flags(&cpi->sf, ref_frames_ordered,
                                         cpi->ext_flags.ref_frame_flags);
 
-  enforce_max_ref_frames(cpi, &ref_frame_flags);
+  enforce_max_ref_frames(cpi, &ref_frame_flags, ref_frame_display_indices,
+                         tpl_frame->frame_display_index);
 
   // Prune reference frames
   for (idx = 0; idx < INTER_REFS_PER_FRAME; ++idx) {