Facilitate LAP based single pass in VBR mode.

Accumulate total_stats with limited number of stats available,
use this to calculate avg_frame_qindex and active_worst_quality
for single pass VBR using LAP.

Change-Id: I8725fb72911e6cec5ba676ec0815ad0aad0854c0
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 928501f..cdd4fab 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -1818,9 +1818,10 @@
   return update_extra_cfg(ctx, &extra_cfg);
 }
 
-static aom_codec_err_t create_frame_stats_buffer(
-    FIRSTPASS_STATS **frame_stats_buffer, STATS_BUFFER_CTX *stats_buf_context,
-    int num_lap_buffers) {
+#if !CONFIG_REALTIME_ONLY
+static aom_codec_err_t create_stats_buffer(FIRSTPASS_STATS **frame_stats_buffer,
+                                           STATS_BUFFER_CTX *stats_buf_context,
+                                           int num_lap_buffers) {
   aom_codec_err_t res = AOM_CODEC_OK;
 
   int size = get_stats_buf_size(num_lap_buffers, MAX_LAG_BUFFERS);
@@ -1832,8 +1833,16 @@
   stats_buf_context->stats_in_end = stats_buf_context->stats_in_start;
   stats_buf_context->stats_in_buf_end =
       stats_buf_context->stats_in_start + size;
+
+  stats_buf_context->total_left_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS));
+  if (stats_buf_context->total_left_stats == NULL) return AOM_CODEC_MEM_ERROR;
+  av1_twopass_zero_stats(stats_buf_context->total_left_stats);
+  stats_buf_context->total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS));
+  if (stats_buf_context->total_stats == NULL) return AOM_CODEC_MEM_ERROR;
+  av1_twopass_zero_stats(stats_buf_context->total_stats);
   return res;
 }
+#endif
 
 static aom_codec_err_t create_context_and_bufferpool(
     AV1_COMP **p_cpi, BufferPool **p_buffer_pool, AV1EncoderConfig *oxcf,
@@ -1911,10 +1920,11 @@
       priv->oxcf.use_highbitdepth =
           (ctx->init_flags & AOM_CODEC_USE_HIGHBITDEPTH) ? 1 : 0;
 
-      res =
-          create_frame_stats_buffer(&priv->frame_stats_buffer,
-                                    &priv->stats_buf_context, *num_lap_buffers);
+#if !CONFIG_REALTIME_ONLY
+      res = create_stats_buffer(&priv->frame_stats_buffer,
+                                &priv->stats_buf_context, *num_lap_buffers);
       if (res != AOM_CODEC_OK) return AOM_CODEC_MEM_ERROR;
+#endif
 
       res = create_context_and_bufferpool(
           &priv->cpi, &priv->buffer_pool, &priv->oxcf, &priv->pkt_list.head,
@@ -1935,9 +1945,6 @@
   return res;
 }
 
-static void destroy_frame_stats_buffer(FIRSTPASS_STATS *frame_stats_buffer) {
-  aom_free(frame_stats_buffer);
-}
 static void destroy_context_and_bufferpool(AV1_COMP *cpi,
                                            BufferPool *buffer_pool) {
   av1_remove_compressor(cpi);
@@ -1947,6 +1954,13 @@
   aom_free(buffer_pool);
 }
 
+static void destroy_stats_buffer(STATS_BUFFER_CTX *stats_buf_context,
+                                 FIRSTPASS_STATS *frame_stats_buffer) {
+  aom_free(stats_buf_context->total_left_stats);
+  aom_free(stats_buf_context->total_stats);
+  aom_free(frame_stats_buffer);
+}
+
 static aom_codec_err_t encoder_destroy(aom_codec_alg_priv_t *ctx) {
   free(ctx->cx_data);
   destroy_context_and_bufferpool(ctx->cpi, ctx->buffer_pool);
@@ -1957,7 +1971,7 @@
     ctx->cpi_lap->lookahead = NULL;
     destroy_context_and_bufferpool(ctx->cpi_lap, ctx->buffer_pool_lap);
   }
-  destroy_frame_stats_buffer(ctx->frame_stats_buffer);
+  destroy_stats_buffer(&ctx->stats_buf_context, ctx->frame_stats_buffer);
   aom_free(ctx);
   return AOM_CODEC_OK;
 }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 2d2e020..6c1fb2c 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2748,7 +2748,7 @@
   oxcf->target_bandwidth = AOMMIN(oxcf->target_bandwidth, max_bitrate);
   // Also need to update cpi->twopass.bits_left.
   TWO_PASS *const twopass = &cpi->twopass;
