Move frame level twopass members to twopass_frame structure

Moved elements stats_in, mb_av_energy and fr_content_type out
of TWOPASS into TWOPASS_FRAME. Each frame context(cpi) will have
a copy of TWOPASS_FRAME, initialized appropriately for the frame
it will be processing.

Change-Id: I864860db45a152b370b3e6f342f8372277febc7d
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 490f3aa..45da020 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -2385,8 +2385,6 @@
         priv->ppi->twopass.frame_stats_arr[i] = &priv->frame_stats_buffer[i];
 
       priv->ppi->twopass.stats_buf_ctx = &priv->stats_buf_context;
-      priv->ppi->twopass.stats_in =
-          priv->ppi->twopass.stats_buf_ctx->stats_in_start;
 #endif
 
 #if CONFIG_FRAME_PARALLEL_ENCODE
@@ -2408,12 +2406,16 @@
                   priv->ppi->parallel_cpi[i],
                   priv->ppi->parallel_cpi[i]->oxcf.max_threads));
         }
+        priv->ppi->parallel_cpi[i]->twopass_frame.stats_in =
+            priv->ppi->twopass.stats_buf_ctx->stats_in_start;
       }
       priv->ppi->cpi = priv->ppi->parallel_cpi[0];
 #else
       res = create_context_and_bufferpool(priv->ppi, &priv->ppi->cpi,
                                           &priv->buffer_pool, &priv->oxcf,
                                           ENCODE_STAGE, -1);
+      priv->ppi->cpi->twopass_frame.stats_in =
+          priv->ppi->twopass.stats_buf_ctx->stats_in_start;
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
 
       // Create another compressor if look ahead is enabled
diff --git a/av1/encoder/aq_complexity.c b/av1/encoder/aq_complexity.c
index 1c3d710..3573b2a 100644
--- a/av1/encoder/aq_complexity.c
+++ b/av1/encoder/aq_complexity.c
@@ -155,10 +155,10 @@
     const int aq_strength = get_aq_c_strength(cm->quant_params.base_qindex,
                                               cm->seq_params->bit_depth);
 
-    low_var_thresh =
-        (is_stat_consumption_stage_twopass(cpi))
-            ? AOMMAX(exp(cpi->ppi->twopass.mb_av_energy), MIN_DEFAULT_LV_THRESH)
-            : DEFAULT_LV_THRESH;
+    low_var_thresh = (is_stat_consumption_stage_twopass(cpi))
+                         ? AOMMAX(exp(cpi->twopass_frame.mb_av_energy),
+                                  MIN_DEFAULT_LV_THRESH)
+                         : DEFAULT_LV_THRESH;
 
     av1_setup_src_planes(mb, cpi->source, mi_row, mi_col, num_planes, bs);
     logvar = av1_log_block_var(cpi, mb, bs);
diff --git a/av1/encoder/aq_variance.c b/av1/encoder/aq_variance.c
index 02daa8f..c2d0a07 100644
--- a/av1/encoder/aq_variance.c
+++ b/av1/encoder/aq_variance.c
@@ -51,7 +51,7 @@
   int resolution_change =
       cm->prev_frame && (cm->width != cm->prev_frame->width ||
                          cm->height != cm->prev_frame->height);
-  int avg_energy = (int)(cpi->ppi->twopass.mb_av_energy - 2);
+  int avg_energy = (int)(cpi->twopass_frame.mb_av_energy - 2);
   double avg_ratio;
   if (avg_energy > 7) avg_energy = 7;
   if (avg_energy < 0) avg_energy = 0;
@@ -166,7 +166,7 @@
                                    BLOCK_SIZE bs) {
   double energy, energy_midpoint;
   energy_midpoint = (is_stat_consumption_stage_twopass(cpi))
-                        ? cpi->ppi->twopass.frame_avg_haar_energy
+                        ? cpi->twopass_frame.frame_avg_haar_energy
                         : DEFAULT_E_MIDPOINT;
   energy = av1_log_block_wavelet_energy(x, bs) - energy_midpoint;
   return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX);
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index e78c85a..ec956a8 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1332,7 +1332,7 @@
        * two pass*/
       cpi->ppi->twopass.stats_buf_ctx->stats_in_start =
           oxcf->twopass_stats_in.buf;
-      cpi->ppi->twopass.stats_in =
+      cpi->twopass_frame.stats_in =
           cpi->ppi->twopass.stats_buf_ctx->stats_in_start;
       cpi->ppi->twopass.stats_buf_ctx->stats_in_end =
           &cpi->ppi->twopass.stats_buf_ctx->stats_in_start[packets - 1];
@@ -3113,7 +3113,7 @@
   int64_t frame_avg_wavelet_energy = av1_haar_ac_sad_mxn_uint8_input(
       src, stride, hbd, num_8x8_rows, num_8x8_cols);
 
-  twopass->frame_avg_haar_energy =
+  cpi->twopass_frame.frame_avg_haar_energy =
       log(((double)frame_avg_wavelet_energy / num_mbs) + 1.0);
 }
 #endif
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 7736ae0..8876f5f 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -3105,6 +3105,11 @@
    */
   VBR_RATECTRL_INFO vbr_rc_info;
 #endif
+
+  /*!
+   * Frame level twopass status and control data
+   */
+  TWO_PASS_FRAME twopass_frame;
 } AV1_COMP;
 
 /*!
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 7adb91e..d89a763 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -252,18 +252,12 @@
   // here.
   FIRSTPASS_STATS *frame_stats_arr[MAX_LAP_BUFFERS + 1];
   int frame_stats_next_idx;  // Index to next unused element in frame_stats_arr.
-  const FIRSTPASS_STATS *stats_in;
   STATS_BUFFER_CTX *stats_buf_ctx;
   int first_pass_done;
   int64_t bits_left;
   double modified_error_min;
   double modified_error_max;
   double modified_error_left;
-  double mb_av_energy;
-  double frame_avg_haar_energy;
-
-  // An indication of the content type of the current frame
-  FRAME_CONTENT_TYPE fr_content_type;
 
   // Projected total bits available for a key frame group of frames
   int64_t kf_group_bits;
@@ -288,6 +282,19 @@
   /*!\endcond */
 } TWO_PASS;
 
