Add functions and parameters for second pass log.

The log file stores useful info about GOPs in the second pass,
and can be used for the third pass.

BUG=aomedia:3101

Change-Id: I4636ed0a00527a3c16a08a4c4996557ff1f6e27a
diff --git a/apps/aomenc.c b/apps/aomenc.c
index f65efa3..fbcc302 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -436,6 +436,7 @@
 const arg_def_t *av1_key_val_args[] = {
   &g_av1_codec_arg_defs.passes,
   &g_av1_codec_arg_defs.two_pass_output,
+  &g_av1_codec_arg_defs.second_pass_log,
   &g_av1_codec_arg_defs.fwd_kf_dist,
   NULL,
 };
diff --git a/av1/arg_defs.c b/av1/arg_defs.c
index 327b664..1af45a8 100644
--- a/av1/arg_defs.c
+++ b/av1/arg_defs.c
@@ -641,5 +641,7 @@
       ARG_DEF(NULL, "two-pass-width", 1, "The width of two-pass-input."),
   .two_pass_height =
       ARG_DEF(NULL, "two-pass-height", 1, "The height of two-pass-input."),
+  .second_pass_log =
+      ARG_DEF("spf", "second-pass-log", 1, "Log file from second pass."),
 #endif  // CONFIG_AV1_ENCODER
 };
diff --git a/av1/arg_defs.h b/av1/arg_defs.h
index c89dbba..2720868 100644
--- a/av1/arg_defs.h
+++ b/av1/arg_defs.h
@@ -223,6 +223,7 @@
   arg_def_t two_pass_output;
   arg_def_t two_pass_width;
   arg_def_t two_pass_height;
+  arg_def_t second_pass_log;
 #endif  // CONFIG_AV1_ENCODER
 } av1_codec_arg_definitions_t;
 
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index d3c1460..381d754 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -166,6 +166,7 @@
   int fwd_kf_dist;
   // the name of the second pass output file when passes > 2
   const char *two_pass_output;
+  const char *second_pass_log;
 };
 
 #if CONFIG_REALTIME_ONLY
@@ -315,6 +316,7 @@
   -1,            // passes
   -1,            // fwd_kf_dist
   NULL,          // two_pass_output
+  NULL,          // second_pass_log
 };
 #else
 static const struct av1_extracfg default_extra_cfg = {
@@ -451,6 +453,7 @@
   -1,           // passes
   -1,           // fwd_kf_dist
   NULL,         // two_pass_output
+  NULL,         // second_pass_log
 };
 #endif
 
@@ -1167,6 +1170,8 @@
   if (extra_cfg->two_pass_output)
     oxcf->two_pass_output = extra_cfg->two_pass_output;
 
+  oxcf->second_pass_log = extra_cfg->second_pass_log;
+
   // Set Key frame configuration.
   kf_cfg->fwd_kf_enabled = cfg->fwd_kf_enabled;
   kf_cfg->auto_key =
@@ -2542,6 +2547,8 @@
 #endif
   check_and_free_string(default_extra_cfg.two_pass_output,
                         &extra_cfg->two_pass_output);
+  check_and_free_string(default_extra_cfg.two_pass_output,
+                        &extra_cfg->second_pass_log);
   check_and_free_string(default_extra_cfg.partition_info_path,
                         &extra_cfg->partition_info_path);
   check_and_free_string(default_extra_cfg.film_grain_table_filename,
@@ -3750,6 +3757,10 @@
                               err_string)) {
     err = allocate_and_set_string(value, default_extra_cfg.two_pass_output,
                                   &extra_cfg.two_pass_output, err_string);
+  } else if (arg_match_helper(&arg, &g_av1_codec_arg_defs.second_pass_log, argv,
+                              err_string)) {
+    err = allocate_and_set_string(value, default_extra_cfg.second_pass_log,
+                                  &extra_cfg.second_pass_log, err_string);
   } else {
     match = 0;
     snprintf(err_string, ARG_ERR_MSG_MAX_LEN, "Cannot find aom option %s",
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 8a7d8bc..d6a60db 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1454,6 +1454,8 @@
     av1_init_thirdpass_ctx(cm, &cpi->third_pass_ctx, NULL);
   }
 
+  cpi->second_pass_log_stream = NULL;
+
   cm->error->setjmp = 0;
   return cpi;
 }
@@ -1608,6 +1610,7 @@
   }
 
   av1_free_thirdpass_ctx(cpi->third_pass_ctx);
+  if (cpi->second_pass_log_stream) fclose(cpi->second_pass_log_stream);
 
   dealloc_compressor_data(cpi);
 
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index b1032b5..fcbf5f0 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -996,6 +996,9 @@
   // the name of the second pass output file when passes > 2
   const char *two_pass_output;
 
+  // the name of the second pass log file when passes > 2
+  const char *second_pass_log;
+
   // Indicates if the encoding is GOOD or REALTIME.
   MODE mode;
 
@@ -3209,6 +3212,11 @@
    * Context needed for third pass encoding.
    */
   THIRD_PASS_DEC_CTX *third_pass_ctx;
