Rework codec to improve performance for Shorts videos

BUG=b/435747631

STATS_CHANGED

Change-Id: I774b30ef4281f0c1db85ee21a06eb96e61aaf0cd
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 8256e39..4dc4258 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -3981,6 +3981,7 @@
   section->frame_avg_wavelet_energy -= frame->frame_avg_wavelet_energy;
   section->coded_error -= frame->coded_error;
   section->sr_coded_error -= frame->sr_coded_error;
+  section->lt_coded_error -= frame->lt_coded_error;
   section->pcnt_inter -= frame->pcnt_inter;
   section->pcnt_motion -= frame->pcnt_motion;
   section->pcnt_second_ref -= frame->pcnt_second_ref;
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 552c342..a49db4a 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -97,6 +97,7 @@
   section->log_intra_error = 0.0;
   section->log_coded_error = 0.0;
   section->sr_coded_error = 0.0;
+  section->lt_coded_error = 0.0;
   section->pcnt_inter = 0.0;
   section->pcnt_motion = 0.0;
   section->pcnt_second_ref = 0.0;
@@ -129,6 +130,7 @@
   section->frame_avg_wavelet_energy += frame->frame_avg_wavelet_energy;
   section->coded_error += frame->coded_error;
   section->sr_coded_error += frame->sr_coded_error;
+  section->lt_coded_error += frame->lt_coded_error;
   section->pcnt_inter += frame->pcnt_inter;
   section->pcnt_motion += frame->pcnt_motion;
   section->pcnt_second_ref += frame->pcnt_second_ref;
@@ -702,7 +704,8 @@
 //    this_inter_error
 static int firstpass_inter_prediction(
     AV1_COMP *cpi, ThreadData *td, const YV12_BUFFER_CONFIG *const last_frame,
-    const YV12_BUFFER_CONFIG *const golden_frame, const int unit_row,
+    const YV12_BUFFER_CONFIG *const golden_frame,
+    const YV12_BUFFER_CONFIG *const last2_frame, const int unit_row,
     const int unit_col, const int recon_yoffset, const int recon_uvoffset,
     const int src_yoffset, const BLOCK_SIZE fp_block_size,
     const int this_intra_error, const int raw_motion_err_counts,
@@ -770,6 +773,19 @@
     }
   }
 
+  int last2_motion_error = motion_error;
+  if ((current_frame->frame_number > 2) && last2_frame != NULL) {
+    FULLPEL_MV tmp_mv = kZeroFullMv;
+    // Assume 0,0 motion with no mv overhead.
+    av1_setup_pre_planes(xd, 0, last2_frame, 0, 0, NULL, 1);
+    xd->plane[0].pre[0].buf += recon_yoffset;
+    last2_motion_error =
+        get_prediction_error_bitdepth(is_high_bitdepth, bitdepth, bsize,
+                                      &x->plane[0].src, &xd->plane[0].pre[0]);
+    first_pass_motion_search(cpi, x, &kZeroMv, &tmp_mv, &last2_motion_error);
+    stats->lt_coded_error += AOMMIN(last2_motion_error, this_intra_error);
+  }
+
   // Motion search in 2nd reference frame.
   int gf_motion_error = motion_error;
   if ((current_frame->frame_number > 1) && golden_frame != NULL) {
@@ -859,6 +875,7 @@
                                       double f_h) {
   fps->coded_error /= num_mbs_16x16;
   fps->sr_coded_error /= num_mbs_16x16;
+  fps->lt_coded_error /= num_mbs_16x16;
   fps->intra_error /= num_mbs_16x16;
   fps->frame_avg_wavelet_energy /= num_mbs_16x16;
   fps->log_coded_error = log1p(fps->coded_error);
@@ -914,6 +931,7 @@
   fps.frame = frame_number;
   fps.coded_error = (double)(stats->coded_error >> 8) + min_err;
   fps.sr_coded_error = (double)(stats->sr_coded_error >> 8) + min_err;
+  fps.lt_coded_error = (double)(stats->lt_coded_error >> 8) + min_err;
   fps.intra_error = (double)(stats->intra_error >> 8) + min_err;
   fps.frame_avg_wavelet_energy = (double)stats->frame_avg_wavelet_energy;
   fps.count = 1.0;
@@ -1033,6 +1051,7 @@
       stats.new_mv_count += mb_stat.new_mv_count;
       stats.second_ref_count += mb_stat.second_ref_count;
       stats.sr_coded_error += mb_stat.sr_coded_error;
+      stats.lt_coded_error += mb_stat.lt_coded_error;
       stats.sum_in_vectors += mb_stat.sum_in_vectors;
       stats.sum_mvc += mb_stat.sum_mvc;
       stats.sum_mvc_abs += mb_stat.sum_mvc_abs;
@@ -1150,6 +1169,10 @@
   if (!golden_frame) {
     golden_frame = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
   }
+  const YV12_BUFFER_CONFIG *last2_frame =
+      av1_get_scaled_ref_frame(cpi, LAST2_FRAME);
+  if (!last2_frame) last2_frame = get_ref_frame_yv12_buf(cm, LAST2_FRAME);
+
   YV12_BUFFER_CONFIG *const this_frame = &cm->cur_frame->buf;
 
   PICK_MODE_CONTEXT *ctx = td->firstpass_ctx;
@@ -1223,10 +1246,10 @@
 
     if (!frame_is_intra_only(cm)) {
       const int this_inter_error = firstpass_inter_prediction(
-          cpi, td, last_frame, golden_frame, unit_row, unit_col, recon_yoffset,
-          recon_uvoffset, src_yoffset, fp_block_size, this_intra_error,
-          raw_motion_err_counts, raw_motion_err_list, best_ref_mv, &best_ref_mv,
-          &last_mv, mb_stats);
+          cpi, td, last_frame, golden_frame, last2_frame, unit_row, unit_col,
+          recon_yoffset, recon_uvoffset, src_yoffset, fp_block_size,
+          this_intra_error, raw_motion_err_counts, raw_motion_err_list,
+          best_ref_mv, &best_ref_mv, &last_mv, mb_stats);
       if (unit_col_in_tile == 0) {
         *first_top_mv = last_mv;
       }
@@ -1235,6 +1258,7 @@
     } else {
       mb_stats->sr_coded_error += this_intra_error;
       mb_stats->coded_error += this_intra_error;
+      mb_stats->lt_coded_error += this_intra_error;
     }
 
     // Adjust to the next column of MBs.
