ref: e51c9e39bcfcf26b9031845ff7767050bcb3b059
parent: 5222a928b04d80fdc88d0d566aa0cf931c426bfb
parent: b6f7d694647a587dacbab1dc65d40c4630aa9632
author: Yaowu Xu <yaowu@google.com>
date: Mon May 14 16:56:34 EDT 2018
Merge "Fixes for consistent encoding across recodes of a frame"
--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -4663,6 +4663,9 @@
for (i = 0; i < BLOCK_SIZES; ++i) {
for (j = 0; j < MAX_MODES; ++j) {
tile_data->thresh_freq_fact[i][j] = RD_THRESH_INIT_FACT;
+#if CONSISTENT_RECODE_STATE
+ tile_data->thresh_freq_fact_prev[i][j] = RD_THRESH_INIT_FACT;
+#endif
tile_data->mode_map[i][j] = j;
}
}
@@ -4787,7 +4790,9 @@
x->fwd_txfm4x4 = xd->lossless ? vp9_fwht4x4 : vpx_fdct4x4;
#endif // CONFIG_VP9_HIGHBITDEPTH
x->inv_txfm_add = xd->lossless ? vp9_iwht4x4_add : vp9_idct4x4_add;
-
+#if CONSISTENT_RECODE_STATE
+ x->optimize = sf->optimize_coefficients == 1 && cpi->oxcf.pass != 1;
+#endif
if (xd->lossless) x->optimize = 0;
cm->tx_mode = select_tx_mode(cpi, xd);
@@ -4912,8 +4917,47 @@
return sum_delta / (cm->mi_rows * cm->mi_cols);
}
+#if CONSISTENT_RECODE_STATE
+static void restore_encode_params(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ const int tile_cols = 1 << cm->log2_tile_cols;
+ const int tile_rows = 1 << cm->log2_tile_rows;
+ int tile_col, tile_row;
+ int i, j;
+ RD_OPT *rd_opt = &cpi->rd;
+ for (i = 0; i < MAX_REF_FRAMES; i++) {
+ for (j = 0; j < REFERENCE_MODES; j++)
+ rd_opt->prediction_type_threshes[i][j] =
+ rd_opt->prediction_type_threshes_prev[i][j];
+
+ for (j = 0; j < SWITCHABLE_FILTER_CONTEXTS; j++)
+ rd_opt->filter_threshes[i][j] = rd_opt->filter_threshes_prev[i][j];
+ }
+
+ if (cpi->tile_data != NULL) {
+ for (tile_row = 0; tile_row < tile_rows; ++tile_row)
+ for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
+ TileDataEnc *tile_data =
+ &cpi->tile_data[tile_row * tile_cols + tile_col];
+ for (i = 0; i < BLOCK_SIZES; ++i) {
+ for (j = 0; j < MAX_MODES; ++j) {
+ tile_data->thresh_freq_fact[i][j] =
+ tile_data->thresh_freq_fact_prev[i][j];
+ }
+ }
+ }
+ }
+
+ cm->interp_filter = cpi->sf.default_interp_filter;
+}
+#endif
+
void vp9_encode_frame(VP9_COMP *cpi) {
VP9_COMMON *const cm = &cpi->common;
+
+#if CONSISTENT_RECODE_STATE
+ restore_encode_params(cpi);
+#endif
// In the longer term the encoder should be generalized to match the
// decoder such that we allow compound where one of the 3 buffers has a
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -3579,6 +3579,39 @@
set_ref_ptrs(cm, xd, LAST_FRAME, LAST_FRAME);
}
+#if CONSISTENT_RECODE_STATE
+static void save_encode_params(VP9_COMP *cpi) {
+ VP9_COMMON *const cm = &cpi->common;
+ const int tile_cols = 1 << cm->log2_tile_cols;
+ const int tile_rows = 1 << cm->log2_tile_rows;
+ int tile_col, tile_row;
+ int i, j;
+ RD_OPT *rd_opt = &cpi->rd;
+ for (i = 0; i < MAX_REF_FRAMES; i++) {
+ for (j = 0; j < REFERENCE_MODES; j++)
+ rd_opt->prediction_type_threshes_prev[i][j] =
+ rd_opt->prediction_type_threshes[i][j];
+
+ for (j = 0; j < SWITCHABLE_FILTER_CONTEXTS; j++)
+ rd_opt->filter_threshes_prev[i][j] = rd_opt->filter_threshes[i][j];
+ }
+
+ if (cpi->tile_data != NULL) {
+ for (tile_row = 0; tile_row < tile_rows; ++tile_row)
+ for (tile_col = 0; tile_col < tile_cols; ++tile_col) {
+ TileDataEnc *tile_data =
+ &cpi->tile_data[tile_row * tile_cols + tile_col];
+ for (i = 0; i < BLOCK_SIZES; ++i) {
+ for (j = 0; j < MAX_MODES; ++j) {
+ tile_data->thresh_freq_fact_prev[i][j] =
+ tile_data->thresh_freq_fact[i][j];
+ }
+ }
+ }
+ }
+}
+#endif
+
static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size,
uint8_t *dest) {
VP9_COMMON *const cm = &cpi->common;
@@ -4610,6 +4643,10 @@
#if CONFIG_INTERNAL_STATS
memset(cpi->mode_chosen_counts, 0,
MAX_MODES * sizeof(*cpi->mode_chosen_counts));
+#endif
+#if CONSISTENT_RECODE_STATE
+ // Backup to ensure consistency between recodes
+ save_encode_params(cpi);
#endif
if (cpi->sf.recode_loop == DISALLOW_RECODE) {
--- a/vp9/encoder/vp9_encoder.h
+++ b/vp9/encoder/vp9_encoder.h
@@ -282,6 +282,9 @@
typedef struct TileDataEnc {
TileInfo tile_info;
int thresh_freq_fact[BLOCK_SIZES][MAX_MODES];
+#if CONSISTENT_RECODE_STATE
+ int thresh_freq_fact_prev[BLOCK_SIZES][MAX_MODES];
+#endif
int8_t mode_map[BLOCK_SIZES][MAX_MODES];
FIRSTPASS_DATA fp_data;
VP9RowMTSync row_mt_sync;
--- a/vp9/encoder/vp9_rd.h
+++ b/vp9/encoder/vp9_rd.h
@@ -23,6 +23,9 @@
extern "C" {
#endif
+// This macro defines the control for consistent recode behaviour
+#define CONSISTENT_RECODE_STATE 0
+
#define RDDIV_BITS 7
#define RD_EPB_SHIFT 6
@@ -108,7 +111,11 @@
int64_t prediction_type_threshes[MAX_REF_FRAMES][REFERENCE_MODES];
int64_t filter_threshes[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
+#if CONSISTENT_RECODE_STATE
+ int64_t prediction_type_threshes_prev[MAX_REF_FRAMES][REFERENCE_MODES];
+ int64_t filter_threshes_prev[MAX_REF_FRAMES][SWITCHABLE_FILTER_CONTEXTS];
+#endif
int RDMULT;
int RDDIV;
} RD_OPT;
--- a/vp9/encoder/vp9_rdopt.c
+++ b/vp9/encoder/vp9_rdopt.c
@@ -3612,9 +3612,13 @@
}
if (best_mode_index < 0 || best_rd >= best_rd_so_far) {
- // If adaptive interp filter is enabled, then the current leaf node of 8x8
- // data is needed for sub8x8. Hence preserve the context.
+// If adaptive interp filter is enabled, then the current leaf node of 8x8
+// data is needed for sub8x8. Hence preserve the context.
+#if CONSISTENT_RECODE_STATE
+ if (bsize == BLOCK_8X8) ctx->mic = *xd->mi[0];
+#else
if (cpi->row_mt && bsize == BLOCK_8X8) ctx->mic = *xd->mi[0];
+#endif
rd_cost->rate = INT_MAX;
rd_cost->rdcost = INT64_MAX;
return;