+/*!
+ * \brief Frame level Two pass status and control data.
+ */
+typedef struct {
+  /*!\cond */
+  const FIRSTPASS_STATS *stats_in;
+  double mb_av_energy;
+  // An indication of the content type of the current frame
+  FRAME_CONTENT_TYPE fr_content_type;
+  double frame_avg_haar_energy;
+  /*!\endcond */
+} TWO_PASS_FRAME;
+
 /*!\cond */
 
 // This structure contains several key parameters to be accumulated for this
@@ -356,6 +363,7 @@
 
 static INLINE int is_fp_wavelet_energy_invalid(
     const FIRSTPASS_STATS *fp_stats) {
+  assert(fp_stats != NULL);
   return (fp_stats->frame_avg_wavelet_energy < 0);
 }
 
diff --git a/av1/encoder/gop_structure.c b/av1/encoder/gop_structure.c
index feb5053..f474093 100644
--- a/av1/encoder/gop_structure.c
+++ b/av1/encoder/gop_structure.c
@@ -409,9 +409,10 @@
 
 // Set parameters for frames between 'start' and 'end' (excluding both).
 static void set_multi_layer_params(
-    const TWO_PASS *twopass, GF_GROUP *const gf_group,
-    const PRIMARY_RATE_CONTROL *p_rc, RATE_CONTROL *rc, FRAME_INFO *frame_info,
-    int start, int end, int *cur_frame_idx, int *frame_ind,
+    const TWO_PASS *twopass, const TWO_PASS_FRAME *twopass_frame,
+    GF_GROUP *const gf_group, const PRIMARY_RATE_CONTROL *p_rc,
+    RATE_CONTROL *rc, FRAME_INFO *frame_info, int start, int end,
+    int *cur_frame_idx, int *frame_ind,
 #if CONFIG_FRAME_PARALLEL_ENCODE
     int *parallel_frame_count, int max_parallel_frames,
     int do_frame_parallel_encode, int *first_frame_index,
@@ -429,8 +430,9 @@
       gf_group->arf_src_offset[*frame_ind] = 0;
       gf_group->cur_frame_idx[*frame_ind] = *cur_frame_idx;
       gf_group->layer_depth[*frame_ind] = MAX_ARF_LAYERS;
-      gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
-          twopass, p_rc, frame_info, start, end - start, 0, NULL, NULL, 0);
+      gf_group->arf_boost[*frame_ind] =
+          av1_calc_arf_boost(twopass, twopass_frame, p_rc, frame_info, start,
+                             end - start, 0, NULL, NULL, 0);
       gf_group->frame_type[*frame_ind] = INTER_FRAME;
       gf_group->refbuf_state[*frame_ind] = REFBUF_UPDATE;
       gf_group->max_layer_depth =
@@ -474,13 +476,14 @@
 #endif  // CONFIG_FRAME_PARALLEL_ENCODE
 
     // Get the boost factor for intermediate ARF frames.
-    gf_group->arf_boost[*frame_ind] = av1_calc_arf_boost(
-        twopass, p_rc, frame_info, m, end - m, m - start, NULL, NULL, 0);
+    gf_group->arf_boost[*frame_ind] =
+        av1_calc_arf_boost(twopass, twopass_frame, p_rc, frame_info, m, end - m,
+                           m - start, NULL, NULL, 0);
     ++(*frame_ind);
 
     // Frames displayed before this internal ARF.