+
+  /*!
+   * File pointer to second pass log
+   */
+  FILE *second_pass_log_stream;
 } AV1_COMP;
 
 /*!
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 182f9e49..44a7563 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 
-#include "av1/encoder/thirdpass.h"
 #include "config/aom_config.h"
 #include "config/aom_scale_rtcd.h"
 
@@ -35,6 +34,7 @@
 #include "av1/encoder/ratectrl.h"
 #include "av1/encoder/rc_utils.h"
 #include "av1/encoder/temporal_filter.h"
+#include "av1/encoder/thirdpass.h"
 #include "av1/encoder/tpl_model.h"
 #include "av1/encoder/encode_strategy.h"
 
@@ -3662,6 +3662,8 @@
 
     define_gf_group(cpi, frame_params, 1);
 
+    av1_write_second_pass_gop_info(cpi);
+
     av1_tf_info_filtering(&cpi->ppi->tf_info, cpi, gf_group);
 
     rc->frames_till_gf_update_due = p_rc->baseline_gf_interval;
diff --git a/av1/encoder/thirdpass.c b/av1/encoder/thirdpass.c
index 1647758..4078d6c 100644
--- a/av1/encoder/thirdpass.c
+++ b/av1/encoder/thirdpass.c
@@ -13,6 +13,7 @@
 #include "aom/aomdx.h"
 #include "aom_mem/aom_mem.h"
 #include "av1/av1_iface_common.h"
+#include "av1/encoder/encoder.h"
 #include "av1/encoder/firstpass.h"
 #include "av1/encoder/thirdpass.h"
 #include "av1/common/blockd.h"
@@ -300,3 +301,61 @@
   if (ctx->buf) free(ctx->buf);
   aom_free(ctx);
 }
+
+void av1_write_second_pass_gop_info(AV1_COMP *cpi) {
+  const AV1EncoderConfig *const oxcf = &cpi->oxcf;
+  const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
+  const PRIMARY_RATE_CONTROL *const p_rc = &cpi->ppi->p_rc;
+
+  if (oxcf->pass == AOM_RC_SECOND_PASS && oxcf->second_pass_log) {
+    // Write the GOP length to a log file.
+    if (!cpi->second_pass_log_stream) {
+      cpi->second_pass_log_stream = fopen(cpi->oxcf.second_pass_log, "wb");
+      if (!cpi->second_pass_log_stream) {
+        aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
+                           "Could not open second pass log file!");
+      }
+    }
+
+    THIRD_PASS_GOP_INFO gop_info;
+
+    gop_info.num_frames = gf_group->size;
+    gop_info.use_arf = (gf_group->arf_index >= 0);
+    gop_info.gf_length = p_rc->baseline_gf_interval;
+
+    size_t count =
+        fwrite(&gop_info, sizeof(gop_info), 1, cpi->second_pass_log_stream);
+    if (count < 1) {
+      aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
+                         "Could not write to second pass log file!");
+    }
+  }
+}
+
+void av1_read_second_pass_gop_info(AV1_COMP *cpi,
+                                   THIRD_PASS_GOP_INFO *gop_info) {
+  const AV1EncoderConfig *const oxcf = &cpi->oxcf;
+
+  if (oxcf->pass == AOM_RC_THIRD_PASS) {
+    if (oxcf->second_pass_log == NULL) {
+      aom_internal_error(
+          cpi->common.error, AOM_CODEC_INVALID_PARAM,
+          "No second pass log file specified for the third pass!");
+    }
+    // Read the GOP length from a file.
+    if (!cpi->second_pass_log_stream) {
+      cpi->second_pass_log_stream = fopen(cpi->oxcf.second_pass_log, "rb");
+      if (!cpi->second_pass_log_stream) {
+        aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
+                           "Could not open second pass log file!");
+      }
+    }
+
+    size_t count =
+        fread(gop_info, sizeof(*gop_info), 1, cpi->second_pass_log_stream);
+    if (count < 1) {
+      aom_internal_error(cpi->common.error, AOM_CODEC_ERROR,
+                         "Could not read from second pass log file!");
+    }
+  }
+}
diff --git a/av1/encoder/thirdpass.h b/av1/encoder/thirdpass.h
index 4c80585..2f35173 100644
--- a/av1/encoder/thirdpass.h
+++ b/av1/encoder/thirdpass.h
@@ -19,9 +19,19 @@
 #include "av1/encoder/firstpass.h"
 #include "av1/encoder/ratectrl.h"
 
+struct AV1_COMP;
+
 // TODO(bohanli): optimize this number
 #define MAX_THIRD_PASS_BUF (2 * MAX_GF_INTERVAL + 1)
 
+// Struct to store useful information related to a GOP, in addition to what is
+// available in the bitstream
+typedef struct {
+  int gf_length;
+  int num_frames;
+  int use_arf;
+} THIRD_PASS_GOP_INFO;
+
 // Struct to store useful information about a frame for the third pass.
 // The members are extracted from the decoder by function get_frame_info.
 typedef struct {
@@ -65,6 +75,7 @@
   int frame_info_count;
   // the end of the previous GOP (order hint)
   int prev_gop_end;
+  THIRD_PASS_GOP_INFO gop_info;
 } THIRD_PASS_DEC_CTX;
 
 void av1_init_thirdpass_ctx(AV1_COMMON *cm, THIRD_PASS_DEC_CTX **ctx,
@@ -82,6 +93,13 @@
 // sure that frame_info[0] always corresponds to the current frame.
 void av1_pop_third_pass_info(THIRD_PASS_DEC_CTX *ctx);
 
+// Write the current GOP information into the second pass log file.
+void av1_write_second_pass_gop_info(struct AV1_COMP *cpi);
+
+// Read the next GOP information from the second pass log file.
+void av1_read_second_pass_gop_info(struct AV1_COMP *cpi,
+                                   THIRD_PASS_GOP_INFO *gop_info);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif