Assign q indices based on qstep_ratio.
Previously, we computed the highest level frame's qstep_ratio, then used
av1_q_mode_compute_gop_q_indices to determine the other frames' q
indices.
This change instead calculates the qstep_ratio for each frame in the GOP
and stores them in the vbr_rc_info struct. Then, each frame q index is
determined from the individual qstep_ratios.
We see a slight performance drop in PSNR and abs_rc_error in this CL.
This is because we use the unfiltered ARF when calculating the
qstep_ratios. This performance drop will be compensated in a
following CL. We evaluate this CL on lowres dataset with --limit=17.
The results for this CL are below.
avg_psnr ovr_psnr abs_rc_error
previous CL 0.148% -1.044% -9.046%
this CL 0.384% -0.588% -7.979%
BUG=aomedia:3045
Change-Id: I6f40c5bff908e1898f25229337426fb4308c5b13
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 6bd432d..79dc8ef 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -2900,16 +2900,13 @@
* 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,
- double arf_qstep_ratio,
+ const double *qstep_ratio_list,
aom_bit_depth_t bit_depth,
const struct GF_GROUP *gf_group,
int *q_index_list) {
- 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) {
- const int height = gf_group_pyramid_level(gf_group, gf_index);
- q_index_list[gf_index] = av1_q_mode_get_q_index(
- base_q_index, gf_group->update_type[gf_index], height, arf_q);
+ for (int i = gf_frame_index; i < gf_group->size; ++i) {
+ q_index_list[i] = av1_get_q_index_from_qstep_ratio(
+ base_q_index, qstep_ratio_list[i], bit_depth);
}
}
#endif // !CONFIG_REALTIME_ONLY
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 4ae0da0..07c98a4 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -663,8 +663,7 @@
*
* \param[in] gf_frame_index Index of the current frame
* \param[in] base_q_index Base q index
- * \param[in] arf_qstep_ratio The quantize step ratio between arf q
- * index and base q index
+ * \param[in] qstep_ratio_list Stores the qstep_ratio for each frame
* \param[in] bit_depth Bit depth
* \param[in] gf_group Pointer to the GOP
* \param[out] q_index_list An array to store output gop q indices.
@@ -672,7 +671,7 @@
* greater than gf_group.size()
*/
void av1_q_mode_compute_gop_q_indices(int gf_frame_index, int base_q_index,
- double arf_qstep_ratio,
+ const double *qstep_ratio_list,
aom_bit_depth_t bit_depth,
const struct GF_GROUP *gf_group,
int *q_index_list);
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 70817d6..33a0dcc 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -1960,25 +1960,26 @@
int av1_q_mode_estimate_base_q(const GF_GROUP *gf_group,
const TplTxfmStats *txfm_stats_list,
const int *stats_valid_list, double bit_budget,
- int gf_frame_index, double arf_qstep_ratio,
- aom_bit_depth_t bit_depth, double scale_factor,
+ int gf_frame_index, aom_bit_depth_t bit_depth,
+ double scale_factor,
+ const double *qstep_ratio_list,
int *q_index_list,
double *estimated_bitrate_byframe) {
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_qstep_ratio,
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q_max, qstep_ratio_list,
bit_depth, gf_group, q_index_list);
double q_max_estimate = av1_estimate_gop_bitrate(
q_index_list, gf_group->size, txfm_stats_list, stats_valid_list, NULL);
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q_min, arf_qstep_ratio,
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q_min, qstep_ratio_list,
bit_depth, gf_group, q_index_list);
double q_min_estimate = av1_estimate_gop_bitrate(
q_index_list, gf_group->size, txfm_stats_list, stats_valid_list, NULL);
while (true) {
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q, qstep_ratio_list,
bit_depth, gf_group, q_index_list);
double estimate = av1_estimate_gop_bitrate(
@@ -2009,7 +2010,7 @@
}
// Update q_index_list and vbr_rc_info.
- av1_q_mode_compute_gop_q_indices(gf_frame_index, q, arf_qstep_ratio,
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q, qstep_ratio_list,
bit_depth, gf_group, q_index_list);
av1_estimate_gop_bitrate(q_index_list, gf_group->size, txfm_stats_list,
stats_valid_list, estimated_bitrate_byframe);
@@ -2017,6 +2018,10 @@
}
double av1_tpl_get_qstep_ratio(const TplParams *tpl_data, int gf_frame_index) {
+ if (!av1_tpl_stats_ready(tpl_data, gf_frame_index)) {
+ return 1;
+ }
+
const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[gf_frame_index];
const TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
@@ -2069,9 +2074,11 @@
if (gf_frame_index == 0) {
vbr_rc_info->q_index_list_ready = 1;
double gop_bit_budget = vbr_rc_info->gop_bit_budget;
- // Use the gop_bit_budget to determine q_index_list.
- const double arf_qstep_ratio =
- av1_tpl_get_qstep_ratio(tpl_data, gf_frame_index);
+
+ for (int i = gf_frame_index; i < gf_group->size; i++) {
+ vbr_rc_info->qstep_ratio_list[i] = av1_tpl_get_qstep_ratio(tpl_data, i);
+ }
+
// We update the q indices in vbr_rc_info in vbr_rc_info->q_index_list
// rather than gf_group->q_val to avoid conflicts with the existing code.
int stats_valid_list[MAX_LENGTH_TPL_FRAME_STATS] = { 0 };
@@ -2089,7 +2096,7 @@
av1_q_mode_estimate_base_q(
gf_group, tpl_data->txfm_stats_list, stats_valid_list, gop_bit_budget,
- gf_frame_index, arf_qstep_ratio, bit_depth, scale_factor,
+ gf_frame_index, bit_depth, scale_factor, vbr_rc_info->qstep_ratio_list,
vbr_rc_info->q_index_list, vbr_rc_info->estimated_bitrate_byframe);
}
}
diff --git a/av1/encoder/tpl_model.h b/av1/encoder/tpl_model.h
index 718d447..aa61253 100644
--- a/av1/encoder/tpl_model.h
+++ b/av1/encoder/tpl_model.h
@@ -254,6 +254,9 @@
int actual_bitrate_byframe[MAX_LENGTH_TPL_FRAME_STATS];
int actual_mv_bitrate_byframe[MAX_LENGTH_TPL_FRAME_STATS];
int actual_coeff_bitrate_byframe[MAX_LENGTH_TPL_FRAME_STATS];
+
+ // Array to store qstep_ratio for each frame in a GOP
+ double qstep_ratio_list[MAX_LENGTH_TPL_FRAME_STATS];
} VBR_RATECTRL_INFO;
static INLINE void vbr_rc_reset_gop_data(VBR_RATECTRL_INFO *vbr_rc_info) {
@@ -550,10 +553,10 @@
* exists
* \param[in] bit_budget The specified bit budget to achieve
* \param[in] gf_frame_index current frame in the GOP
- * \param[in] arf_qstep_ratio ARF q step ratio
* \param[in] bit_depth bit depth
* \param[in] scale_factor Scale factor to improve budget estimation
- * \param[out] q_index_list array of q_index, one per frame
+ * \param[in] qstep_ratio_list Stores the qstep_ratio for each frame
+ * \param[out] q_index_list array of q_index, one per frame
* \param[out] estimated_bitrate_byframe bits usage per frame in the GOP
*
* \return Returns the optimal base q index to use.
@@ -561,8 +564,9 @@
int av1_q_mode_estimate_base_q(const struct GF_GROUP *gf_group,
const TplTxfmStats *txfm_stats_list,
const int *stats_valid_list, double bit_budget,
- int gf_frame_index, double arf_qstep_ratio,
- aom_bit_depth_t bit_depth, double scale_factor,
+ int gf_frame_index, aom_bit_depth_t bit_depth,
+ double scale_factor,
+ const double *qstep_ratio_list,
int *q_index_list,
double *estimated_bitrate_byframe);
diff --git a/test/ratectrl_test.cc b/test/ratectrl_test.cc
index 67adf27..4b462e3 100644
--- a/test/ratectrl_test.cc
+++ b/test/ratectrl_test.cc
@@ -41,7 +41,7 @@
// TODO(angiebird): Move this test to tpl_mode_test.cc
TEST(RatectrlTest, QModeComputeGOPQIndicesTest) {
const int base_q_index = 80;
- const double arf_qstep_ratio = 0.5;
+ double qstep_ratio_list[5] = { 0.5, 1, 1, 1, 0.5 };
const aom_bit_depth_t bit_depth = AOM_BITS_8;
const int gf_frame_index = 0;
@@ -58,10 +58,10 @@
}
const int arf_q = av1_get_q_index_from_qstep_ratio(
- base_q_index, arf_qstep_ratio, bit_depth);
+ base_q_index, qstep_ratio_list[0], bit_depth);
av1_q_mode_compute_gop_q_indices(gf_frame_index, base_q_index,
- arf_qstep_ratio, bit_depth, &gf_group,
+ qstep_ratio_list, bit_depth, &gf_group,
gf_group.q_val);
for (int i = 0; i < gf_group.size; i++) {
diff --git a/test/tpl_model_test.cc b/test/tpl_model_test.cc
index 3094c6c..da5a821 100644
--- a/test/tpl_model_test.cc
+++ b/test/tpl_model_test.cc
@@ -235,7 +235,7 @@
* 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, double arf_qstep_ratio,
+int find_gop_q_iterative(double bit_budget, const double *qstep_ratio_list,
GF_GROUP gf_group, const int *stats_valid_list,
TplTxfmStats *stats_list, int gf_frame_index,
aom_bit_depth_t bit_depth) {
@@ -243,7 +243,7 @@
// 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_qstep_ratio,
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, 255, qstep_ratio_list,
bit_depth, &gf_group, gf_group.q_val);
double curr_estimate = av1_estimate_gop_bitrate(
gf_group.q_val, gf_group.size, stats_list, stats_valid_list, NULL);
@@ -252,7 +252,7 @@
// 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_qstep_ratio,
+ av1_q_mode_compute_gop_q_indices(gf_frame_index, q, qstep_ratio_list,
bit_depth, &gf_group, gf_group.q_val);
curr_estimate = av1_estimate_gop_bitrate(
gf_group.q_val, gf_group.size, stats_list, stats_valid_list, NULL);
@@ -274,10 +274,14 @@
5, 6, 6, 1, 5, 1, 5, 6, 1, 5, 1, 4 };
int stats_valid_list[25] = { 0 };
const int gf_frame_index = 0;
- const double arf_qstep_ratio = 2;
const aom_bit_depth_t bit_depth = AOM_BITS_8;
const double scale_factor = 1.0;
+ double qstep_ratio_list[25];
+ for (int i = 0; i < 25; i++) {
+ qstep_ratio_list[i] = 1;
+ }
+
for (int i = 0; i < gf_group.size; i++) {
stats_valid_list[i] = 1;
gf_group.update_type[i] = gf_group_update_types[i];
@@ -297,9 +301,9 @@
// Binary search method to find the optimal q.
const int result = av1_q_mode_estimate_base_q(
&gf_group, stats_list, stats_valid_list, bit_budget, gf_frame_index,
- arf_qstep_ratio, bit_depth, scale_factor, q_index_list, NULL);
+ bit_depth, scale_factor, qstep_ratio_list, q_index_list, NULL);
const int test_result = find_gop_q_iterative(
- bit_budget, arf_qstep_ratio, gf_group, stats_valid_list, stats_list,
+ bit_budget, qstep_ratio_list, gf_group, stats_valid_list, stats_list,
gf_frame_index, bit_depth);
if (bit_budget == 0) {