-    set_multi_layer_params(twopass, gf_group, p_rc, rc, frame_info, start, m,
-                           cur_frame_idx, frame_ind,
+    set_multi_layer_params(twopass, twopass_frame, gf_group, p_rc, rc,
+                           frame_info, start, m, cur_frame_idx, frame_ind,
 #if CONFIG_FRAME_PARALLEL_ENCODE
                            parallel_frame_count, max_parallel_frames,
                            do_frame_parallel_encode, first_frame_index,
@@ -503,8 +506,8 @@
     ++(*cur_frame_idx);
 
     // Frames displayed after this internal ARF.
-    set_multi_layer_params(twopass, gf_group, p_rc, rc, frame_info, m + 1, end,
-                           cur_frame_idx, frame_ind,
+    set_multi_layer_params(twopass, twopass_frame, gf_group, p_rc, rc,
+                           frame_info, m + 1, end, cur_frame_idx, frame_ind,
 #if CONFIG_FRAME_PARALLEL_ENCODE
                            parallel_frame_count, max_parallel_frames,
                            do_frame_parallel_encode, first_frame_index,
@@ -716,9 +719,9 @@
 
   // Rest of the frames.
   if (!is_multi_layer_configured)
-    set_multi_layer_params(twopass, gf_group, p_rc, rc, frame_info,
-                           cur_frame_index, gf_interval, &cur_frame_index,
-                           &frame_index,
+    set_multi_layer_params(twopass, &cpi->twopass_frame, gf_group, p_rc, rc,
+                           frame_info, cur_frame_index, gf_interval,
+                           &cur_frame_index, &frame_index,
 #if CONFIG_FRAME_PARALLEL_ENCODE
                            &parallel_frame_count, cpi->ppi->num_fp_contexts,
                            do_frame_parallel_encode, &first_frame_index,
diff --git a/av1/encoder/gop_structure.h b/av1/encoder/gop_structure.h
index 0a6f4ab..3d37e2b 100644
--- a/av1/encoder/gop_structure.h
+++ b/av1/encoder/gop_structure.h
@@ -67,6 +67,7 @@
 
 /*!\cond */
 int av1_calc_arf_boost(const TWO_PASS *twopass,
+                       const TWO_PASS_FRAME *twopass_frame,
                        const PRIMARY_RATE_CONTROL *p_rc, FRAME_INFO *frame_info,
                        int offset, int f_frames, int b_frames,
                        int *num_fpstats_used, int *num_fpstats_required,
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index a96b292..151fe00 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -88,38 +88,45 @@
 
 // Resets the first pass file to the given position using a relative seek from
 // the current position.
-static void reset_fpf_position(TWO_PASS *p, const FIRSTPASS_STATS *position) {
-  p->stats_in = position;
+static void reset_fpf_position(TWO_PASS_FRAME *p_frame,
+                               const FIRSTPASS_STATS *position) {
+  p_frame->stats_in = position;
 }
 
-static int input_stats(TWO_PASS *p, FIRSTPASS_STATS *fps) {
-  if (p->stats_in >= p->stats_buf_ctx->stats_in_end) return EOF;
+static int input_stats(TWO_PASS *p, TWO_PASS_FRAME *p_frame,
+                       FIRSTPASS_STATS *fps) {
+  if (p_frame->stats_in >= p->stats_buf_ctx->stats_in_end) return EOF;
 
-  *fps = *p->stats_in;
-  ++p->stats_in;
+  *fps = *p_frame->stats_in;
+  ++p_frame->stats_in;
   return 1;
 }
 
-static int input_stats_lap(TWO_PASS *p, FIRSTPASS_STATS *fps) {
-  if (p->stats_in >= p->stats_buf_ctx->stats_in_end) return EOF;
+static int input_stats_lap(TWO_PASS *p, TWO_PASS_FRAME *p_frame,
+                           FIRSTPASS_STATS *fps) {
+  if (p_frame->stats_in >= p->stats_buf_ctx->stats_in_end) return EOF;
 
-  *fps = *p->stats_in;
+  *fps = *p_frame->stats_in;
   /* Move old stats[0] out to accommodate for next frame stats  */
   memmove(p->frame_stats_arr[0], p->frame_stats_arr[1],
-          (p->stats_buf_ctx->stats_in_end - p->stats_in - 1) *
+          (p->stats_buf_ctx->stats_in_end - p_frame->stats_in - 1) *
               sizeof(FIRSTPASS_STATS));
   p->stats_buf_ctx->stats_in_end--;
   return 1;
 }
 
 // Read frame stats at an offset from the current position.
-static const FIRSTPASS_STATS *read_frame_stats(const TWO_PASS *p, int offset) {
-  if ((offset >= 0 && p->stats_in + offset >= p->stats_buf_ctx->stats_in_end) ||
-      (offset < 0 && p->stats_in + offset < p->stats_buf_ctx->stats_in_start)) {
+static const FIRSTPASS_STATS *read_frame_stats(const TWO_PASS *p,
+                                               const TWO_PASS_FRAME *p_frame,
+                                               int offset) {
+  if ((offset >= 0 &&
+       p_frame->stats_in + offset >= p->stats_buf_ctx->stats_in_end) ||
+      (offset < 0 &&
+       p_frame->stats_in + offset < p->stats_buf_ctx->stats_in_start)) {
     return NULL;
   }
 
-  return &p->stats_in[offset];
+  return &p_frame->stats_in[offset];
 }
 
 static void subtract_stats(FIRSTPASS_STATS *section,
@@ -416,6 +423,7 @@
 // by a static section. For example in slide shows where there is a fade
 // between slides. This is to help with more optimal kf and gf positioning.
 static int detect_transition_to_still(TWO_PASS *const twopass,
+                                      TWO_PASS_FRAME *const twopass_frame,
                                       const int min_gf_interval,
                                       const int frame_interval,
                                       const int still_interval,
@@ -429,7 +437,7 @@
     int j;
     // Look ahead a few frames to see if static condition persists...
     for (j = 0; j < still_interval; ++j) {
-      const FIRSTPASS_STATS *stats = &twopass->stats_in[j];
+      const FIRSTPASS_STATS *stats = &twopass_frame->stats_in[j];
       if (stats >= twopass->stats_buf_ctx->stats_in_end) break;
 
       if (stats->pcnt_inter - stats->pcnt_motion < 0.999) break;
@@ -443,8 +451,10 @@
 // This function detects a flash through the high relative pcnt_second_ref
 // score in the frame following a flash frame. The offset passed in should
 // reflect this.
-static int detect_flash(const TWO_PASS *twopass, const int offset) {
-  const FIRSTPASS_STATS *const next_frame = read_frame_stats(twopass, offset);
+static int detect_flash(const TWO_PASS *twopass,
+                        const TWO_PASS_FRAME *twopass_frame, const int offset) {
+  const FIRSTPASS_STATS *const next_frame =
+      read_frame_stats(twopass, twopass_frame, offset);
 
   // What we are looking for here is a situation where there is a
   // brief break in prediction (such as a flash) but subsequent frames
@@ -639,6 +649,7 @@
 #define GF_MIN_BOOST 50
 #define MIN_DECAY_FACTOR 0.01
 int av1_calc_arf_boost(const TWO_PASS *twopass,
+                       const TWO_PASS_FRAME *twopass_frame,
                        const PRIMARY_RATE_CONTROL *p_rc, FRAME_INFO *frame_info,
                        int offset, int f_frames, int b_frames,
                        int *num_fpstats_used, int *num_fpstats_required,
@@ -653,7 +664,8 @@
 
   // Search forward from the proposed arf/next gf position.
   for (i = 0; i < f_frames; ++i) {
-    const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset);
+    const FIRSTPASS_STATS *this_frame =
+        read_frame_stats(twopass, twopass_frame, i + offset);
     if (this_frame == NULL) break;
 
     // Update the motion related elements to the boost calculation.
@@ -663,8 +675,8 @@
 
     // We want to discount the flash frame itself and the recovery
     // frame that follows as both will have poor scores.
-    flash_detected = detect_flash(twopass, i + offset) ||
-                     detect_flash(twopass, i + offset + 1);
+    flash_detected = detect_flash(twopass, twopass_frame, i + offset) ||
+                     detect_flash(twopass, twopass_frame, i + offset + 1);
 
     // Accumulate the effect of prediction quality decay.
     if (!flash_detected) {
@@ -688,7 +700,8 @@
   init_gf_stats(&gf_stats);
   // Search backward towards last gf position.
   for (i = -1; i >= -b_frames; --i) {
-    const FIRSTPASS_STATS *this_frame = read_frame_stats(twopass, i + offset);
+    const FIRSTPASS_STATS *this_frame =
+        read_frame_stats(twopass, twopass_frame, i + offset);
     if (this_frame == NULL) break;
 
     // Update the motion related elements to the boost calculation.
@@ -698,8 +711,8 @@
 
     // We want to discount the the flash frame itself and the recovery
     // frame that follows as both will have poor scores.
-    flash_detected = detect_flash(twopass, i + offset) ||
-                     detect_flash(twopass, i + offset + 1);
+    flash_detected = detect_flash(twopass, twopass_frame, i + offset) ||
+                     detect_flash(twopass, twopass_frame, i + offset + 1);
 
     // Cumulative effect of prediction quality decay.
     if (!flash_detected) {
@@ -980,9 +993,10 @@
   if (!flash_detected) {
     // Break clause to detect very still sections after motion. For example,
     // a static image after a fade or other transition.
-    if (detect_transition_to_still(
-            twopass, rc->min_gf_interval, frame_index - cur_start, 5,
-            gf_stats->loop_decay_rate, gf_stats->last_loop_decay_rate)) {
+    if (detect_transition_to_still(twopass, &cpi->twopass_frame,
+                                   rc->min_gf_interval, frame_index - cur_start,
+                                   5, gf_stats->loop_decay_rate,
+                                   gf_stats->last_loop_decay_rate)) {
       return 1;
     }
   }
@@ -1869,7 +1883,7 @@
   PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
   TWO_PASS *const twopass = &cpi->ppi->twopass;
   FIRSTPASS_STATS next_frame;
-  const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+  const FIRSTPASS_STATS *const start_pos = cpi->twopass_frame.stats_in;
   const FIRSTPASS_STATS *const stats = start_pos - (rc->frames_since_key == 0);
 
   const int f_w = cpi->common.width;
@@ -1912,13 +1926,13 @@
       // reached maximum len, but nothing special yet (almost static)
       // let's look at the next interval
       cut_here = 1;
-    } else if (EOF == input_stats(twopass, &next_frame)) {
+    } else if (EOF == input_stats(twopass, &cpi->twopass_frame, &next_frame)) {
       // reaches last frame, break
       cut_here = 2;
     } else {
       // Test for the case where there is a brief flash but the prediction
       // quality back to an earlier frame is then restored.
-      flash_detected = detect_flash(twopass, 0);
+      flash_detected = detect_flash(twopass, &cpi->twopass_frame, 0);
       // TODO(bohanli): remove redundant accumulations here, or unify
       // this and the ones in define_gf_group
       accumulate_next_frame_stats(&next_frame, flash_detected,
@@ -2081,7 +2095,7 @@
       count_cuts++;
 
       // reset pointers to the shrinked location
-      twopass->stats_in = start_pos + cur_last;
+      cpi->twopass_frame.stats_in = start_pos + cur_last;
       cur_start = cur_last;
       int cur_region_idx =
           find_regions_index(regions, num_regions, cur_start + 1 + offset);
@@ -2104,7 +2118,7 @@
     p_rc->gf_intervals[n - 1] = cut_pos[n] - cut_pos[n - 1];
   }
   p_rc->cur_gf_index = 0;
-  twopass->stats_in = start_pos;
+  cpi->twopass_frame.stats_in = start_pos;
 }
 
 static void correct_frames_to_key(AV1_COMP *cpi) {
@@ -2205,7 +2219,7 @@
   // If forward keyframes are enabled, ensure the final gf group obeys the
   // MIN_FWD_KF_INTERVAL.
   const int is_last_kf =
-      (twopass->stats_in - arf_position + rc->frames_to_key) >=
+      (cpi->twopass_frame.stats_in - arf_position + rc->frames_to_key) >=
       twopass->stats_buf_ctx->stats_in_end;
 
   if (cpi->oxcf.kf_cfg.fwd_kf_enabled && use_alt_ref && !is_last_kf &&
@@ -2282,7 +2296,7 @@
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
   TWO_PASS *const twopass = &cpi->ppi->twopass;
   FIRSTPASS_STATS next_frame;
-  const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+  const FIRSTPASS_STATS *const start_pos = cpi->twopass_frame.stats_in;
   GF_GROUP *gf_group = &cpi->ppi->gf_group;
   FRAME_INFO *frame_info = &cpi->frame_info;
   const GFConfig *const gf_cfg = &oxcf->gf_cfg;
@@ -2332,7 +2346,7 @@
   // get the determined gf group length from p_rc->gf_intervals
   while (i < p_rc->gf_intervals[p_rc->cur_gf_index]) {
     // read in the next frame
-    if (EOF == input_stats(twopass, &next_frame)) break;
+    if (EOF == input_stats(twopass, &cpi->twopass_frame, &next_frame)) break;
     // Accumulate error score of frames in this gf group.
     double mod_frame_err =
         calculate_modified_err(frame_info, twopass, oxcf, &next_frame);
@@ -2341,17 +2355,17 @@
     ++i;
   }
 
-  reset_fpf_position(twopass, start_pos);
+  reset_fpf_position(&cpi->twopass_frame, start_pos);
 
   i = is_intra_only;
-  input_stats(twopass, &next_frame);
+  input_stats(twopass, &cpi->twopass_frame, &next_frame);
   while (i < p_rc->gf_intervals[p_rc->cur_gf_index]) {
     // read in the next frame
-    if (EOF == input_stats(twopass, &next_frame)) break;
+    if (EOF == input_stats(twopass, &cpi->twopass_frame, &next_frame)) break;
 
     // Test for the case where there is a brief flash but the prediction
     // quality back to an earlier frame is then restored.
-    flash_detected = detect_flash(twopass, 0);
+    flash_detected = detect_flash(twopass, &cpi->twopass_frame, 0);
 
     // accumulate stats for next frame
     accumulate_next_frame_stats(&next_frame, flash_detected,
@@ -2448,21 +2462,21 @@
 
     // Calculate the boost for alt ref.
     p_rc->gfu_boost = av1_calc_arf_boost(
-        twopass, p_rc, frame_info, alt_offset, forward_frames, ext_len,
-        &p_rc->num_stats_used_for_gfu_boost,
+        twopass, &cpi->twopass_frame, p_rc, frame_info, alt_offset,
+        forward_frames, ext_len, &p_rc->num_stats_used_for_gfu_boost,
         &p_rc->num_stats_required_for_gfu_boost, cpi->ppi->lap_enabled);
   } else {
-    reset_fpf_position(twopass, start_pos);
+    reset_fpf_position(&cpi->twopass_frame, start_pos);
     gf_group->max_layer_depth_allowed = 0;
     set_baseline_gf_interval(cpi, i, active_max_gf_interval, use_alt_ref,
                              is_final_pass);
 
     p_rc->gfu_boost = AOMMIN(
         MAX_GF_BOOST,
-        av1_calc_arf_boost(twopass, p_rc, frame_info, alt_offset, ext_len, 0,
-                           &p_rc->num_stats_used_for_gfu_boost,
-                           &p_rc->num_stats_required_for_gfu_boost,
-                           cpi->ppi->lap_enabled));
+        av1_calc_arf_boost(
+            twopass, &cpi->twopass_frame, p_rc, frame_info, alt_offset, ext_len,
+            0, &p_rc->num_stats_used_for_gfu_boost,
+            &p_rc->num_stats_required_for_gfu_boost, cpi->ppi->lap_enabled));
   }
 
 #define LAST_ALR_BOOST_FACTOR 0.2f
@@ -2478,7 +2492,7 @@
   rc->frames_till_gf_update_due = p_rc->baseline_gf_interval;
 
   // Reset the file position.
-  reset_fpf_position(twopass, start_pos);
+  reset_fpf_position(&cpi->twopass_frame, start_pos);
 
   if (cpi->ppi->lap_enabled) {
     // Since we don't have enough stats to know the actual error of the
@@ -2523,7 +2537,7 @@
   av1_gop_setup_structure(cpi);
 
   // Reset the file position.
-  reset_fpf_position(twopass, start_pos);
+  reset_fpf_position(&cpi->twopass_frame, start_pos);
 
   // Calculate a section intra ratio used in setting max loop filter.
   if (rc->frames_since_key != 0) {
@@ -2639,7 +2653,7 @@
              second_ref_usage_thresh_max_delta;
 }
 
-static int test_candidate_kf(TWO_PASS *twopass,
+static int test_candidate_kf(TWO_PASS *twopass, TWO_PASS_FRAME *twopass_frame,
                              const FIRSTPASS_STATS *last_frame,
                              const FIRSTPASS_STATS *this_frame,
                              const FIRSTPASS_STATS *next_frame,
@@ -2658,11 +2672,11 @@
 
   if (scenecut_mode == ENABLE_SCENECUT_MODE_1) {
     curr_frame = *this_frame;
-    const FIRSTPASS_STATS *const start_position = twopass->stats_in;
+    const FIRSTPASS_STATS *const start_position = twopass_frame->stats_in;
     for (num_future_frames = 0; num_future_frames < SCENE_CUT_KEY_TEST_INTERVAL;
          num_future_frames++)
-      if (EOF == input_stats(twopass, &curr_frame)) break;
-    reset_fpf_position(twopass, start_position);
+      if (EOF == input_stats(twopass, twopass_frame, &curr_frame)) break;
+    reset_fpf_position(twopass_frame, start_position);
     if (num_future_frames < 3) {
       return 0;
     } else {
@@ -2694,7 +2708,7 @@
            DOUBLE_DIVIDE_CHECK(next_frame->coded_error)) >
           II_IMPROVEMENT_THRESHOLD))))) {
     int i;
-    const FIRSTPASS_STATS *start_pos = twopass->stats_in;
+    const FIRSTPASS_STATS *start_pos = twopass_frame->stats_in;
     double boost_score = 0.0;
     double old_boost_score = 0.0;
     double decay_accumulator = 1.0;
@@ -2703,7 +2717,7 @@
     for (i = 0; i < total_frames_to_test; ++i) {
       // Get the next frame details
       FIRSTPASS_STATS local_next_frame;
-      if (EOF == input_stats(twopass, &local_next_frame)) break;
+      if (EOF == input_stats(twopass, twopass_frame, &local_next_frame)) break;
       double next_iiratio = (BOOST_FACTOR * local_next_frame.intra_error /
                              DOUBLE_DIVIDE_CHECK(local_next_frame.coded_error));
 
@@ -2741,7 +2755,7 @@
     }
 
     // Reset the file position
-    reset_fpf_position(twopass, start_pos);
+    reset_fpf_position(twopass_frame, start_pos);
   }
   return is_viable_kf;
 }
@@ -2831,7 +2845,7 @@
   const int num_mbs = (oxcf->resize_cfg.resize_mode != RESIZE_NONE)
                           ? cpi->initial_mbs
                           : cpi->common.mi_params.MBs;
-  while (twopass->stats_in < twopass->stats_buf_ctx->stats_in_end &&
+  while (cpi->twopass_frame.stats_in < twopass->stats_buf_ctx->stats_in_end &&
          frames_to_key < num_frames_to_detect_scenecut) {
     // Accumulate total number of stats available till next key frame
     num_stats_used_for_kf_boost++;
@@ -2843,25 +2857,25 @@
 
     // Load the next frame's stats.
     last_frame = *this_frame;
-    input_stats(twopass, this_frame);
+    input_stats(twopass, &cpi->twopass_frame, this_frame);
 
     // Provided that we are not at the end of the file...
     if ((cpi->ppi->p_rc.enable_scenecut_detection > 0) && kf_cfg->auto_key &&
-        twopass->stats_in < twopass->stats_buf_ctx->stats_in_end) {
+        cpi->twopass_frame.stats_in < twopass->stats_buf_ctx->stats_in_end) {
       double loop_decay_rate;
 
       // Check for a scene cut.
       if (frames_since_key >= kf_cfg->key_freq_min &&
-          test_candidate_kf(twopass, &last_frame, this_frame, twopass->stats_in,
-                            frames_since_key, oxcf->rc_cfg.mode,
-                            cpi->ppi->p_rc.enable_scenecut_detection,
-                            num_mbs)) {
+          test_candidate_kf(
+              twopass, &cpi->twopass_frame, &last_frame, this_frame,
+              cpi->twopass_frame.stats_in, frames_since_key, oxcf->rc_cfg.mode,
+              cpi->ppi->p_rc.enable_scenecut_detection, num_mbs)) {
         scenecut_detected = 1;
         break;
       }
 
       // How fast is the prediction quality decaying?
-      loop_decay_rate = get_prediction_decay_rate(twopass->stats_in);
+      loop_decay_rate = get_prediction_decay_rate(cpi->twopass_frame.stats_in);
 
       // We want to know something about the recent past... rather than
       // as used elsewhere where we are concerned with decay in prediction
@@ -2874,9 +2888,9 @@
       // Special check for transition or high motion followed by a
       // static scene.
       if (frames_since_key >= kf_cfg->key_freq_min &&
-          detect_transition_to_still(twopass, rc->min_gf_interval, i,
-                                     kf_cfg->key_freq_max - i, loop_decay_rate,
-                                     decay_accumulator)) {
+          detect_transition_to_still(
+              twopass, &cpi->twopass_frame, rc->min_gf_interval, i,
+              kf_cfg->key_freq_max - i, loop_decay_rate, decay_accumulator)) {
         scenecut_detected = 1;
         // In the case of transition followed by a static scene, the key frame
         // could be a good predictor for the following frames, therefore we
@@ -2906,13 +2920,14 @@
     frames_to_key = num_frames_to_next_key;
 
   if (!kf_cfg->fwd_kf_enabled || scenecut_detected ||
-      twopass->stats_in >= twopass->stats_buf_ctx->stats_in_end)
+      cpi->twopass_frame.stats_in >= twopass->stats_buf_ctx->stats_in_end)
     p_rc->next_is_fwd_key = 0;
 
   return frames_to_key;
 }
 
 static double get_kf_group_avg_error(TWO_PASS *twopass,
+                                     TWO_PASS_FRAME *twopass_frame,
                                      const FIRSTPASS_STATS *first_frame,
                                      const FIRSTPASS_STATS *start_position,
                                      int frames_to_key) {
@@ -2920,11 +2935,11 @@
   int num_frames, i;
   double kf_group_avg_error = 0.0;
 
-  reset_fpf_position(twopass, start_position);
+  reset_fpf_position(twopass_frame, start_position);
 
   for (i = 0; i < frames_to_key; ++i) {
     kf_group_avg_error += cur_frame.coded_error;
-    if (EOF == input_stats(twopass, &cur_frame)) break;
+    if (EOF == input_stats(twopass, twopass_frame, &cur_frame)) break;
   }
   num_frames = i + 1;
   num_frames = AOMMIN(num_frames, frames_to_key);
@@ -2963,7 +2978,7 @@
   int num_frames = 0;
   // Accumulate total stat using available number of stats.
   for (num_frames = 0; num_frames < (rc->frames_to_key - 1); ++num_frames) {
-    if (EOF == input_stats(twopass, &cur_frame)) break;
+    if (EOF == input_stats(twopass, &cpi->twopass_frame, &cur_frame)) break;
     av1_accumulate_stats(avg_frame_stat, &cur_frame);
   }
 
@@ -3022,7 +3037,9 @@
   if (use_avg_stat) num_stat_used = calc_avg_stats(cpi, &frame_stat);
 
   for (i = num_stat_used; i < (rc->frames_to_key - 1); ++i) {
-    if (!use_avg_stat && EOF == input_stats(twopass, &frame_stat)) break;
+    if (!use_avg_stat &&
+        EOF == input_stats(twopass, &cpi->twopass_frame, &frame_stat))
+      break;
 
     // Monitor for static sections.
     // For the first frame in kf group, the second ref indicator is invalid.
@@ -3107,7 +3124,7 @@
     return;
   }
   int i;
-  const FIRSTPASS_STATS *const start_position = twopass->stats_in;
+  const FIRSTPASS_STATS *const start_position = cpi->twopass_frame.stats_in;
   int kf_bits = 0;
   double zero_motion_accumulator = 1.0;
   double boost_score = 0.0;
@@ -3150,7 +3167,7 @@
     rc->frames_to_key /= 2;
 
     // Reset to the start of the group.
-    reset_fpf_position(twopass, start_position);
+    reset_fpf_position(&cpi->twopass_frame, start_position);
 
     kf_group_err = 0.0;
 
@@ -3158,10 +3175,11 @@
     for (i = 0; i < rc->frames_to_key; ++i) {
       kf_group_err +=
           calculate_modified_err(frame_info, twopass, oxcf, &tmp_frame);
-      if (EOF == input_stats(twopass, &tmp_frame)) break;
+      if (EOF == input_stats(twopass, &cpi->twopass_frame, &tmp_frame)) break;
     }
     p_rc->next_key_frame_forced = 1;
-  } else if ((twopass->stats_in == twopass->stats_buf_ctx->stats_in_end &&
+  } else if ((cpi->twopass_frame.stats_in ==
+                  twopass->stats_buf_ctx->stats_in_end &&
               is_stat_consumption_stage_twopass(cpi)) ||
              rc->frames_to_key >= kf_cfg->key_freq_max) {
     p_rc->next_key_frame_forced = 1;
@@ -3173,7 +3191,7 @@
     p_rc->next_is_fwd_key |= p_rc->next_key_frame_forced;
 
   // Special case for the last key frame of the file.
-  if (twopass->stats_in >= twopass->stats_buf_ctx->stats_in_end) {
+  if (cpi->twopass_frame.stats_in >= twopass->stats_buf_ctx->stats_in_end) {
     // Accumulate kf group error.
     kf_group_err +=
         calculate_modified_err(frame_info, twopass, oxcf, this_frame);
@@ -3190,8 +3208,9 @@
     int64_t max_grp_bits;
 
     if (oxcf->rc_cfg.vbr_corpus_complexity_lap) {
-      kf_group_avg_error = get_kf_group_avg_error(
-          twopass, &first_frame, start_position, rc->frames_to_key);
+      kf_group_avg_error =
+          get_kf_group_avg_error(twopass, &cpi->twopass_frame, &first_frame,
+                                 start_position, rc->frames_to_key);
     }
 
     // Default allocation based on bits left and relative
@@ -3224,13 +3243,13 @@
   }
 
   // Reset the first pass file position.
-  reset_fpf_position(twopass, start_position);
+  reset_fpf_position(&cpi->twopass_frame, start_position);
 
   // Scan through the kf group collating various stats used to determine
   // how many bits to spend on it.
   boost_score = get_kf_boost_score(cpi, kf_raw_err, &zero_motion_accumulator,
                                    &sr_accumulator, 0);
-  reset_fpf_position(twopass, start_position);
+  reset_fpf_position(&cpi->twopass_frame, start_position);
   // Store the zero motion percentage
   twopass->kf_zeromotion_pct = (int)(zero_motion_accumulator * 100.0);
 
@@ -3247,7 +3266,7 @@
       // TODO(any): Explore using average frame stats for AOM_Q as well.
       boost_score = get_kf_boost_score(
           cpi, kf_raw_err, &zero_motion_accumulator, &sr_accumulator, 1);
-      reset_fpf_position(twopass, start_position);
+      reset_fpf_position(&cpi->twopass_frame, start_position);
       p_rc->kf_boost += (int)boost_score;
     }
   }
@@ -3309,15 +3328,18 @@
   const TWO_PASS *const twopass = &cpi->ppi->twopass;
 
   return (!frame_is_intra_only(&cpi->common) &&
-          twopass->stats_in - 2 > twopass->stats_buf_ctx->stats_in_start &&
-          twopass->stats_in < twopass->stats_buf_ctx->stats_in_end &&
-          (twopass->stats_in - 1)->pcnt_inter -
-                  (twopass->stats_in - 1)->pcnt_motion ==
+          cpi->twopass_frame.stats_in - 2 >
+              twopass->stats_buf_ctx->stats_in_start &&
+          cpi->twopass_frame.stats_in < twopass->stats_buf_ctx->stats_in_end &&
+          (cpi->twopass_frame.stats_in - 1)->pcnt_inter -
+                  (cpi->twopass_frame.stats_in - 1)->pcnt_motion ==
               1 &&
-          (twopass->stats_in - 2)->pcnt_inter -
-                  (twopass->stats_in - 2)->pcnt_motion ==
+          (cpi->twopass_frame.stats_in - 2)->pcnt_inter -
+                  (cpi->twopass_frame.stats_in - 2)->pcnt_motion ==
               1 &&
-          twopass->stats_in->pcnt_inter - twopass->stats_in->pcnt_motion == 1);
+          cpi->twopass_frame.stats_in->pcnt_inter -
+                  cpi->twopass_frame.stats_in->pcnt_motion ==
+              1);
 }
 
 #define ARF_STATS_OUTPUT 0
@@ -3341,26 +3363,26 @@
 }
 
 static INLINE void set_twopass_params_based_on_fp_stats(
-    const AV1_COMP *cpi, const FIRSTPASS_STATS *this_frame_ptr) {
+    AV1_COMP *cpi, const FIRSTPASS_STATS *this_frame_ptr) {
   if (this_frame_ptr == NULL) return;
 
-  TWO_PASS *const twopass = &cpi->ppi->twopass;
+  TWO_PASS_FRAME *twopass_frame = &cpi->twopass_frame;
   // The multiplication by 256 reverses a scaling factor of (>> 8)
   // applied when combining MB error values for the frame.
-  twopass->mb_av_energy = log((this_frame_ptr->intra_error) + 1.0);
+  twopass_frame->mb_av_energy = log((this_frame_ptr->intra_error) + 1.0);
 
   const FIRSTPASS_STATS *const total_stats =
-      twopass->stats_buf_ctx->total_stats;
+      cpi->ppi->twopass.stats_buf_ctx->total_stats;
   if (is_fp_wavelet_energy_invalid(total_stats) == 0) {
-    twopass->frame_avg_haar_energy =
+    twopass_frame->frame_avg_haar_energy =
         log((this_frame_ptr->frame_avg_wavelet_energy) + 1.0);
   }
 
   // Set the frame content type flag.
   if (this_frame_ptr->intra_skip_pct >= FC_ANIMATION_THRESH)
-    twopass->fr_content_type = FC_GRAPHICS_ANIMATION;
+    twopass_frame->fr_content_type = FC_GRAPHICS_ANIMATION;
   else
-    twopass->fr_content_type = FC_NORMAL;
+    twopass_frame->fr_content_type = FC_NORMAL;
 }
 
 static void process_first_pass_stats(AV1_COMP *cpi,
@@ -3408,9 +3430,9 @@
   }
 
   if (cpi->ppi->lap_enabled) {
-    input_stats_lap(twopass, this_frame);
+    input_stats_lap(twopass, &cpi->twopass_frame, this_frame);
   } else {
-    input_stats(twopass, this_frame);
+    input_stats(twopass, &cpi->twopass_frame, this_frame);
   }
   set_twopass_params_based_on_fp_stats(cpi, this_frame);
 }
@@ -3573,11 +3595,11 @@
   GF_GROUP *const gf_group = &cpi->ppi->gf_group;
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
 
-  const FIRSTPASS_STATS *const start_pos = twopass->stats_in;
+  const FIRSTPASS_STATS *const start_pos = cpi->twopass_frame.stats_in;
 
-  if (is_stat_consumption_stage(cpi) && !twopass->stats_in) return;
+  if (is_stat_consumption_stage(cpi) && !cpi->twopass_frame.stats_in) return;
 
-  assert(twopass->stats_in != NULL);
+  assert(cpi->twopass_frame.stats_in != NULL);
   const int update_type = gf_group->update_type[cpi->gf_frame_index];
   frame_params->frame_type = gf_group->frame_type[cpi->gf_frame_index];
 
@@ -3595,8 +3617,9 @@
           oxcf->pass >= AOM_RC_SECOND_PASS) {
         cpi->partition_search_skippable_frame = is_skippable_frame(cpi);
       }
-      const FIRSTPASS_STATS *const this_frame_ptr = read_frame_stats(
-          twopass, gf_group->arf_src_offset[cpi->gf_frame_index]);
+      const FIRSTPASS_STATS *const this_frame_ptr =
+          read_frame_stats(twopass, &cpi->twopass_frame,
+                           gf_group->arf_src_offset[cpi->gf_frame_index]);
       set_twopass_params_based_on_fp_stats(cpi, this_frame_ptr);
       return;
     }
@@ -3626,7 +3649,7 @@
     // Define next KF group and assign bits to it.
     int kf_offset = rc->frames_to_key;
     if (rc->frames_to_key < 0) {
-      this_frame = *(twopass->stats_in - 1);
+      this_frame = *(cpi->twopass_frame.stats_in - 1);
     } else {
       frame_params->frame_type = KEY_FRAME;
     }
@@ -3674,7 +3697,7 @@
 
   // Define a new GF/ARF group. (Should always enter here for key frames).
   if (cpi->gf_frame_index == gf_group->size) {
-    const FIRSTPASS_STATS *const start_position = twopass->stats_in;
+    const FIRSTPASS_STATS *const start_position = cpi->twopass_frame.stats_in;
 
     if (cpi->ppi->lap_enabled && cpi->ppi->p_rc.enable_scenecut_detection) {
       int num_frames_to_detect_scenecut, frames_to_key;
@@ -3685,7 +3708,7 @@
         rc->frames_to_key = AOMMIN(rc->frames_to_key, frames_to_key);
     }
 
-    reset_fpf_position(twopass, start_position);
+    reset_fpf_position(&cpi->twopass_frame, start_position);
 
     int max_gop_length =
         (oxcf->gf_cfg.lag_in_frames >= 32 &&
@@ -3704,9 +3727,10 @@
       // how many frames we can analyze from this frame
       int rest_frames = AOMMIN(rc->frames_to_key + p_rc->next_is_fwd_key,
                                MAX_FIRSTPASS_ANALYSIS_FRAMES);
-      rest_frames = AOMMIN(
-          rest_frames, (int)(twopass->stats_buf_ctx->stats_in_end -
-                             twopass->stats_in + (rc->frames_since_key == 0)));
+      rest_frames =
+          AOMMIN(rest_frames, (int)(twopass->stats_buf_ctx->stats_in_end -
+                                    cpi->twopass_frame.stats_in +
+                                    (rc->frames_since_key == 0)));
       p_rc->frames_till_regions_update = rest_frames;
 
       if (cpi->ppi->lap_enabled) {
@@ -3716,12 +3740,13 @@
                        twopass->stats_buf_ctx->stats_in_end);
         estimate_coeff(twopass->stats_buf_ctx->stats_in_start,
                        twopass->stats_buf_ctx->stats_in_end);
-        identify_regions(twopass->stats_in, rest_frames,
+        identify_regions(cpi->twopass_frame.stats_in, rest_frames,
                          (rc->frames_since_key == 0), p_rc->regions,
                          &p_rc->num_regions);
       } else {
-        identify_regions(twopass->stats_in - (rc->frames_since_key == 0),
-                         rest_frames, 0, p_rc->regions, &p_rc->num_regions);
+        identify_regions(
+            cpi->twopass_frame.stats_in - (rc->frames_since_key == 0),
+            rest_frames, 0, p_rc->regions, &p_rc->num_regions);
       }
     }
 
@@ -3803,10 +3828,11 @@
 
   if (gf_group->update_type[cpi->gf_frame_index] == ARF_UPDATE ||
       gf_group->update_type[cpi->gf_frame_index] == INTNL_ARF_UPDATE) {
-    reset_fpf_position(twopass, start_pos);
+    reset_fpf_position(&cpi->twopass_frame, start_pos);
 
-    const FIRSTPASS_STATS *const this_frame_ptr = read_frame_stats(
-        twopass, gf_group->arf_src_offset[cpi->gf_frame_index]);
+    const FIRSTPASS_STATS *const this_frame_ptr =
+        read_frame_stats(twopass, &cpi->twopass_frame,
+                         gf_group->arf_src_offset[cpi->gf_frame_index]);
     set_twopass_params_based_on_fp_stats(cpi, this_frame_ptr);
   } else {
     // Update the total stats remaining structure.
@@ -3871,7 +3897,7 @@
   {
     const double avg_error =
         stats->coded_error / DOUBLE_DIVIDE_CHECK(stats->count);
-    const FIRSTPASS_STATS *s = twopass->stats_in;
+    const FIRSTPASS_STATS *s = cpi->twopass_frame.stats_in;
     double modified_error_total = 0.0;
     twopass->modified_error_min =
         (avg_error * oxcf->rc_cfg.vbrmin_section) / 100;
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index f4e05d3..cb5e3af 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -323,7 +323,7 @@
   sf->rt_sf.use_nonrd_pick_mode = 0;
   sf->rt_sf.use_real_time_ref_set = 0;
 
-  if (cpi->ppi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION ||
+  if (cpi->twopass_frame.fr_content_type == FC_GRAPHICS_ANIMATION ||
       cpi->use_screen_content_tools) {
     sf->mv_sf.exhaustive_searches_thresh = (1 << 20);
   } else {
@@ -814,7 +814,7 @@
   sf->rt_sf.use_nonrd_pick_mode = 0;
   sf->rt_sf.use_real_time_ref_set = 0;
 
-  if (cpi->ppi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION ||
+  if (cpi->twopass_frame.fr_content_type == FC_GRAPHICS_ANIMATION ||
       cpi->use_screen_content_tools) {
     sf->mv_sf.exhaustive_searches_thresh = (1 << 20);
   } else {
diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index c77d454..a131259 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -978,7 +978,7 @@
   const int q = av1_get_q(cpi);
   // Get correlation estimates from first-pass;
   const FIRSTPASS_STATS *stats =
-      cpi->ppi->twopass.stats_in - (cpi->rc.frames_since_key == 0);
+      cpi->twopass_frame.stats_in - (cpi->rc.frames_since_key == 0);
   double accu_coeff0 = 1.0, accu_coeff1 = 1.0;
   for (int i = 1; i <= max_after; i++) {
     if (stats + filter_frame_lookahead_idx + i >=