Use base_q_ratio to determine base qp in qmode rc
BUG: b/264900183
Change-Id: I98d2254248d57fe7e0848d38fc581c417ebfa9cf
diff --git a/av1/qmode_rc/ratectrl_qmode.cc b/av1/qmode_rc/ratectrl_qmode.cc
index 888323b..d87b32a 100644
--- a/av1/qmode_rc/ratectrl_qmode.cc
+++ b/av1/qmode_rc/ratectrl_qmode.cc
@@ -868,6 +868,12 @@
StatusOr<GopStructList> AV1RateControlQMode::DetermineGopInfo(
const FirstpassInfo &firstpass_info) {
const int stats_size = static_cast<int>(firstpass_info.stats_list.size());
+ if (stats_size <= 0) {
+ Status status;
+ status.code = AOM_CODEC_INVALID_PARAM;
+ status.message = "The firstpass info length is insufficient.";
+ return status;
+ }
GopStructList gop_list;
RefFrameManager ref_frame_manager(rc_param_.ref_frame_table_size,
rc_param_.max_ref_frames);
@@ -903,6 +909,33 @@
gop_list.push_back(gop);
}
}
+
+ // Determine the qp adjustment ratio for this gop.
+ double global_avg_coded_error = 0.0;
+ for (int i = 0; i < stats_size; ++i) {
+ global_avg_coded_error +=
+ log(1.0 + std::min(analyzed_fp_info.stats_list[i].coded_error,
+ analyzed_fp_info.stats_list[i].sr_coded_error));
+ }
+ global_avg_coded_error /= static_cast<double>(stats_size);
+
+ for (auto &gop_struct : gop_list) {
+ double gop_avg_coded_error = 0.0;
+ for (int i = gop_struct.global_order_idx_offset;
+ i < gop_struct.global_order_idx_offset + gop_struct.show_frame_count;
+ ++i) {
+ gop_avg_coded_error +=
+ log(1.0 + std::min(analyzed_fp_info.stats_list[i].coded_error,
+ analyzed_fp_info.stats_list[i].sr_coded_error));
+ }
+ gop_avg_coded_error /=
+ std::max(static_cast<double>(gop_struct.show_frame_count), 1.0);
+
+ gop_struct.base_q_ratio =
+ fabs(global_avg_coded_error - gop_avg_coded_error) < 0.001
+ ? 1.0
+ : exp((global_avg_coded_error - gop_avg_coded_error) * 2.0);
+ }
return gop_list;
}
@@ -1674,14 +1707,17 @@
const GopStruct &gop_struct) {
GopEncodeInfo gop_encode_info;
const int frame_count = static_cast<int>(gop_struct.gop_frame_list.size());
- for (int i = 0; i < frame_count; i++) {
+ const int base_offset = av1_get_deltaq_offset(
+ AOM_BITS_8, rc_param_.base_q_index, gop_struct.base_q_ratio);
+ const int base_q_index = rc_param_.base_q_index + base_offset;
+ for (int i = 0; i < frame_count; ++i) {
FrameEncodeParameters param;
const GopFrame &gop_frame = gop_struct.gop_frame_list[i];
// Use constant QP for TPL pass encoding. Keep the functionality
// that allows QP changes across sub-gop.
- param.q_index = rc_param_.base_q_index;
+ param.q_index = base_q_index;
param.rdmult = av1_compute_rd_mult_based_on_qindex(AOM_BITS_8, LF_UPDATE,
- rc_param_.base_q_index);
+ base_q_index);
// TODO(jingning): gop_frame is needed in two pass tpl later.
(void)gop_frame;
@@ -1858,15 +1894,19 @@
GopFrame arf_frame = GopFrameInvalid();
const int frame_count = static_cast<int>(gop_struct.gop_frame_list.size());
- const int active_worst_quality = rc_param_.base_q_index;
- int active_best_quality = rc_param_.base_q_index;
+
+ const int base_offset = av1_get_deltaq_offset(
+ AOM_BITS_8, rc_param_.base_q_index, gop_struct.base_q_ratio);
+ const int base_q_index = rc_param_.base_q_index + base_offset;
+ const int active_worst_quality = base_q_index;
+ int active_best_quality = base_q_index;
for (int i = 0; i < frame_count; ++i) {
FrameEncodeParameters param;
const GopFrame &gop_frame = gop_struct.gop_frame_list[i];
if (gop_frame.update_type == GopFrameType::kOverlay ||
gop_frame.update_type == GopFrameType::kIntermediateOverlay ||
gop_frame.update_type == GopFrameType::kRegularLeaf) {
- param.q_index = rc_param_.base_q_index;
+ param.q_index = base_q_index;
} else if (gop_frame.update_type == GopFrameType::kRegularKey ||
gop_frame.update_type == GopFrameType::kRegularGolden ||
gop_frame.update_type == GopFrameType::kRegularArf) {
@@ -1884,11 +1924,10 @@
std::max(sqrt(score), 1.0),
gop_frame.update_type == GopFrameType::kRegularKey ? 6.0 : 4.0);
const double qstep_ratio = 1.0 / boost;
- param.q_index = av1_get_q_index_from_qstep_ratio(rc_param_.base_q_index,
+ param.q_index = av1_get_q_index_from_qstep_ratio(base_q_index,
qstep_ratio, AOM_BITS_8);
- param.q_index = AdjustStaticQp(avg_correlation, score, param.q_index);
- if (rc_param_.base_q_index) param.q_index = std::max(param.q_index, 1);
+ if (base_q_index) param.q_index = std::max(param.q_index, 1);
active_best_quality = param.q_index;
if (gop_frame.update_type == GopFrameType::kRegularArf) {
@@ -1924,8 +1963,6 @@
static_cast<int>(tpl_gop_stats.frame_stats_list.size());
const int stats_size = static_cast<int>(firstpass_info.stats_list.size());
- const FirstpassInfo analyzed_fp_info =
- AnalyzeFpStats(std::move(firstpass_info));
const int this_gop_len = gop_struct.show_frame_count;
const int next_gop_len =
@@ -1939,8 +1976,12 @@
return status;
}
- const int active_worst_quality = rc_param_.base_q_index;
- int active_best_quality = rc_param_.base_q_index;
+ const int base_offset = av1_get_deltaq_offset(
+ AOM_BITS_8, rc_param_.base_q_index, gop_struct.base_q_ratio);
+ const int base_q_index = rc_param_.base_q_index + base_offset;
+
+ const int active_worst_quality = base_q_index;
+ int active_best_quality = base_q_index;
double base_rdcost = 1.0; // baseline total rdcost
double hqr_rdcost = 0; // high quality reference total rdcost
@@ -1969,14 +2010,14 @@
double tp_frame_importance =
1.0 + fabs((base_rdcost - hqr_rdcost) / arf_rdcost_high);
- for (int i = 0; i < frame_count; i++) {
+ for (int i = 0; i < frame_count; ++i) {
FrameEncodeParameters param;
const GopFrame &gop_frame = gop_struct.gop_frame_list[i];
if (gop_frame.update_type == GopFrameType::kOverlay ||
gop_frame.update_type == GopFrameType::kIntermediateOverlay ||
gop_frame.update_type == GopFrameType::kRegularLeaf) {
- param.q_index = rc_param_.base_q_index;
+ param.q_index = base_q_index;
} else if (gop_frame.update_type == GopFrameType::kRegularGolden ||
gop_frame.update_type == GopFrameType::kRegularKey ||
gop_frame.update_type == GopFrameType::kRegularArf) {
@@ -1997,21 +2038,10 @@
// Imitate the behavior of av1_tpl_get_qstep_ratio()
const double qstep_ratio = sqrt(1 / frame_importance);
- param.q_index = av1_get_q_index_from_qstep_ratio(rc_param_.base_q_index,
+ param.q_index = av1_get_q_index_from_qstep_ratio(base_q_index,
qstep_ratio, AOM_BITS_8);
- int this_index, first_index, last_index, ref_before_index,
- ref_after_index;
- SetUpFrameIndices(gop_frame.update_type, stats_size, this_gop_len,
- next_gop_len, this_index, first_index, last_index,
- ref_before_index, ref_after_index);
- double avg_correlation = 0;
- const double score = GetAccumulatedScore(
- analyzed_fp_info, this_index, first_index, last_index,
- ref_before_index, ref_after_index, avg_correlation);
- param.q_index = AdjustStaticQp(avg_correlation, score, param.q_index);
-
- if (rc_param_.base_q_index) param.q_index = AOMMAX(param.q_index, 1);
+ if (base_q_index) param.q_index = AOMMAX(param.q_index, 1);
active_best_quality = param.q_index;
if (rc_param_.max_distinct_q_indices_per_frame > 1) {
diff --git a/test/ratectrl_qmode_test.cc b/test/ratectrl_qmode_test.cc
index dcf72d2..9b8d4ef 100644
--- a/test/ratectrl_qmode_test.cc
+++ b/test/ratectrl_qmode_test.cc
@@ -9,6 +9,7 @@
* PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
+#include "av1/encoder/rd.h"
#include "av1/qmode_rc/ratectrl_qmode.h"
#include <algorithm>
@@ -1062,8 +1063,13 @@
rc.GetGopEncodeInfo(gop_list[gop_idx], tpl_gop_list[tpl_gop_idx], {},
firstpass_info, ref_frame_table);
ASSERT_THAT(gop_encode_info.status(), IsOkStatus());
+
+ const int base_offset = av1_get_deltaq_offset(
+ AOM_BITS_8, rc_param_.base_q_index, gop_list[gop_idx].base_q_ratio);
+ const int base_q_index = rc_param_.base_q_index + base_offset;
+
for (auto &frame_param : gop_encode_info->param_list) {
- EXPECT_LE(frame_param.q_index, rc_param_.base_q_index);
+ EXPECT_LE(frame_param.q_index, base_q_index);
}
ref_frame_table = gop_encode_info->final_snapshot;
for (auto &gop_frame : ref_frame_table) {