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