Add EncodeFrameInput, pass1 thru av1_encode()

Add a new EncodeFrameInput structure encompassing the input to the
low-level encoder: a source frame buffer and the last frame buffer
where applicable.  The frame duration (in timestamp format) is also
included so the first pass can use it for stats.  The big change here is
that cpi->source etc. aren't set until we get to av1_encode() so
high-level strategy code can't use them.  Therefore, I change some TPL
stats code to use the EncodeFrameInput instead of cpi->source

Redirect control flow for the first pass through the av1_encode()
interface.  Now all frame-encoding goes via av1_encode_strategy() and
av1_encode() making first pass slightly less of a special case.

This forms part of wider restructuring and refactoring in order to
achieve a clean API separation at the entry to the low-level encoder.

BUG=aomedia:2244

Change-Id: I1105586574869a23b0c27a86a3ed2b4243bc7bf9
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 3e02884..272f170 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -237,6 +237,7 @@
 }
 
 static int Pass0Encode(AV1_COMP *const cpi, uint8_t *const dest,
+                       const EncodeFrameInput *const frame_input,
                        EncodeFrameParams *const frame_params,
                        EncodeFrameResults *const frame_results) {
   if (cpi->oxcf.rc_mode == AOM_CBR) {
@@ -251,7 +252,8 @@
   // Work out which reference frame slots may be used.
   frame_params->ref_frame_flags = get_ref_frame_flags(cpi);
 
-  if (av1_encode(cpi, dest, frame_params, frame_results) != AOM_CODEC_OK) {
+  if (av1_encode(cpi, dest, frame_input, frame_params, frame_results) !=
+      AOM_CODEC_OK) {
     return AOM_CODEC_ERROR;
   }
 
@@ -265,7 +267,16 @@
   return AOM_CODEC_OK;
 }
 
+static int Pass1Encode(AV1_COMP *const cpi,
+                       const EncodeFrameInput *const frame_input,
+                       EncodeFrameParams *const frame_params) {
+  cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(&cpi->oxcf);
+  av1_encode(cpi, NULL, frame_input, frame_params, NULL);
+  return AOM_CODEC_OK;
+}
+
 static int Pass2Encode(AV1_COMP *const cpi, uint8_t *const dest,
+                       const EncodeFrameInput *const frame_input,
                        EncodeFrameParams *const frame_params,
                        EncodeFrameResults *const frame_results) {
   AV1_COMMON *const cm = &cpi->common;
@@ -284,7 +295,8 @@
   // Work out which reference frame slots may be used.
   frame_params->ref_frame_flags = get_ref_frame_flags(cpi);
 
-  if (av1_encode(cpi, dest, frame_params, frame_results) != AOM_CODEC_OK) {
+  if (av1_encode(cpi, dest, frame_input, frame_params, frame_results) !=
+      AOM_CODEC_OK) {
     return AOM_CODEC_ERROR;
   }
 
@@ -310,7 +322,7 @@
 
 int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
                         uint8_t *const dest, unsigned int *frame_flags,
-                        struct lookahead_entry *source) {
+                        const EncodeFrameInput *const frame_input) {
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
 
   EncodeFrameParams frame_params;
@@ -332,14 +344,17 @@
   frame_params.speed = oxcf->speed;
 
   if (oxcf->pass == 0) {  // Single pass encode
-    if (Pass0Encode(cpi, dest, &frame_params, &frame_results) != AOM_CODEC_OK) {
+    if (Pass0Encode(cpi, dest, frame_input, &frame_params, &frame_results) !=
+        AOM_CODEC_OK) {
       return AOM_CODEC_ERROR;
     }
   } else if (oxcf->pass == 1) {  // Two-pass encode, first pass
-    cpi->td.mb.e_mbd.lossless[0] = is_lossless_requested(oxcf);
-    av1_first_pass(cpi, source);
+    if (Pass1Encode(cpi, frame_input, &frame_params) != AOM_CODEC_OK) {
+      return AOM_CODEC_ERROR;
+    }
   } else if (oxcf->pass == 2) {  // Two-pass encode, second pass
-    if (Pass2Encode(cpi, dest, &frame_params, &frame_results) != AOM_CODEC_OK) {
+    if (Pass2Encode(cpi, dest, frame_input, &frame_params, &frame_results) !=
+        AOM_CODEC_OK) {
       return AOM_CODEC_ERROR;
     }
   }
diff --git a/av1/encoder/encode_strategy.h b/av1/encoder/encode_strategy.h
index 33d0927..ccb9b01 100644
--- a/av1/encoder/encode_strategy.h
+++ b/av1/encoder/encode_strategy.h
@@ -21,7 +21,7 @@
 // results of these decisions and then calls av1_encode()
 int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
                         uint8_t *const dest, unsigned int *frame_flags,
-                        struct lookahead_entry *source);
+                        const EncodeFrameInput *const frame_input);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index f6d612e..c20a217 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -5529,19 +5529,27 @@
 }
 
 int av1_encode(AV1_COMP *const cpi, uint8_t *const dest,
+               const EncodeFrameInput *const frame_input,
                const EncodeFrameParams *const frame_params,
                EncodeFrameResults *const frame_results) {
   AV1_COMMON *const cm = &cpi->common;
 
-  // TODO(david.turner@argondesign.com): Copy data from frame_params to cpi and
-  // cm as appropriate
+  cpi->unscaled_source = frame_input->source;
+  cpi->source = frame_input->source;
+  cpi->unscaled_last_source = frame_input->last_source;
 
   cm->error_resilient_mode = frame_params->error_resilient_mode;
   cpi->ref_frame_flags = frame_params->ref_frame_flags;
   cpi->speed = frame_params->speed;
 
-  if (encode_frame_to_data_rate(cpi, &frame_results->size, dest,
-                                frame_params->frame_flags) != AOM_CODEC_OK) {
+  if (cpi->oxcf.pass == 1) {
+    av1_first_pass(cpi, frame_input->ts_duration);
+  } else if (cpi->oxcf.pass == 0 || cpi->oxcf.pass == 2) {
+    if (encode_frame_to_data_rate(cpi, &frame_results->size, dest,
+                                  frame_params->frame_flags) != AOM_CODEC_OK) {
+      return AOM_CODEC_ERROR;
+    }
+  } else {
     return AOM_CODEC_ERROR;
   }
 
@@ -5877,7 +5885,8 @@
 } GF_PICTURE;
 
 static void init_gop_frames(AV1_COMP *cpi, GF_PICTURE *gf_picture,
-                            const GF_GROUP *gf_group, int *tpl_group_frames) {
+                            const GF_GROUP *gf_group, int *tpl_group_frames,
+                            const EncodeFrameInput *const frame_input) {
   AV1_COMMON *cm = &cpi->common;
   const SequenceHeader *const seq_params = &cm->seq_params;
   int frame_idx = 0;
@@ -5927,7 +5936,7 @@
   ++*tpl_group_frames;
 
   // Initialize ARF frame
-  gf_picture[1].frame = cpi->source;
+  gf_picture[1].frame = frame_input->source;
   gf_picture[1].ref_frame[0] = gld_index;
   gf_picture[1].ref_frame[1] = lst_index;
   gf_picture[1].ref_frame[2] = alt_index;
@@ -6426,13 +6435,14 @@
   }
 }
 
-static void setup_tpl_stats(AV1_COMP *cpi) {
+static void setup_tpl_stats(AV1_COMP *cpi,
+                            const EncodeFrameInput *const frame_input) {
   GF_PICTURE gf_picture[MAX_LAG_BUFFERS];
   const GF_GROUP *gf_group = &cpi->twopass.gf_group;
   int tpl_group_frames = 0;
   int frame_idx;
 
-  init_gop_frames(cpi, gf_picture, gf_group, &tpl_group_frames);
+  init_gop_frames(cpi, gf_picture, gf_group, &tpl_group_frames, frame_input);
 
   init_tpl_stats(cpi);
 
@@ -6607,6 +6617,7 @@
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
   AV1_COMMON *const cm = &cpi->common;
   struct aom_usec_timer cmptimer;
+  EncodeFrameInput frame_input;
 
 #if CONFIG_BITSTREAM_DEBUG
   assert(cpi->oxcf.max_threads == 0 &&
@@ -6659,14 +6670,9 @@
     return -1;
   }
 
-  if (temporal_filtered) {
-    cpi->unscaled_source = &cpi->alt_ref_buffer;
-    cpi->source = &cpi->alt_ref_buffer;
-  } else {
-    cpi->unscaled_source = &source->img;
-    cpi->source = &source->img;
-  }
-  cpi->unscaled_last_source = last_source != NULL ? &last_source->img : NULL;
+  frame_input.source = temporal_filtered ? &cpi->alt_ref_buffer : &source->img;
+  frame_input.last_source = last_source != NULL ? &last_source->img : NULL;
+  frame_input.ts_duration = source->ts_end - source->ts_start;
 
   *time_stamp = source->ts_start;
   *time_end = source->ts_end;
@@ -6722,11 +6728,11 @@
     cm->max_qmlevel = cpi->oxcf.qm_maxlevel;
     if (cpi->twopass.gf_group.index == 1 && cpi->oxcf.enable_tpl_model) {
       set_frame_size(cpi, cm->width, cm->height);
-      setup_tpl_stats(cpi);
+      setup_tpl_stats(cpi, &frame_input);
     }
   }
 
-  if (av1_encode_strategy(cpi, size, dest, frame_flags, source) !=
+  if (av1_encode_strategy(cpi, size, dest, frame_flags, &frame_input) !=
       AOM_CODEC_OK) {
     return AOM_CODEC_ERROR;
   }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 1b4d7cd..100313d 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -869,6 +869,12 @@
   int is_screen_content_type;
 } AV1_COMP;
 
+typedef struct {
+  YV12_BUFFER_CONFIG *source;
+  YV12_BUFFER_CONFIG *last_source;
+  int64_t ts_duration;
+} EncodeFrameInput;
+
 // EncodeFrameParams contains per-frame encoding parameters decided upon by
 // av1_encode_strategy() and passed down to av1_encode()
 typedef struct {
@@ -910,6 +916,7 @@
                             const aom_rational_t *timebase);
 
 int av1_encode(AV1_COMP *const cpi, uint8_t *const dest,
+               const EncodeFrameInput *const frame_input,
                const EncodeFrameParams *const frame_params,
                EncodeFrameResults *const frame_results);
 
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index c5dd78a..8349ee7 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -486,7 +486,7 @@
 
 #define UL_INTRA_THRESH 50
 #define INVALID_ROW -1
-void av1_first_pass(AV1_COMP *cpi, const struct lookahead_entry *source) {
+void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) {
   int mb_row, mb_col;
   MACROBLOCK *const x = &cpi->td.mb;
   AV1_COMMON *const cm = &cpi->common;
@@ -1040,7 +1040,7 @@
     // TODO(paulwilkins):  Handle the case when duration is set to 0, or
     // something less than the full time between subsequent values of
     // cpi->source_time_stamp.
-    fps.duration = (double)(source->ts_end - source->ts_start);
+    fps.duration = (double)ts_duration;
 
     // Don't want to do output stats with a stack variable!
     twopass->this_frame_stats = fps;
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 35af2d1..9bb1df5 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -174,7 +174,7 @@
 
 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 struct lookahead_entry *source);
+void av1_first_pass(struct AV1_COMP *cpi, const int64_t ts_duration);
 void av1_end_first_pass(struct AV1_COMP *cpi);
 
 void av1_init_second_pass(struct AV1_COMP *cpi);