@@ -1289,7 +1313,8 @@
   const int qindex = find_fp_qindex(seq_params->bit_depth);
   const int ref_frame_flags_backup = cpi->ref_frame_flags;
   cpi->ref_frame_flags = av1_ref_frame_flag_list[LAST_FRAME] |
-                         av1_ref_frame_flag_list[GOLDEN_FRAME];
+                         av1_ref_frame_flag_list[GOLDEN_FRAME] |
+                         av1_ref_frame_flag_list[LAST2_FRAME];
 
   // Detect if the key frame is screen content type.
   if (frame_is_intra_only(cm)) {
@@ -1343,6 +1368,8 @@
 
   const YV12_BUFFER_CONFIG *last_frame = NULL;
   const YV12_BUFFER_CONFIG *golden_frame = NULL;
+  const YV12_BUFFER_CONFIG *last2_frame = NULL;
+
   if (!frame_is_intra_only(cm)) {
     av1_scale_references(cpi, EIGHTTAP_REGULAR, 0, 0);
     last_frame = av1_is_scaled(get_ref_scale_factors_const(cm, LAST_FRAME))
@@ -1351,6 +1378,9 @@
     golden_frame = av1_is_scaled(get_ref_scale_factors_const(cm, GOLDEN_FRAME))
                        ? av1_get_scaled_ref_frame(cpi, GOLDEN_FRAME)
                        : get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
+    last2_frame = av1_is_scaled(get_ref_scale_factors_const(cm, LAST2_FRAME))
+                      ? av1_get_scaled_ref_frame(cpi, LAST2_FRAME)
+                      : get_ref_frame_yv12_buf(cm, LAST2_FRAME);
   }
 
   YV12_BUFFER_CONFIG *const this_frame = &cm->cur_frame->buf;
@@ -1440,6 +1470,12 @@
                          current_frame->frame_number, ts_duration,
                          fp_block_size);
 
+  if (this_frame_stats->pcnt_inter < 0.2 && last2_frame != NULL) {
+    assign_frame_buffer_p(
+        &cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST2_FRAME)],
+        cm->ref_frame_map[get_ref_frame_map_idx(cm, GOLDEN_FRAME)]);
+  }
+
   // Copy the previous Last Frame back into gf buffer if the prediction is good
   // enough... but also don't allow it to lag too far.
   if ((twopass->sr_update_lag > 3) ||
@@ -1472,6 +1508,13 @@
         cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]);
   }
 
+  if (current_frame->frame_number == 0 &&
+      get_ref_frame_map_idx(cm, LAST2_FRAME) != INVALID_IDX) {
+    assign_frame_buffer_p(
+        &cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST2_FRAME)],
+        cm->ref_frame_map[get_ref_frame_map_idx(cm, LAST_FRAME)]);
+  }
+
   print_reconstruction_frame(last_frame, current_frame->frame_number,
                              /*do_print=*/0);
 
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index a1b7e7d..d4b6ef1 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -69,6 +69,10 @@
    */
   double sr_coded_error;
   /*!
+   * Best of intra pred error and inter pred error using long term frame as ref.
+   */
+  double lt_coded_error;
+  /*!
    * Percentage of blocks with inter pred error < intra pred error.
    */
   double pcnt_inter;
@@ -482,6 +486,9 @@
   int64_t coded_error;
   // Best of intra pred error and inter pred error using golden frame as ref.
   int64_t sr_coded_error;
+  // Best of coded error using long term reference.
+  int64_t lt_coded_error;
+
   // Count of motion vector.
   int mv_count;
   // Count of blocks that pick inter prediction (inter pred error is smaller
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index a109109..a1d6640 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2985,6 +2985,7 @@
                           : cpi->common.mi_params.MBs;
   const int future_stats_count =
       av1_firstpass_info_future_count(firstpass_info, 0);
+
   while (frames_to_key < future_stats_count &&
          frames_to_key < num_frames_to_detect_scenecut) {
     // Provided that we are not at the end of the file...
@@ -2999,7 +3000,19 @@
             oxcf->rc_cfg.mode, cpi->ppi->p_rc.enable_scenecut_detection,
             num_mbs);
         if (scenecut_detected) {
-          break;
+          int test_next_gop = 0;
+
+          for (int idx = 0; idx < 32; ++idx) {
+            const FIRSTPASS_STATS *next_stats =
+                av1_firstpass_info_peek(firstpass_info, frames_to_key + idx);
+
+            if (next_stats == NULL) continue;
+
+            if (next_stats->lt_coded_error * 2.5 < next_stats->coded_error)
+              test_next_gop = 1;
+          }
+
+          if (!test_next_gop) break;
         }
       }