-  FIRSTPASS_STATS *stats = twopass->total_stats;
+  FIRSTPASS_STATS *stats = twopass->stats_buf_ctx->total_stats;
   if (stats != NULL)
     cpi->twopass.bits_left =
         (int64_t)(stats->duration * cpi->oxcf.target_bandwidth / 10000000.0);
@@ -3156,9 +3156,7 @@
   cpi->twopass.stats_in = cpi->twopass.stats_buf_ctx->stats_in_start;
 
 #if !CONFIG_REALTIME_ONLY
-  if (is_stat_generation_stage(cpi)) {
-    av1_init_first_pass(cpi);
-  } else if (is_stat_consumption_stage(cpi)) {
+  if (is_stat_consumption_stage(cpi)) {
     const size_t packet_sz = sizeof(FIRSTPASS_STATS);
     const int packets = (int)(oxcf->two_pass_stats_in.sz / packet_sz);
 
@@ -3668,9 +3666,6 @@
 #endif  // CONFIG_HTB_TRELLIS
   av1_free_ref_frame_buffers(cm->buffer_pool);
 
-  aom_free(cpi->twopass.total_stats);
-  aom_free(cpi->twopass.total_left_stats);
-
   aom_free(cpi);
 
 #ifdef OUTPUT_YUV_SKINMAP
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index bbe37e6..0955510 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -136,16 +136,9 @@
   section->duration += frame->duration;
 }
 
-void av1_init_first_pass(AV1_COMP *cpi) {
-  if (!cpi->lap_enabled) {
-    cpi->twopass.total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS));
-    av1_twopass_zero_stats(cpi->twopass.total_stats);
-  }
-}
-
 void av1_end_first_pass(AV1_COMP *cpi) {
-  if (cpi->twopass.total_stats)
-    output_stats(cpi->twopass.total_stats, cpi->output_pkt_list);
+  if (cpi->twopass.stats_buf_ctx->total_stats)
+    output_stats(cpi->twopass.stats_buf_ctx->total_stats, cpi->output_pkt_list);
 }
 
 static aom_variance_fn_t get_block_variance_fn(BLOCK_SIZE bsize) {
@@ -820,8 +813,8 @@
   // local variable 'fps'), and then cpi->output_pkt_list will point to it.
   *this_frame_stats = fps;
   output_stats(this_frame_stats, cpi->output_pkt_list);
-  if (twopass->total_stats != NULL) {
-    accumulate_stats(twopass->total_stats, &fps);
+  if (cpi->twopass.stats_buf_ctx->total_stats != NULL) {
+    accumulate_stats(cpi->twopass.stats_buf_ctx->total_stats, &fps);
   }
   /*In the case of two pass, first pass uses it as a circular buffer,
    * when LAP is enabled it is used as a linear buffer*/
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index b7f1fd0..99d4445 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -133,11 +133,12 @@
   FIRSTPASS_STATS *stats_in_start;
   FIRSTPASS_STATS *stats_in_end;
   FIRSTPASS_STATS *stats_in_buf_end;
+  FIRSTPASS_STATS *total_stats;
+  FIRSTPASS_STATS *total_left_stats;
 } STATS_BUFFER_CTX;
 
 typedef struct {
   unsigned int section_intra_rating;
-  FIRSTPASS_STATS *total_stats;
   // Circular queue of first pass stats stored for most recent frames.
   // cpi->output_pkt_list[i].data.twopass_stats.buf points to actual data stored
   // here.
@@ -145,7 +146,6 @@
   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;
-  FIRSTPASS_STATS *total_left_stats;
   int first_pass_done;
   int64_t bits_left;
   double modified_error_min;
@@ -183,7 +183,6 @@
 struct EncodeFrameParams;
 struct AV1EncoderConfig;
 
-void av1_init_first_pass(struct AV1_COMP *cpi);
 void av1_rc_get_first_pass_params(struct AV1_COMP *cpi);
 void av1_first_pass(struct AV1_COMP *cpi, const int64_t ts_duration);
 void av1_end_first_pass(struct AV1_COMP *cpi);
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index d55b69e..6adc1fb 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -55,7 +55,7 @@
                                      const TWO_PASS *twopass,
                                      const AV1EncoderConfig *oxcf,
                                      const FIRSTPASS_STATS *this_frame) {
-  const FIRSTPASS_STATS *const stats = twopass->total_stats;
+  const FIRSTPASS_STATS *const stats = twopass->stats_buf_ctx->total_stats;
   if (stats == NULL) {
     return 0;
   }
@@ -2410,20 +2410,31 @@
   TWO_PASS *const twopass = &cpi->twopass;
 
   if (cpi->oxcf.rc_mode != AOM_Q && current_frame->frame_number == 0 &&
-      cpi->twopass.total_stats && cpi->twopass.total_left_stats) {
-    const int frames_left =
-        (int)(twopass->total_stats->count - current_frame->frame_number);
+      cpi->twopass.stats_buf_ctx->total_stats &&
+      cpi->twopass.stats_buf_ctx->total_left_stats) {
+    if (cpi->lap_enabled) {
+      /*
+       * Accumulate total_stats using available limited number of stats,
+       * and assign it to total_left_stats.
+       */
+      *cpi->twopass.stats_buf_ctx->total_left_stats =
+          *cpi->twopass.stats_buf_ctx->total_stats;
+    }
+    const int frames_left = (int)(twopass->stats_buf_ctx->total_stats->count -
+                                  current_frame->frame_number);
 
     // Special case code for first frame.
     const int section_target_bandwidth =
         (int)(twopass->bits_left / frames_left);
-    const double section_length = twopass->total_left_stats->count;
+    const double section_length =
+        twopass->stats_buf_ctx->total_left_stats->count;
     const double section_error =
-        twopass->total_left_stats->coded_error / section_length;
+        twopass->stats_buf_ctx->total_left_stats->coded_error / section_length;
     const double section_intra_skip =
-        twopass->total_left_stats->intra_skip_pct / section_length;
+        twopass->stats_buf_ctx->total_left_stats->intra_skip_pct /
+        section_length;
     const double section_inactive_zone =
-        (twopass->total_left_stats->inactive_zone_rows * 2) /
+        (twopass->stats_buf_ctx->total_left_stats->inactive_zone_rows * 2) /
         ((double)cm->mi_params.mb_rows * section_length);
     const int tmp_q = get_twopass_worst_quality(
         cpi, section_error, section_intra_skip + section_inactive_zone,
@@ -2458,8 +2469,8 @@
   }
 
   // Update the total stats remaining structure.
-  if (twopass->total_left_stats)
-    subtract_stats(twopass->total_left_stats, this_frame);
+  if (twopass->stats_buf_ctx->total_left_stats)
+    subtract_stats(twopass->stats_buf_ctx->total_left_stats, this_frame);
 
   // Set the frame content type flag.
   if (this_frame->intra_skip_pct >= FC_ANIMATION_THRESH)
@@ -2661,17 +2672,12 @@
   double frame_rate;
   FIRSTPASS_STATS *stats;
 
-  twopass->total_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS));
-  twopass->total_left_stats = aom_calloc(1, sizeof(FIRSTPASS_STATS));
-  av1_twopass_zero_stats(twopass->total_stats);
-  av1_twopass_zero_stats(twopass->total_left_stats);
-
   if (!twopass->stats_buf_ctx->stats_in_end) return;
 
-  stats = twopass->total_stats;
+  stats = twopass->stats_buf_ctx->total_stats;
 
   *stats = *twopass->stats_buf_ctx->stats_in_end;
-  *twopass->total_left_stats = *stats;
+  *twopass->stats_buf_ctx->total_left_stats = *stats;
 
   frame_rate = 10000000.0 * stats->count / stats->duration;
   // Each frame can have a different duration, as the frame rate in the source
@@ -2726,9 +2732,6 @@
 void av1_init_single_pass_lap(AV1_COMP *cpi) {
   TWO_PASS *const twopass = &cpi->twopass;
 
-  twopass->total_stats = NULL;
-  twopass->total_left_stats = NULL;
-
   if (!twopass->stats_buf_ctx->stats_in_end) return;
 
   // This variable monitors how far behind the second ref update is lagging.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index ea4ff9f..433163f 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1813,9 +1813,10 @@
 static void vbr_rate_correction(AV1_COMP *cpi, int *this_frame_target) {
   RATE_CONTROL *const rc = &cpi->rc;
   int64_t vbr_bits_off_target = rc->vbr_bits_off_target;
-  const int stats_count = cpi->twopass.total_stats != NULL
-                              ? (int)cpi->twopass.total_stats->count
-                              : 0;
+  const int stats_count =
+      cpi->twopass.stats_buf_ctx->total_stats != NULL
+          ? (int)cpi->twopass.stats_buf_ctx->total_stats->count
+          : 0;
   const int frame_window = AOMMIN(
       16, (int)(stats_count - (int)cpi->common.current_frame.frame_number));