Integrate BITRATE_ACCURACY with new ARF q feature
av1_get_arf_q_index_q_mode() can not be directly used
in BITRATE_ACCURACY because it's using
active_worst_quality (cq_level) as leaf frame q index, but in
BITRATE_ACCURACY, we are tuning the leaf frame q index and
therefore we will need to parameterize active_worst_quality.
We rename av1_get_arf_q_index_q_mode() as av1_tpl_get_q_index()
and decompose it into two functions, av1_tpl_get_qstep_ratio()
and av1_get_q_index_from_qstep_ratio().
av1_tpl_get_qstep_ratio() aims at computing the qstep
ratio between leaf frame q index and arf frame q index.
av1_get_q_index_from_qstep_ratio() finds arf q index based on
the qstep ratio with respect to the leaf frame q index.
We pass the qstep ratio into av1_q_mode_estimate_base_q()
so that it can be used to infer arf q index from
leaf frame q index.
Change-Id: If68a8ffee00656ec22df01c7cc003de5e9540071
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index 9f3b3ca..af01945 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -1040,11 +1040,12 @@
gop_bit_budget -= cpi->vbr_rc_info.keyframe_bitrate;
}
// Use the gop_bit_budget to determine gf_group->q_val.
- int arf_q =
- av1_get_arf_q_index_q_mode(cpi, cpi->ppi->tpl_data.tpl_frame);
+ const double arf_qstep_ratio =
+ av1_tpl_get_qstep_ratio(&cpi->ppi->tpl_data, cpi->gf_frame_index);
av1_q_mode_estimate_base_q(&cpi->ppi->gf_group,
cpi->ppi->tpl_data.txfm_stats_list,
- gop_bit_budget, cpi->gf_frame_index, arf_q);
+ gop_bit_budget, cpi->gf_frame_index,
+ arf_qstep_ratio, cm->seq_params->bit_depth);
}
#endif
}
diff --git a/av1/encoder/encoder_utils.c b/av1/encoder/encoder_utils.c
index 2116527..b44f03b 100644
--- a/av1/encoder/encoder_utils.c
+++ b/av1/encoder/encoder_utils.c
@@ -552,8 +552,9 @@
cpi->ppi->tpl_data.tpl_frame[cpi->gf_frame_index].is_valid &&
is_frame_tpl_eligible(gf_group, cpi->gf_frame_index) &&
!is_lossless_requested(&cpi->oxcf.rc_cfg) && !frame_is_intra_only(cm)) {
- *q = av1_get_arf_q_index_q_mode(
- cpi, &cpi->ppi->tpl_data.tpl_frame[cpi->gf_frame_index]);
+ *q = av1_tpl_get_q_index(&cpi->ppi->tpl_data, cpi->gf_frame_index,
+ cpi->rc.active_worst_quality,
+ cm->seq_params->bit_depth);
*top_index = *bottom_index = *q;
if (gf_group->update_type[cpi->gf_frame_index] == ARF_UPDATE)
cpi->ppi->p_rc.arf_q = *q;
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index a43d816..c81fa23 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -1069,11 +1069,12 @@
gop_bit_budget -= cpi->vbr_rc_info.keyframe_bitrate;
}
// Use the gop_bit_budget to determine gf_group->q_val.
- int arf_q =
- av1_get_arf_q_index_q_mode(cpi, cpi->ppi->tpl_data.tpl_frame);
+ const double arf_qstep_ratio =
+ av1_tpl_get_qstep_ratio(&cpi->ppi->tpl_data, cpi->gf_frame_index);
av1_q_mode_estimate_base_q(
&cpi->ppi->gf_group, cpi->ppi->tpl_data.txfm_stats_list,
- gop_bit_budget, cpi->gf_frame_index, arf_q);
+ gop_bit_budget, cpi->gf_frame_index, arf_qstep_ratio,
+ cpi->common.seq_params->bit_depth);
}
#endif // CONFIG_BITRATE_ACCURACY
}
@@ -3869,7 +3870,8 @@
(int64_t)(stats->duration * oxcf->rc_cfg.target_bandwidth / 10000000.0);
#if CONFIG_BITRATE_ACCURACY
- vbr_rc_init(&cpi->vbr_rc_info, cpi->ppi->twopass.bits_left, stats->count);
+ vbr_rc_init(&cpi->vbr_rc_info, cpi->ppi->twopass.bits_left,
+ (int)round(stats->count));
#endif
// This variable monitors how far behind the second ref update is lagging.
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index ca13f14..ac82abe 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1779,50 +1779,6 @@
return min_boost - (int)(boost * arf_boost_factor);
}
-#if !CONFIG_REALTIME_ONLY
-// TODO(jingning): Need further refactoring to reduce the data structure
-// access scope.
-int av1_get_arf_q_index_q_mode(AV1_COMP *cpi, TplDepFrame *tpl_frame) {
- AV1_COMMON *cm = &cpi->common;
- double lef_qstep = av1_dc_quant_QTX(cpi->rc.active_worst_quality, 0,
- cm->seq_params->bit_depth);
-
- TplParams *tpl_data = &cpi->ppi->tpl_data;
- TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
-
- int tpl_stride = tpl_frame->stride;
- int64_t intra_cost_base = 0;
- int64_t mc_dep_cost_base = 0;
- int64_t pred_error = 1;
- int64_t recn_error = 1;
- const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
-
- for (int row = 0; row < cm->mi_params.mi_rows; row += step) {
- for (int col = 0; col < cm->mi_params.mi_cols; col += step) {
- TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos(
- row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];
- int64_t mc_dep_delta =
- RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate,
- this_stats->mc_dep_dist);
- intra_cost_base += (this_stats->recrf_dist << RDDIV_BITS);
- pred_error += (this_stats->srcrf_sse << RDDIV_BITS);
- recn_error += (this_stats->srcrf_dist << RDDIV_BITS);
- mc_dep_cost_base += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta;
- }
- }
- double r0 = (double)intra_cost_base / mc_dep_cost_base;
-
- int arf_qp;
- double tgt_qstep;
- for (arf_qp = cpi->rc.active_worst_quality; arf_qp > 0; --arf_qp) {
- tgt_qstep = av1_dc_quant_QTX(arf_qp, 0, cm->seq_params->bit_depth);
- if (tgt_qstep + 0.1 <= lef_qstep * sqrt(r0)) break;
- }
-
- return arf_qp;
-}
-#endif
-
static int rc_pick_q_and_bounds_q_mode(const AV1_COMP *cpi, int width,
int height, int gf_index,
int *bottom_index, int *top_index) {
@@ -3107,15 +3063,22 @@
}
}
+#if !CONFIG_REALTIME_ONLY
+// TODO(angiebird): move this function to tpl_model.c
/*
* Compute the q_indices for the entire GOP.
* Intended to be used only with AOM_Q mode.
*/
void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
- int arf_q, struct GF_GROUP *gf_group) {
+ double arf_qstep_ratio,
+ aom_bit_depth_t bit_depth,
+ struct GF_GROUP *gf_group) {
+ const int arf_q = av1_get_q_index_from_qstep_ratio(
+ base_q_index, arf_qstep_ratio, bit_depth);
for (int gf_index = gf_frame_index; gf_index < gf_group->size; ++gf_index) {
- int height = gf_group_pyramid_level(gf_group, gf_index);
+ const int height = gf_group_pyramid_level(gf_group, gf_index);
gf_group->q_val[gf_index] = av1_q_mode_get_q_index(
base_q_index, gf_group->update_type[gf_index], height, arf_q);
}
}
+#endif // !CONFIG_REALTIME_ONLY
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 45c6ff3..583bdf2 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -707,18 +707,22 @@
*/
int av1_encodedframe_overshoot_cbr(struct AV1_COMP *cpi, int *q);
+#if !CONFIG_REALTIME_ONLY
/*!\brief Compute the q_indices for the entire GOP.
*
* Intended to be used only with AOM_Q mode.
*
* \param[in] gf_frame_index Index of the current frame
* \param[in] base_q_index Base q index
- * \param[in] bit_depth Bit depth
- * \param[in] arf_q ARF q index
+ * \param[in] arf_qstep_ratio The quantize step ratio between arf q
+ * index and base q index \param[in] bit_depth Bit depth
* \param[out] gf_group Pointer to the GOP
*/
void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
- int arf_q, struct GF_GROUP *gf_group);
+ double arf_qstep_ratio,
+ aom_bit_depth_t bit_depth,
+ struct GF_GROUP *gf_group);
+#endif // !CONFIG_REALTIME_ONLY
/*!\brief Compute the q_indices for a single frame.
*
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 6d06670..0116398 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1960,20 +1960,24 @@
int av1_q_mode_estimate_base_q(GF_GROUP *gf_group,
const TplTxfmStats *txfm_stats_list,
double bit_budget, int gf_frame_index,
- int arf_q) {
+ double arf_qstep_ratio,
+ aom_bit_depth_t bit_depth) {
int q_max = 255; // Maximum q value.
int q_min = 0; // Minimum q value.
int q = (q_max + q_min) / 2;
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q_max, arf_q, gf_group);
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q_max, arf_qstep_ratio,
+ bit_depth, gf_group);
double q_max_estimate = av1_estimate_gop_bitrate(
gf_group->q_val, gf_group->size, txfm_stats_list);
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q_min, arf_q, gf_group);
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q_min, arf_qstep_ratio,
+ bit_depth, gf_group);
double q_min_estimate = av1_estimate_gop_bitrate(
gf_group->q_val, gf_group->size, txfm_stats_list);
while (true) {
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_q, gf_group);
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+ bit_depth, gf_group);
double estimate = av1_estimate_gop_bitrate(gf_group->q_val, gf_group->size,
txfm_stats_list);
@@ -2001,6 +2005,53 @@
}
// Before returning, update the gop q_val.
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_q, gf_group);
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+ bit_depth, gf_group);
return q;
}
+
+double av1_tpl_get_qstep_ratio(const TplParams *tpl_data, int gf_frame_index) {
+ const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_frame_index];
+ const TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
+
+ const int tpl_stride = tpl_frame->stride;
+ int64_t intra_cost_base = 0;
+ int64_t mc_dep_cost_base = 0;
+ int64_t pred_error = 1;
+ int64_t recn_error = 1;
+ const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
+
+ for (int row = 0; row < tpl_frame->mi_rows; row += step) {
+ for (int col = 0; col < tpl_frame->mi_cols; col += step) {
+ const TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos(
+ row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];
+ const int64_t mc_dep_delta =
+ RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate,
+ this_stats->mc_dep_dist);
+ intra_cost_base += (this_stats->recrf_dist << RDDIV_BITS);
+ pred_error += (this_stats->srcrf_sse << RDDIV_BITS);
+ recn_error += (this_stats->srcrf_dist << RDDIV_BITS);
+ mc_dep_cost_base += (this_stats->recrf_dist << RDDIV_BITS) + mc_dep_delta;
+ }
+ }
+ const double r0 = (double)intra_cost_base / mc_dep_cost_base;
+ return sqrt(r0);
+}
+
+int av1_get_q_index_from_qstep_ratio(int leaf_qindex, double qstep_ratio,
+ aom_bit_depth_t bit_depth) {
+ const double leaf_qstep = av1_dc_quant_QTX(leaf_qindex, 0, bit_depth);
+ const double target_qstep = leaf_qstep * qstep_ratio;
+ int qindex = leaf_qindex;
+ for (qindex = leaf_qindex; qindex > 0; --qindex) {
+ const double qstep = av1_dc_quant_QTX(qindex, 0, bit_depth);
+ if (qstep + 0.1 <= target_qstep) break;
+ }
+ return qindex;
+}
+
+int av1_tpl_get_q_index(const TplParams *tpl_data, int gf_frame_index,
+ int leaf_qindex, aom_bit_depth_t bit_depth) {
+ const double qstep_ratio = av1_tpl_get_qstep_ratio(tpl_data, gf_frame_index);
+ return av1_get_q_index_from_qstep_ratio(leaf_qindex, qstep_ratio, bit_depth);
+}
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index 2019fb1..b5aabf8 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -487,15 +487,52 @@
* \param[in] stats Transform stats struct
* \param[in] bit_budget The specified bit budget to achieve
* \param[in] gf_frame_index current frame in the GOP
- * \param[in] bit_depth Bit depth
- * \param[in] arf_q ARF q index
+ * \param[in] arf_qstep_ratio ARF q step ratio
+ * \param[in] bit_depth bit depth
*
* \return Returns the optimal base q index to use.
*/
int av1_q_mode_estimate_base_q(struct GF_GROUP *gf_group,
const TplTxfmStats *txfm_stats_list,
double bit_budget, int gf_frame_index,
- int arf_q);
+ double arf_qstep_ratio,
+ aom_bit_depth_t bit_depth);
+
+/*!\brief Get current frame's q_index from tpl stats and leaf_qindex
+ *
+ * \param[in] tpl_data TPL struct
+ * \param[in] gf_frame_index current frame index in the GOP
+ * \param[in] leaf_qindex q index of leaf frame
+ * \param[in] bit_depth bit depth
+ *
+ * \return q_index
+ */
+int av1_tpl_get_q_index(const TplParams *tpl_data, int gf_frame_index,
+ int leaf_qindex, aom_bit_depth_t bit_depth);
+
+/*!\brief Compute the ratio between arf q step and the leaf q step based on TPL
+ * stats
+ *
+ * \param[in] tpl_data TPL struct
+ * \param[in] gf_frame_index current frame index in the GOP
+ * \param[in] leaf_qindex q index of leaf frame
+ * \param[in] bit_depth bit depth
+ *
+ * \return qstep_ratio
+ */
+double av1_tpl_get_qstep_ratio(const TplParams *tpl_data, int gf_frame_index);
+
+/*!\brief Find a q index whose step size is near qstep_ratio * leaf_qstep
+ *
+ * \param[in] leaf_qindex q index of leaf frame
+ * \param[in] qstep_ratio step ratio between target q index and leaf
+ * q index
+ * \param[in] bit_depth bit depth
+ *
+ * \return q_index
+ */
+int av1_get_q_index_from_qstep_ratio(int leaf_qindex, double qstep_ratio,
+ aom_bit_depth_t bit_depth);
/*!\endcond */
#ifdef __cplusplus
diff --git a/test/ratectrl_test.cc b/test/ratectrl_test.cc
index 735deee..ffb6b9f 100644
--- a/test/ratectrl_test.cc
+++ b/test/ratectrl_test.cc
@@ -39,32 +39,40 @@
EXPECT_EQ(q_index, base_q_index);
}
+#if !CONFIG_REALTIME_ONLY
+// TODO(angiebird): Move this test to tpl_mode_test.cc
TEST(RatectrlTest, QModeComputeGOPQIndicesTest) {
- int base_q_index = 36;
- int arf_q = 36;
+ const int base_q_index = 80;
+ const double arf_qstep_ratio = 0.5;
+ const aom_bit_depth_t bit_depth = AOM_BITS_8;
- int gf_frame_index = 0;
+ const int gf_frame_index = 0;
GF_GROUP gf_group = {};
gf_group.size = 5;
- int layer_depth[5] = { 1, 3, 2, 3, 1 };
- int update_type[5] = { KF_UPDATE, INTNL_ARF_UPDATE, INTNL_OVERLAY_UPDATE,
- INTNL_ARF_UPDATE, ARF_UPDATE };
+ const int layer_depth[5] = { 1, 3, 2, 3, 1 };
+ const int update_type[5] = { KF_UPDATE, INTNL_ARF_UPDATE,
+ INTNL_OVERLAY_UPDATE, INTNL_ARF_UPDATE,
+ ARF_UPDATE };
for (int i = 0; i < gf_group.size; i++) {
gf_group.layer_depth[i] = layer_depth[i];
gf_group.update_type[i] = update_type[i];
}
- av1_q_mode_compute_gop_q_indices(gf_frame_index, base_q_index, arf_q,
- &gf_group);
+ const int arf_q = av1_get_q_index_from_qstep_ratio(
+ base_q_index, arf_qstep_ratio, bit_depth);
+
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, base_q_index,
+ arf_qstep_ratio, bit_depth, &gf_group);
for (int i = 0; i < gf_group.size; i++) {
- if (arf_q == base_q_index) {
- EXPECT_EQ(gf_group.q_val[i], base_q_index);
+ if (layer_depth[i] == 1) {
+ EXPECT_EQ(gf_group.q_val[i], arf_q);
} else {
- EXPECT_LE(gf_group.q_val[i], base_q_index);
+ EXPECT_GT(gf_group.q_val[i], arf_q);
}
}
}
+#endif // !CONFIG_REALTIME_ONLY
} // namespace
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc
index bac6da8..720804e 100644
--- a/test/tpl_model_test.cc
+++ b/test/tpl_model_test.cc
@@ -233,13 +233,15 @@
* Helper method to brute-force search for the closest q_index
* that achieves the specified bit budget.
*/
-int find_gop_q_iterative(double bit_budget, int arf_q, GF_GROUP gf_group,
- TplTxfmStats *stats_list, int gf_frame_index) {
+int find_gop_q_iterative(double bit_budget, double arf_qstep_ratio,
+ GF_GROUP gf_group, TplTxfmStats *stats_list,
+ int gf_frame_index, aom_bit_depth_t bit_depth) {
// Brute force iterative method to find the optimal q.
// Use the result to test against the binary search result.
// Initial estimate when q = 255
- av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, arf_q, &gf_group);
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, arf_qstep_ratio,
+ bit_depth, &gf_group);
double curr_estimate =
av1_estimate_gop_bitrate(gf_group.q_val, gf_group.size, stats_list);
double best_estimate_budget_distance = fabs(curr_estimate - bit_budget);
@@ -247,7 +249,8 @@
// Start at q = 254 because we already have an estimate for q = 255.
for (int q = 254; q >= 0; q--) {
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_q, &gf_group);
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+ bit_depth, &gf_group);
curr_estimate =
av1_estimate_gop_bitrate(gf_group.q_val, gf_group.size, stats_list);
double curr_estimate_budget_distance = fabs(curr_estimate - bit_budget);
@@ -266,7 +269,8 @@
const int gf_group_update_types[25] = { 0, 3, 6, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1,
5, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1, 4 };
const int gf_frame_index = 0;
- const int arf_q = 144;
+ const double arf_qstep_ratio = 2;
+ const aom_bit_depth_t bit_depth = AOM_BITS_8;
for (int i = 0; i < gf_group.size; i++) {
gf_group.update_type[i] = gf_group_update_types[i];
@@ -284,11 +288,13 @@
for (double bit_budget : bit_budgets) {
// Binary search method to find the optimal q.
- int result = av1_q_mode_estimate_base_q(&gf_group, stats_list, bit_budget,
- gf_frame_index, arf_q);
+ const int result =
+ av1_q_mode_estimate_base_q(&gf_group, stats_list, bit_budget,
+ gf_frame_index, arf_qstep_ratio, bit_depth);
- int test_result = find_gop_q_iterative(bit_budget, arf_q, gf_group,
- stats_list, gf_frame_index);
+ const int test_result =
+ find_gop_q_iterative(bit_budget, arf_qstep_ratio, gf_group, stats_list,
+ gf_frame_index, bit_depth);
if (bit_budget == 0) {
EXPECT_EQ(result, 255);