Add parsing code for 2-pass tpl stats generation

Change-Id: Ia6f301ceaca457998f4d1f371986b3df84ad3a9b
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 7f1d551..70acde9 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -71,6 +71,7 @@
 #include "av1/encoder/rdopt.h"
 #include "av1/encoder/segmentation.h"
 #include "av1/encoder/speed_features.h"
+#include "av1/encoder/tpl_model.h"
 #include "av1/encoder/reconinter_enc.h"
 #include "av1/encoder/var_based_part.h"
 
@@ -4504,9 +4505,7 @@
 
     if (cpi->tpl_model_pass == 1) {
       assert(cpi->oxcf.enable_tpl_model == 2);
-
-      // TODO(debargha, yuec): Update forward tpl model here
-
+      av1_tpl_setup_forward_stats(cpi);
       cpi->tpl_model_pass = 0;
       loop = 1;
     }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index da8d49d..d4b1a36 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -860,6 +860,8 @@
   // when two pass tpl model is used, set to 1 for the
   // first pass, then 0 for the final pass.
   int tpl_model_pass;
+  // Number of gf_group frames for tpl stats
+  int tpl_gf_group_frames;
 
   TWO_PASS twopass;
 
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index e776e33..2328fda 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -373,14 +373,13 @@
   }
 }
 
-#ifndef NDEBUG
 static YV12_BUFFER_CONFIG *get_framebuf(
     AV1_COMP *cpi, const EncodeFrameInput *const frame_input, int frame_idx) {
   if (frame_idx == 0) {
     RefCntBuffer *ref_buf = get_ref_frame_buf(&cpi->common, GOLDEN_FRAME);
     return &ref_buf->buf;
   } else if (frame_idx == 1) {
-    return frame_input->source;
+    return frame_input ? frame_input->source : NULL;
   } else {
     const GF_GROUP *gf_group = &cpi->twopass.gf_group;
     const int frame_disp_idx = gf_group->frame_disp_idx[frame_idx];
@@ -389,7 +388,6 @@
     return &buf->img;
   }
 }
-#endif  // NDEBUG
 
 static void mc_flow_dispenser(AV1_COMP *cpi, YV12_BUFFER_CONFIG **gf_picture,
                               int frame_idx) {
@@ -627,17 +625,76 @@
                          const EncodeFrameInput *const frame_input) {
   YV12_BUFFER_CONFIG *gf_picture[MAX_LENGTH_TPL_FRAME_STATS];
   GF_GROUP *gf_group = &cpi->twopass.gf_group;
-  int tpl_group_frames = 0;
   int frame_idx;
 
-  init_gop_frames_for_tpl(cpi, gf_picture, gf_group, &tpl_group_frames,
+  init_gop_frames_for_tpl(cpi, gf_picture, gf_group, &cpi->tpl_gf_group_frames,
                           frame_input);
 
   init_tpl_stats(cpi);
 
   if (cpi->oxcf.enable_tpl_model == 1) {
     // Backward propagation from tpl_group_frames to 1.
-    for (frame_idx = tpl_group_frames - 1; frame_idx > 0; --frame_idx)
+    for (frame_idx = cpi->tpl_gf_group_frames - 1; frame_idx > 0; --frame_idx)
       mc_flow_dispenser(cpi, gf_picture, frame_idx);
   }
 }
+
+void get_tpl_forward_stats(AV1_COMP *cpi, MACROBLOCK *x, MACROBLOCKD *xd,
+                           BLOCK_SIZE bsize, YV12_BUFFER_CONFIG *ref,
+                           YV12_BUFFER_CONFIG *src,
+                           TplDepFrame *ref_tpl_frame) {
+  // TODO(debargha, yuec): Fill this up
+  (void)cpi;
+  (void)x;
+  (void)xd;
+  (void)bsize;
+  (void)ref;
+  (void)src;
+  (void)ref_tpl_frame;
+}
+
+void av1_tpl_setup_forward_stats(AV1_COMP *cpi) {
+  ThreadData *td = &cpi->td;
+  MACROBLOCK *x = &td->mb;
+  MACROBLOCKD *xd = &x->e_mbd;
+#if MC_FLOW_BSIZE == 64
+  const BLOCK_SIZE bsize = BLOCK_64X64;
+#elif MC_FLOW_BSIZE == 32
+  const BLOCK_SIZE bsize = BLOCK_32X32;
+#elif MC_FLOW_BSIZE == 16
+  const BLOCK_SIZE bsize = BLOCK_16X16;
+#elif MC_FLOW_BSIZE == 8
+  const BLOCK_SIZE bsize = BLOCK_8X8;
+#elif MC_FLOW_BSIZE == 4
+  const BLOCK_SIZE bsize = BLOCK_4X4;
+#else
+#error "Invalid block size for tpl model"
+#endif  // MC_FLOW_BSIZE == 64
+
+  const GF_GROUP *gf_group = &cpi->twopass.gf_group;
+  const int tpl_cur_idx = cpi->twopass.gf_group.frame_disp_idx[gf_group->index];
+  TplDepFrame *tpl_frame = &cpi->tpl_stats[tpl_cur_idx];
+  int tpl_used_mask[MAX_LENGTH_TPL_FRAME_STATS] = { 0 };
+  for (int idx = gf_group->index + 1; idx < cpi->tpl_gf_group_frames; ++idx) {
+    const int tpl_future_idx = cpi->twopass.gf_group.frame_disp_idx[idx];
+
+    if (tpl_future_idx == tpl_cur_idx) continue;
+    if (tpl_used_mask[tpl_future_idx]) continue;
+
+    for (int ridx = 0; ridx < INTER_REFS_PER_FRAME; ++ridx) {
+      const int ref_idx = gf_group->ref_frame_gop_idx[idx][ridx];
+      const int tpl_ref_idx = cpi->twopass.gf_group.frame_disp_idx[ref_idx];
+      if (tpl_ref_idx == tpl_cur_idx) {
+        // Do tpl stats computation between current buffer and the one at
+        // gf_group index given by idx (and with disp index given by
+        // tpl_future_idx).
+        assert(idx >= 2);
+        YV12_BUFFER_CONFIG *cur_buf = &cpi->common.cur_frame->buf;
+        YV12_BUFFER_CONFIG *future_buf = get_framebuf(cpi, NULL, idx);
+        get_tpl_forward_stats(cpi, x, xd, bsize, cur_buf, future_buf,
+                              tpl_frame);
+        tpl_used_mask[tpl_future_idx] = 1;
+      }
+    }
+  }
+}
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index f6b33b0..4732d1c 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -19,6 +19,8 @@
 void av1_tpl_setup_stats(AV1_COMP *cpi,
                          const EncodeFrameInput *const frame_input);
 
+void av1_tpl_setup_forward_stats(AV1_COMP *cpi);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif