Realtime mode with lookahead for 1 pass

Make nonzero lookahead (lag_in_frames > 0) work with
1 pass realtime mode. This new encoding mode is for
single spatial layer and VBR mode. And disallowed
for REALTIIME_CONFIG=1 (lag-in-frames is kept forced
to 0 for this build config under realtime mode).

The gop/pyramid structure is set in the function
define_gf_group_pass0(), with the gop length and depth
set by the user via the parameters:
--min/max-gf-interval, --gf-min/max-pyr-height

The gop structure will be fixed (based on user settings) for
the whole sequence for now, adaptation to the source content
will be added later.

The nonrd-pickmode encoding (speed >= 7) is expanded to
support the additional references for prediction in this
encoding mode.

Test for this encoding mode added in datarate_test,cc.

Initial borg result for speed 8, comparing nonzero lookahead
(with gf-interval=16 and pyr-height=1) vs lookahead=0:
bdrate gain of ~15/19% (avg_psnr/ssim) with IC speed slowdown of ~50%.

The case of spatial layers was done here (not merged in):
https://aomedia-review.googlesource.com/c/aom/+/193401

Change-Id: I50eeff1a87884f7237f5163b209f79fdae899979
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 3caae90..c3eb292 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -1206,10 +1206,12 @@
   }
   config->use_16bit_internal |= config->cfg.g_bit_depth > AOM_BITS_8;
 
+#if CONFIG_REALTIME_ONLY
   if (global->usage == AOM_USAGE_REALTIME && config->cfg.g_lag_in_frames != 0) {
     aom_tools_warn("non-zero lag-in-frames option ignored in realtime mode.\n");
     config->cfg.g_lag_in_frames = 0;
   }
