Commit a1d24bae45 for aom

commit a1d24bae455a25fc30a3a738a5347711af49a9c3
Author: Marco Paniconi <marpan@google.com>
Date:   Fri Dec 19 08:56:45 2025 -0800

    Source content analysis for one_pass_rt_lag encoding

    For the one_pass realtime with lookahead encoding mode:
    add source analysis processing of frames in lookahead buffer,
    for adjusting the gop parameters. Usage of this feature
    will be in subsequent CL.

    Also fix speed feature setting for source_sad usage.

    Change-Id: I5d20b35848cf60d86e65364fc50a269029889b6f

diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index b0d6db4715..202ebaeead 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -3808,6 +3808,31 @@ static void get_one_pass_rt_lag_params(AV1_COMP *cpi, unsigned int frame_flags,
             : MAX_GF_LENGTH_LAP;
     // Limit the max gop length for the last gop in 1 pass setting.
     max_gop_length = AOMMIN(max_gop_length, rc->frames_to_key);
+    // Go through source frames in lookahead buffer and compute source metrics:
+    // scene change, frame average source sad, etc.
+    for (int i = 1; i < max_gop_length; i++) {
+      EncodeFrameInput frame_input;
+      memset(&frame_input, 0, sizeof(frame_input));
+      struct lookahead_entry *e =
+          av1_lookahead_peek(cpi->ppi->lookahead, i, cpi->compressor_stage);
+      struct lookahead_entry *e_prev =
+          av1_lookahead_peek(cpi->ppi->lookahead, i - 1, cpi->compressor_stage);
+      if (e != NULL && e_prev != NULL) {
+        frame_input.source = &e->img;
+        frame_input.last_source = &e_prev->img;
+        rc->high_source_sad_lag[i] = -1;
+        rc->frame_source_sad_lag[i] = 0;
+        rc->avg_source_sad = 0;
+        av1_rc_scene_detection_onepass_rt(cpi, &frame_input);
+        rc->high_source_sad_lag[i] = rc->high_source_sad;
+        rc->frame_source_sad_lag[i] = rc->frame_source_sad;
+        // Use rc->high_source_sad_lag[i] and frame_source_sad_lag[i] to
+        // adjust/adapt the gop parameters. Reset the parameters for the
+        // encoding.
+        rc->high_source_sad = 0;
+        rc->frame_source_sad = UINT64_MAX;
+      }
+    }
     calculate_gf_length(cpi, max_gop_length, MAX_NUM_GF_INTERVALS);
     define_gf_group(cpi, frame_params, 0);
     rc->frames_till_gf_update_due = p_rc->baseline_gf_interval;
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 99d25049d4..8e09f0f043 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -3159,21 +3159,8 @@ static unsigned int estimate_scroll_motion(
   return best_sad;
 }

-/*!\brief Check for scene detection, for 1 pass real-time mode.
- *
- * Compute average source sad (temporal sad: between current source and
- * previous source) over a subset of superblocks. Use this is detect big changes
- * in content and set the \c cpi->rc.high_source_sad flag.
- *
- * \ingroup rate_control
- * \param[in]       cpi          Top level encoder structure
- * \param[in]       frame_input  Current and last input source frames
- *
- * \remark Nothing is returned. Instead the flag \c cpi->rc.high_source_sad
- * is set if scene change is detected, and \c cpi->rc.avg_source_sad is updated.
- */
-static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
-                                          const EncodeFrameInput *frame_input) {
+void av1_rc_scene_detection_onepass_rt(AV1_COMP *cpi,
+                                       const EncodeFrameInput *frame_input) {
   AV1_COMMON *const cm = &cpi->common;
   RATE_CONTROL *const rc = &cpi->rc;
   YV12_BUFFER_CONFIG const *const unscaled_src = frame_input->source;
@@ -3265,7 +3252,7 @@ static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
       rc->prev_frame_is_dropped || cpi->svc.number_temporal_layers > 1;
   // Store blkwise SAD for later use. Disable for spatial layers for now.
   if (width == cm->render_width && height == cm->render_height &&
-      cpi->svc.number_spatial_layers == 1) {
+      cpi->svc.number_spatial_layers == 1 && !is_one_pass_rt_lag_params(cpi)) {
     if (cpi->src_sad_blk_64x64 == NULL) {
       CHECK_MEM_ERROR(cm, cpi->src_sad_blk_64x64,
                       (uint64_t *)aom_calloc(sb_cols * sb_rows,
@@ -3354,7 +3341,7 @@ static void rc_scene_detection_onepass_rt(AV1_COMP *cpi,
   const uint64_t thresh_high_motion = scale * 64 * 64;
   if (cpi->svc.temporal_layer_id == 0 && rc->drop_count_consec < 3) {
     cpi->rc.high_motion_content_screen_rtc = 0;
-    if (cpi->oxcf.speed >= 11 &&
+    if (cpi->oxcf.speed >= 11 && !is_one_pass_rt_lag_params(cpi) &&
         cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
         rc->num_col_blscroll_last_tl0 < 5 &&
         rc->num_row_blscroll_last_tl0 < 5 &&
@@ -3833,7 +3820,7 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, FRAME_TYPE *const frame_type,
              svc->spatial_layer_id == 0) {
     if (rc->prev_coded_width == cm->width &&
         rc->prev_coded_height == cm->height) {
-      rc_scene_detection_onepass_rt(cpi, frame_input);
+      av1_rc_scene_detection_onepass_rt(cpi, frame_input);
     } else {
       aom_free(cpi->src_sad_blk_64x64);
       cpi->src_sad_blk_64x64 = NULL;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index cd376bacf9..4d6ef52bea 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -190,10 +190,20 @@ typedef struct {
   int sframe_due;

   int high_source_sad;
+  /*!
+   * The high_source_sad flag, which indicates scene change, for each frame [i]
+   * in the lookahead buffer, used for the encoding mode: is_one_pass_rt_lag.
+   */
+  int high_source_sad_lag[MAX_GF_INTERVAL];
   int high_motion_content_screen_rtc;
   uint64_t avg_source_sad;
   uint64_t prev_avg_source_sad;
   uint64_t frame_source_sad;
+  /*!
+   * The frame source sad for each frame [i] in the lookahead buffer,
+   * used for the encoding mode: is_one_pass_rt_lag.
+   */
+  uint64_t frame_source_sad_lag[MAX_GF_INTERVAL];
   unsigned int last_frame_low_source_sad;
   uint64_t frame_spatial_variance;
   int static_since_last_scene_change;
@@ -831,6 +841,22 @@ int av1_encodedframe_overshoot_cbr(struct AV1_COMP *cpi, int *q);
  */
 int av1_postencode_drop_cbr(struct AV1_COMP *cpi, size_t *size);

+/*!\brief Check for scene detection, for 1 pass real-time mode.
+ *
+ * Compute average source sad (temporal sad: between current source and
+ * previous source) over a subset of superblocks. Use this is detect big changes
+ * in content and set the \c cpi->rc.high_source_sad flag.
+ *
+ * \ingroup rate_control
+ * \param[in]       cpi          Top level encoder structure
+ * \param[in]       frame_input  Current and last input source frames
+ *
+ * \remark Nothing is returned. Instead the flag \c cpi->rc.high_source_sad
+ * is set if scene change is detected, and \c cpi->rc.avg_source_sad is updated.
+ */
+void av1_rc_scene_detection_onepass_rt(
+    struct AV1_COMP *cpi, const struct EncodeFrameInput *frame_input);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 3d9833a647..bd35d8b5ae 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1839,6 +1839,11 @@ static void set_rt_speed_feature_framesize_dependent(const AV1_COMP *const cpi,
     sf->rt_sf.set_zeromv_skip_based_on_source_sad = 0;

   if (is_one_pass_rt_lag_params(cpi)) {
+    const RefreshFrameInfo *const refresh_frame = &cpi->refresh_frame;
+    if (refresh_frame->alt_ref_frame) {
+      sf->rt_sf.source_metrics_sb_nonrd = 0;
+      sf->rt_sf.var_part_based_on_qidx = 0;
+    }
     sf->rt_sf.use_nonrd_altref_frame = 1;
     // For non-zero lag: disable the 3 speed features below for now,
     // until further testing.