+#endif
 
   if (global->usage == AOM_USAGE_ALL_INTRA) {
     if (config->cfg.g_lag_in_frames != 0) {
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index a1ee702..c049a99 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -1356,10 +1356,13 @@
   color_cfg->chroma_sample_position = extra_cfg->chroma_sample_position;
 
   // Set Group of frames configuration.
-  // Force lag_in_frames to 0 for REALTIME mode
+#if CONFIG_REALTIME_ONLY
   gf_cfg->lag_in_frames = (oxcf->mode == REALTIME)
                               ? 0
                               : clamp(cfg->g_lag_in_frames, 0, MAX_LAG_BUFFERS);
+#else
+  gf_cfg->lag_in_frames = clamp(cfg->g_lag_in_frames, 0, MAX_LAG_BUFFERS);
+#endif
   gf_cfg->enable_auto_arf = extra_cfg->enable_auto_alt_ref;
   gf_cfg->enable_auto_brf = extra_cfg->enable_auto_bwd_ref;
   gf_cfg->min_gf_interval = extra_cfg->min_gf_interval;
@@ -3009,7 +3012,7 @@
 
       set_encoder_config(&priv->oxcf, &priv->cfg, &priv->extra_cfg);
       if (priv->oxcf.rc_cfg.mode != AOM_CBR &&
-          priv->oxcf.pass == AOM_RC_ONE_PASS && priv->oxcf.mode == GOOD) {
+          priv->oxcf.pass == AOM_RC_ONE_PASS) {
         // Enable look ahead - enabled for AOM_Q, AOM_CQ, AOM_VBR
         *num_lap_buffers =
             AOMMIN((int)priv->cfg.g_lag_in_frames,
@@ -3522,7 +3525,7 @@
 #endif  // CONFIG_MULTITHREAD
 
     // Call for LAP stage
-    if (cpi_lap != NULL) {
+    if (cpi_lap != NULL && !is_one_pass_rt_lag_params(cpi)) {
       if (cpi_lap->ppi->b_freeze_internal_state) {
         av1_save_all_coding_context(cpi_lap);
       }
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index b18b21f..5ac74da 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -1302,8 +1302,7 @@
     return -1;
   }
 
-  // TODO(sarahparker) finish bit allocation for one pass pyramid
-  if (has_no_stats_stage(cpi)) {
+  if (has_no_stats_stage(cpi) && !is_one_pass_rt_lag_params(cpi)) {
     gf_cfg->gf_max_pyr_height =
         AOMMIN(gf_cfg->gf_max_pyr_height, USE_ALTREF_FOR_ONE_PASS);
     gf_cfg->gf_min_pyr_height =
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index c68f7e9..95202d1 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -4127,7 +4127,8 @@
 static inline int is_stat_consumption_stage(const AV1_COMP *const cpi) {
   return (is_stat_consumption_stage_twopass(cpi) ||
           (cpi->oxcf.pass == AOM_RC_ONE_PASS &&
-           (cpi->compressor_stage == ENCODE_STAGE) && cpi->ppi->lap_enabled));
+           (cpi->compressor_stage == ENCODE_STAGE) && cpi->ppi->lap_enabled &&
+           cpi->oxcf.mode != REALTIME));
 }
 
 // Decide whether 'dv_costs' need to be allocated/stored during the encoding.
@@ -4148,11 +4149,18 @@
 static inline int has_no_stats_stage(const AV1_COMP *const cpi) {
   assert(
       IMPLIES(!cpi->ppi->lap_enabled, cpi->compressor_stage == ENCODE_STAGE));
-  return (cpi->oxcf.pass == AOM_RC_ONE_PASS && !cpi->ppi->lap_enabled);
+  return (cpi->oxcf.pass == AOM_RC_ONE_PASS &&
+          (!cpi->ppi->lap_enabled || cpi->oxcf.mode == REALTIME));
 }
 
 /*!\cond */
 
+static inline int is_one_pass_rt_lag_params(const AV1_COMP *cpi) {
+  return cpi->oxcf.pass == AOM_RC_ONE_PASS &&
+         cpi->oxcf.gf_cfg.lag_in_frames > 0 && cpi->oxcf.mode == REALTIME &&
+         cpi->oxcf.rc_cfg.mode != AOM_CBR;
+}
+
 static inline int is_one_pass_rt_params(const AV1_COMP *cpi) {
   return has_no_stats_stage(cpi) && cpi->oxcf.gf_cfg.lag_in_frames == 0 &&
          (cpi->oxcf.mode == REALTIME || cpi->svc.number_spatial_layers > 1);
diff --git a/av1/encoder/nonrd_opt.h b/av1/encoder/nonrd_opt.h
index 1e783e9..9f81c0a 100644
--- a/av1/encoder/nonrd_opt.h
+++ b/av1/encoder/nonrd_opt.h
@@ -21,7 +21,9 @@
 #define RTC_MODES (AOMMAX(RTC_INTER_MODES, RTC_INTRA_MODES))
 #define CALC_BIASED_RDCOST(rdcost) (7 * (rdcost) >> 3)
 #define NUM_COMP_INTER_MODES_RT (6)
+#define NUM_COMP_INTER_MODES_RT_FULL (10)
 #define NUM_INTER_MODES 12
+#define NUM_INTER_MODES_FULL 28
 #define CAP_TX_SIZE_FOR_BSIZE_GT32(tx_mode_search_type, bsize) \
   (((tx_mode_search_type) != ONLY_4X4 && (bsize) > BLOCK_32X32) ? true : false)
 #define TX_SIZE_FOR_BSIZE_GT32 (TX_16X16)
@@ -144,6 +146,23 @@
   { ALTREF_FRAME, GLOBALMV },  { ALTREF_FRAME, NEWMV },
 };
 
+static const REF_MODE ref_mode_set_full[NUM_INTER_MODES_FULL] = {
+  { LAST_FRAME, NEARESTMV },    { LAST_FRAME, NEARMV },
+  { LAST_FRAME, GLOBALMV },     { LAST_FRAME, NEWMV },
+  { GOLDEN_FRAME, NEARESTMV },  { GOLDEN_FRAME, NEARMV },
+  { GOLDEN_FRAME, GLOBALMV },   { GOLDEN_FRAME, NEWMV },
+  { ALTREF_FRAME, NEARESTMV },  { ALTREF_FRAME, NEARMV },
+  { ALTREF_FRAME, GLOBALMV },   { ALTREF_FRAME, NEWMV },
+  { LAST2_FRAME, NEARESTMV },   { LAST2_FRAME, NEARMV },
+  { LAST2_FRAME, GLOBALMV },    { LAST2_FRAME, NEWMV },
+  { LAST3_FRAME, NEARESTMV },   { LAST3_FRAME, NEARMV },
+  { LAST3_FRAME, GLOBALMV },    { LAST3_FRAME, NEWMV },
+  { BWDREF_FRAME, NEARESTMV },  { BWDREF_FRAME, NEARMV },
+  { BWDREF_FRAME, GLOBALMV },   { BWDREF_FRAME, NEWMV },
+  { ALTREF2_FRAME, NEARESTMV }, { ALTREF2_FRAME, NEARMV },
+  { ALTREF2_FRAME, GLOBALMV },  { ALTREF2_FRAME, NEWMV },
+};
+
 static const COMP_REF_MODE comp_ref_mode_set[NUM_COMP_INTER_MODES_RT] = {
   { { LAST_FRAME, GOLDEN_FRAME }, GLOBAL_GLOBALMV },
   { { LAST_FRAME, GOLDEN_FRAME }, NEAREST_NEARESTMV },
@@ -153,6 +172,20 @@
   { { LAST_FRAME, ALTREF_FRAME }, NEAREST_NEARESTMV },
 };
 
+static const COMP_REF_MODE
+    comp_ref_mode_set_full[NUM_COMP_INTER_MODES_RT_FULL] = {
+      { { LAST_FRAME, GOLDEN_FRAME }, GLOBAL_GLOBALMV },
+      { { LAST_FRAME, GOLDEN_FRAME }, NEAREST_NEARESTMV },
+      { { LAST_FRAME, LAST2_FRAME }, GLOBAL_GLOBALMV },
+      { { LAST_FRAME, LAST2_FRAME }, NEAREST_NEARESTMV },
+      { { LAST_FRAME, ALTREF_FRAME }, GLOBAL_GLOBALMV },
+      { { LAST_FRAME, ALTREF_FRAME }, NEAREST_NEARESTMV },
+      { { LAST_FRAME, BWDREF_FRAME }, GLOBAL_GLOBALMV },
+      { { LAST_FRAME, BWDREF_FRAME }, NEAREST_NEARESTMV },
+      { { LAST_FRAME, ALTREF2_FRAME }, GLOBAL_GLOBALMV },
+      { { LAST_FRAME, ALTREF2_FRAME }, NEAREST_NEARESTMV },
+    };
+
 static const int_interpfilters filters_ref_set[9] = {
   [0].as_filters = { EIGHTTAP_REGULAR, EIGHTTAP_REGULAR },
   [1].as_filters = { EIGHTTAP_SMOOTH, EIGHTTAP_SMOOTH },
@@ -466,7 +499,8 @@
         &frame_mv[NEARESTMV][ref_frame], &frame_mv[NEARMV][ref_frame], 0);
     frame_mv[GLOBALMV][ref_frame] = mbmi_ext->global_mvs[ref_frame];
     // Early exit for non-LAST frame if force_skip_low_temp_var is set.
-    if (!ref_is_scaled && bsize >= BLOCK_8X8 && !skip_pred_mv &&
+    if (!is_one_pass_rt_lag_params(cpi) && !ref_is_scaled &&
+        bsize >= BLOCK_8X8 && !skip_pred_mv &&
         !(force_skip_low_temp_var && ref_frame != LAST_FRAME)) {
       av1_mv_pred(cpi, x, yv12_mb[ref_frame][0].buf, yv12->y_stride, ref_frame,
                   bsize);
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index 72c82db..f201006 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -311,7 +311,8 @@
   int_mv *this_ref_frm_newmv = &frame_mv[NEWMV][ref_frame];
   unsigned int y_sad_zero;
   if (ref_frame > LAST_FRAME && cpi->oxcf.rc_cfg.mode == AOM_CBR &&
-      (cpi->ref_frame_flags & AOM_LAST_FLAG) && gf_temporal_ref) {
+      (cpi->ref_frame_flags & AOM_LAST_FLAG) && gf_temporal_ref &&
+      !is_one_pass_rt_lag_params(cpi)) {
     int tmp_sad;
     int dis;
 
@@ -371,7 +372,8 @@
                                             const MACROBLOCKD *xd,
                                             const ModeCosts *mode_costs,
                                             int segment_id, BLOCK_SIZE bsize,
-                                            unsigned int *ref_costs_single) {
+                                            unsigned int *ref_costs_single,
+                                            int is_one_pass_rt_lag) {
   int seg_ref_active =
       segfeature_active(&cm->seg, segment_id, SEG_LVL_REF_FRAME);
   if (seg_ref_active) {
@@ -395,6 +397,18 @@
     ref_costs_single[GOLDEN_FRAME] += mode_costs->single_ref_cost[0][1][0];
     ref_costs_single[ALTREF_FRAME] += mode_costs->single_ref_cost[0][0][1];
     ref_costs_single[ALTREF_FRAME] += mode_costs->single_ref_cost[0][2][0];
+    if (is_one_pass_rt_lag) {
+      ref_costs_single[ALTREF2_FRAME] = base_cost;
+      ref_costs_single[BWDREF_FRAME] = base_cost;
+      ref_costs_single[LAST2_FRAME] = base_cost;
+      ref_costs_single[LAST3_FRAME] = base_cost;
+      ref_costs_single[LAST2_FRAME] += mode_costs->single_ref_cost[0][0][0];
+      ref_costs_single[LAST3_FRAME] += mode_costs->single_ref_cost[0][0][0];
+      ref_costs_single[BWDREF_FRAME] += mode_costs->single_ref_cost[0][0][1];
+      ref_costs_single[BWDREF_FRAME] += mode_costs->single_ref_cost[0][1][0];
+      ref_costs_single[ALTREF2_FRAME] += mode_costs->single_ref_cost[0][0][1];
+      ref_costs_single[ALTREF2_FRAME] += mode_costs->single_ref_cost[0][2][0];
+    }
   }
 }
 
@@ -2213,14 +2227,12 @@
     const int *use_ref_frame_mask, int comp_index,
     bool comp_use_zero_zeromv_only, MV_REFERENCE_FRAME *last_comp_ref_frame,
     BLOCK_SIZE bsize) {
-  const MV_REFERENCE_FRAME *rf = comp_ref_mode_set[comp_index].ref_frame;
+  const MV_REFERENCE_FRAME *rf =
+      is_one_pass_rt_lag_params(cpi)
+          ? comp_ref_mode_set_full[comp_index].ref_frame
+          : comp_ref_mode_set[comp_index].ref_frame;
   int skip_gf = 0;
   int skip_alt = 0;
-  *this_mode = comp_ref_mode_set[comp_index].pred_mode;
-  *ref_frame = rf[0];
-  *ref_frame2 = rf[1];
-  assert(*ref_frame == LAST_FRAME);
-  assert(*this_mode == GLOBAL_GLOBALMV || *this_mode == NEAREST_NEARESTMV);
   if (x->source_variance < 50 && bsize > BLOCK_16X16) {
     if (x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_U)] == 1 ||
         x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_V)] == 1)
@@ -2352,7 +2364,8 @@
 
   // Estimate cost for single reference frames
   estimate_single_ref_frame_costs(cm, xd, mode_costs, segment_id, bsize,
-                                  search_state->ref_costs_single);
+                                  search_state->ref_costs_single,
+                                  is_one_pass_rt_lag_params(cpi));
 
   // Reset flag to indicate modes evaluated
   av1_zero(search_state->mode_checked);
@@ -2388,9 +2401,17 @@
                     &search_state->use_scaled_ref_frame[LAST_FRAME]);
   }
   // Update mask to use all reference frame
-  get_ref_frame_use_mask(cpi, x, mi, mi_row, mi_col, bsize, gf_temporal_ref,
-                         search_state->use_ref_frame_mask,
-                         force_skip_low_temp_var);
+  if (!is_one_pass_rt_lag_params(cpi)) {
+    get_ref_frame_use_mask(cpi, x, mi, mi_row, mi_col, bsize, gf_temporal_ref,
+                           search_state->use_ref_frame_mask,
+                           force_skip_low_temp_var);
+  } else {
+    for (MV_REFERENCE_FRAME ref_frame_iter = LAST_FRAME;
+         ref_frame_iter <= ALTREF_FRAME; ++ref_frame_iter) {
+      search_state->use_ref_frame_mask[ref_frame_iter] =
+          cpi->ref_frame_flags & (1 << (ref_frame_iter - 1));
+    }
+  }
 
   skip_pred_mv = x->force_zeromv_skip_for_blk ||
                  (x->nonrd_prune_ref_frame_search > 2 &&
@@ -2431,6 +2452,15 @@
   // for allowed compound modes, setup ref mv stack and reference frame.
   if (idx >= num_inter_modes) {
     const int comp_index = idx - num_inter_modes;
+    const COMP_REF_MODE *const comp_modes = is_one_pass_rt_lag_params(cpi)
+                                                ? comp_ref_mode_set_full
+                                                : comp_ref_mode_set;
+    const MV_REFERENCE_FRAME *rf = comp_modes[comp_index].ref_frame;
+    *this_mode = comp_modes[comp_index].pred_mode;
+    *ref_frame = rf[0];
+    *ref_frame2 = rf[1];
+    assert(*ref_frame == LAST_FRAME);
+    assert(*this_mode == GLOBAL_GLOBALMV || *this_mode == NEAREST_NEARESTMV);
     if (!setup_compound_params_from_comp_idx(
             cpi, x, search_state->yv12_mb, this_mode, ref_frame, ref_frame2,
             search_state->frame_mv, search_state->use_ref_frame_mask,
@@ -2440,9 +2470,15 @@
     }
     *is_single_pred = 0;
   } else {
-    *this_mode = ref_mode_set[idx].pred_mode;
-    *ref_frame = ref_mode_set[idx].ref_frame;
     *ref_frame2 = NONE_FRAME;
+    const REF_MODE *const single_modes =
+        is_one_pass_rt_lag_params(cpi) ? ref_mode_set_full : ref_mode_set;
+    *this_mode = single_modes[idx].pred_mode;
+    *ref_frame = single_modes[idx].ref_frame;
+  }
+
+  if (is_one_pass_rt_lag_params(cpi) && cpi->rc.is_src_frame_alt_ref) {
+    if (*this_mode != GLOBALMV || *ref_frame != ALTREF_FRAME) return true;
   }
 
   if (cpi->sf.rt_sf.skip_newmv_mode_sad_screen && cpi->rc.high_source_sad &&
@@ -2521,6 +2557,7 @@
   // Skip compound mode based on variance of previously evaluated single
   // reference modes.
   if (rt_sf->prune_compoundmode_with_singlemode_var && !*is_single_pred &&
+      !is_one_pass_rt_lag_params(cpi) &&
       prune_compoundmode_with_singlemode_var(
           *this_mode, *ref_frame, *ref_frame2, search_state->frame_mv,
           search_state->mode_checked, search_state->vars,
@@ -2577,6 +2614,8 @@
       return true;
   }
 
+  if (is_one_pass_rt_lag_params(cpi)) return false;
+
   // Skip mode based on block size, reference frame mode and other block
   // properties.
   if (skip_mode_by_bsize_and_ref_frame(
@@ -3243,7 +3282,8 @@
   int best_early_term = 0;
   int force_skip_low_temp_var = 0;
   unsigned int sse_zeromv_norm = UINT_MAX;
-  const int num_inter_modes = NUM_INTER_MODES;
+  const int num_inter_modes =
+      is_one_pass_rt_lag_params(cpi) ? NUM_INTER_MODES_FULL : NUM_INTER_MODES;
   const REAL_TIME_SPEED_FEATURES *const rt_sf = &cpi->sf.rt_sf;
   bool check_globalmv = rt_sf->check_globalmv_on_single_ref;
   PRED_BUFFER tmp_buffer[4];
@@ -3274,7 +3314,9 @@
   int_mv svc_mv = { .as_int = 0 };
   int force_mv_inter_layer = 0;
   bool comp_use_zero_zeromv_only = 0;
-  int tot_num_comp_modes = NUM_COMP_INTER_MODES_RT;
+  int tot_num_comp_modes = is_one_pass_rt_lag_params(cpi)
+                               ? NUM_COMP_INTER_MODES_RT_FULL
+                               : NUM_COMP_INTER_MODES_RT;
 #if CONFIG_AV1_TEMPORAL_DENOISING
   const int denoise_recheck_zeromv = 1;
   AV1_PICKMODE_CTX_DEN ctx_den;
@@ -3371,9 +3413,14 @@
              tx_mode_to_biggest_tx_size[txfm_params->tx_mode_search_type]),
       TX_16X16);
 
-  fill_single_inter_mode_costs(search_state.single_inter_mode_costs,
-                               num_inter_modes, ref_mode_set, mode_costs,
-                               mbmi_ext->mode_context);
+  if (!is_one_pass_rt_lag_params(cpi))
+    fill_single_inter_mode_costs(search_state.single_inter_mode_costs,
+                                 num_inter_modes, ref_mode_set, mode_costs,
+                                 mbmi_ext->mode_context);
+  else
+    fill_single_inter_mode_costs(search_state.single_inter_mode_costs,
+                                 num_inter_modes, ref_mode_set_full, mode_costs,
+                                 mbmi_ext->mode_context);
 
   MV_REFERENCE_FRAME last_comp_ref_frame = NONE_FRAME;
 
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index dac8758..a4b40ce 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -2190,13 +2190,9 @@
   const GFConfig *const gf_cfg = &oxcf->gf_cfg;
   int target;
 
-  if (oxcf->q_cfg.aq_mode == CYCLIC_REFRESH_AQ) {
-    av1_cyclic_refresh_set_golden_update(cpi);
-  } else {
-    p_rc->baseline_gf_interval = p_rc->gf_intervals[p_rc->cur_gf_index];
-    rc->intervals_till_gf_calculate_due--;
-    p_rc->cur_gf_index++;
-  }
+  p_rc->baseline_gf_interval = p_rc->gf_intervals[p_rc->cur_gf_index];
+  rc->intervals_till_gf_calculate_due--;
+  p_rc->cur_gf_index++;
 
   // correct frames_to_key when lookahead queue is flushing
   correct_frames_to_key(cpi);
@@ -2208,7 +2204,13 @@
   p_rc->constrained_gf_group =
       (p_rc->baseline_gf_interval >= rc->frames_to_key) ? 1 : 0;
 
-  gf_group->max_layer_depth_allowed = oxcf->gf_cfg.gf_max_pyr_height;
+  // Default for pyr_height if inputs not set.
+  if (oxcf->gf_cfg.gf_max_pyr_height == 0 ||
+      oxcf->gf_cfg.gf_min_pyr_height == 0) {
+    gf_group->max_layer_depth_allowed = 1;
+  } else {
+    gf_group->max_layer_depth_allowed = oxcf->gf_cfg.gf_max_pyr_height;
+  }
 
   // Rare case when the look-ahead is less than the target GOP length, can't
   // generate ARF frame.
@@ -3900,7 +3902,7 @@
       p_rc->frames_till_regions_update = rest_frames;
 
       int ret;
-      if (cpi->ppi->lap_enabled) {
+      if (cpi->ppi->lap_enabled && !is_one_pass_rt_lag_params(cpi)) {
         mark_flashes(twopass->stats_buf_ctx->stats_in_start,
                      twopass->stats_buf_ctx->stats_in_end);
         estimate_noise(twopass->stats_buf_ctx->stats_in_start,
@@ -4021,6 +4023,13 @@
 
     define_gf_group(cpi, frame_params, 0);
 
+    if (is_one_pass_rt_lag_params(cpi)) {
+      rc->frames_till_gf_update_due = p_rc->baseline_gf_interval;
+      frame_params->frame_type = gf_group->frame_type[cpi->gf_frame_index];
+      av1_setup_target_rate(cpi);
+      return;
+    }
+
     if (gf_group->update_type[cpi->gf_frame_index] != ARF_UPDATE &&
         rc->frames_since_key > 0)
       process_first_pass_stats(cpi, &this_frame);
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index de2db3f..e043f6b 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -2747,7 +2747,7 @@
 
 int av1_calc_pframe_target_size_one_pass_vbr(
     const AV1_COMP *const cpi, FRAME_UPDATE_TYPE frame_update_type) {
-  static const int af_ratio = 10;
+  const int af_ratio = is_one_pass_rt_lag_params(cpi) ? 6 : 10;
   const RATE_CONTROL *const rc = &cpi->rc;
   const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
   int64_t target;
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 446caf8..da5471c 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1836,6 +1836,15 @@
   // disable for now.
   if (cpi->active_map.enabled)
     sf->rt_sf.set_zeromv_skip_based_on_source_sad = 0;
+
+  if (is_one_pass_rt_lag_params(cpi)) {
+    sf->rt_sf.use_nonrd_altref_frame = 1;
+    // For non-zero lag: disable the 3 speed features below for now,
+    // until further testing.
+    sf->rt_sf.use_rtc_tf = 0;
+    sf->rt_sf.nonrd_check_partition_merge_mode = 0;
+    sf->rt_sf.nonrd_check_partition_split = 0;
+  }
 }
 
 static void set_rt_speed_features_framesize_independent(AV1_COMP *cpi,
@@ -1974,7 +1983,7 @@
   sf->rt_sf.mode_search_skip_flags |= FLAG_SKIP_INTRA_DIRMISMATCH;
   sf->rt_sf.num_inter_modes_for_tx_search = 5;
   sf->rt_sf.prune_inter_modes_using_temp_var = 1;
-  sf->rt_sf.use_real_time_ref_set = 1;
+  sf->rt_sf.use_real_time_ref_set = is_one_pass_rt_lag_params(cpi) ? 0 : 1;
   sf->rt_sf.use_simple_rd_model = 1;
   sf->rt_sf.prune_inter_modes_with_golden_ref = boosted ? 0 : 1;
   // TODO(any): This sf could be removed.
@@ -2003,6 +2012,13 @@
   sf->rt_sf.use_fast_fixed_part = 0;
   sf->rt_sf.increase_source_sad_thresh = 0;
 
+  if (is_one_pass_rt_lag_params(cpi) && speed <= 6) {
+    sf->hl_sf.frame_parameter_update = 1;
+    sf->inter_sf.use_dist_wtd_comp_flag = 0;
+    sf->inter_sf.disable_masked_comp = 1;
+    sf->inter_sf.disable_onesided_comp = 1;
+  }
+
   if (speed >= 6) {
     sf->mv_sf.use_fullpel_costlist = 1;
 
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index c10c5c6..9f3fff8 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -355,6 +355,29 @@
     RunBasicRateTargetingTestReversed(&video, bitrate_array[GET_PARAM(4)], 0.5,
                                       1.5);
   }
+
+  virtual void BasicRateTargetingVBRLagRealtime() {
+    ::libaom_test::I420VideoSource video("niklas_640_480_30.yuv", 320, 240, 30,
+                                         1, 0, 200);
+    cfg_.rc_min_quantizer = 0;
+    cfg_.rc_max_quantizer = 63;
+    cfg_.g_error_resilient = 0;
+    cfg_.rc_end_usage = AOM_VBR;
+    cfg_.g_lag_in_frames = 48;
+    cfg_.g_pass = AOM_RC_ONE_PASS;
+    cfg_.g_usage = AOM_USAGE_REALTIME;
+    cfg_.g_profile = 0;
+    cfg_.g_timebase = video.timebase();
+    cfg_.g_threads = 1;
+
+    ResetModel();
+    lag_realtime_mode_ = 1;
+    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+    ASSERT_GE(effective_datarate_, cfg_.rc_target_bitrate * 0.85)
+        << " The datarate for the file is lower than target by too much!";
+    ASSERT_LE(effective_datarate_, cfg_.rc_target_bitrate * 2.0)
+        << " The datarate for the file is greater than target by too much!";
+  }
 };
 
 // Params: test mode, speed, aq mode.
@@ -610,6 +633,10 @@
   BasicRateTargetingCifCBRKf();
 }
 
+TEST_P(DatarateTestRealtime, BasicRateTargetingVBRLagRealtime) {
+  BasicRateTargetingVBRLagRealtime();
+}
+
 // Check that (1) the first dropped frame gets earlier and earlier
 // as the drop frame threshold is increased, and (2) that the total number of
 // frame drops does not decrease as we increase frame drop threshold.
diff --git a/test/datarate_test.h b/test/datarate_test.h
index 9741282..9b91cb4 100644
--- a/test/datarate_test.h
+++ b/test/datarate_test.h
@@ -69,6 +69,7 @@
       effective_datarate_dynamic_[i] = 0.0;
     }
     avif_mode_ = 0;
+    lag_realtime_mode_ = 0;
   }
 
   void PreEncodeFrameHook(::libaom_test::VideoSource *video,
@@ -117,6 +118,12 @@
         encoder->Control(AOME_SET_CQ_LEVEL, 0);
         encoder->Control(AV1E_SET_AQ_MODE, (aq_mode_ > 0) ? 1 : 0);
       }
+      if (lag_realtime_mode_) {
+        encoder->Control(AV1E_SET_MIN_GF_INTERVAL, 16);
+        encoder->Control(AV1E_SET_MAX_GF_INTERVAL, 16);
+        encoder->Control(AV1E_SET_GF_MAX_PYRAMID_HEIGHT, 1);
+        encoder->Control(AV1E_SET_GF_MIN_PYRAMID_HEIGHT, 1);
+      }
     }
 
     if (speed_change_test_) {
@@ -282,6 +289,7 @@
   int64_t bits_total_dynamic_[3];
   int frame_number_dynamic_[3];
   int avif_mode_;
+  int lag_realtime_mode_;
 };
 
 }  // namespace
diff --git a/test/encode_test_driver.cc b/test/encode_test_driver.cc
index 6ad10bd..6d42f4b 100644
--- a/test/encode_test_driver.cc
+++ b/test/encode_test_driver.cc
@@ -196,7 +196,7 @@
     ASSERT_NO_FATAL_FAILURE(video->Begin());
     encoder->InitEncoder(video);
 
-    if (mode_ == kRealTime) {
+    if (mode_ == kRealTime && cfg_.g_lag_in_frames == 0) {
       encoder->Control(AOME_SET_ENABLEAUTOALTREF, 0);
     }