Qmode rc: make last frame always the nearest backward frame
This provides good gains:
hd2 (%):
avgpsnr ovrpsnr ssim vmaf
-2.246 -2.237 -2.188 -2.302
qmode (%):
avgpsnr ovrpsnr ssim vmaf
-3.887 -3.286 -4.073 -3.727
Change-Id: Ib95274f6b4c5bcd41980289634cae835b4481d4e
diff --git a/av1/qmode_rc/reference_manager.cc b/av1/qmode_rc/reference_manager.cc
index eea7b7d..eefd188 100644
--- a/av1/qmode_rc/reference_manager.cc
+++ b/av1/qmode_rc/reference_manager.cc
@@ -209,20 +209,30 @@
void RefFrameManager::UpdateOrder(int global_order_idx) {
cur_global_order_idx_ = global_order_idx;
- if (forward_stack_.empty()) {
- return;
- }
- int ref_idx = forward_stack_.back();
- const GopFrame &gf_frame = ref_frame_table_[ref_idx];
- // If the current processing frame is an overlay / show existing frame.
- if (gf_frame.global_order_idx == global_order_idx) {
- forward_stack_.pop_back();
- if (gf_frame.is_golden_frame) {
- // high quality frame
- backward_queue_.push_back(ref_idx);
- } else {
+ if (!forward_stack_.empty()) {
+ int ref_idx = forward_stack_.back();
+ const GopFrame &gf_frame = ref_frame_table_[ref_idx];
+ // If the current processing frame is an overlay / show existing frame, move
+ // the corresponding arf or intermediate arf frame from forward_stack_ to
+ // last_queue_. In this way this arf will be the last frame for the next
+ // frame.
+ if (gf_frame.global_order_idx == global_order_idx) {
+ forward_stack_.pop_back();
last_queue_.push_back(ref_idx);
+ return;
+ }
+ }
+
+ if (!last_queue_.empty()) {
+ int this_ref_idx = last_queue_.back();
+ GopFrame &this_gf_frame = ref_frame_table_[this_ref_idx];
+ // If the last (stack top) of last_queue_ is an arf frame, then move it to
+ // the backward_queue_ so it will become the golden frame of future leaf
+ // frames.
+ if (this_gf_frame.is_arf_frame) {
+ last_queue_.pop_back();
+ backward_queue_.push_back(this_ref_idx);
}
}
}
diff --git a/test/ratectrl_qmode_test.cc b/test/ratectrl_qmode_test.cc
index 760ae70..39ce2be 100644
--- a/test/ratectrl_qmode_test.cc
+++ b/test/ratectrl_qmode_test.cc
@@ -680,8 +680,8 @@
// After the first kShowExisting, the kIntermediateArf should be moved from
// kForward to kLast due to the cur_global_order_idx_ update
EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kForward), 1);
- EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kBackward), 2);
- EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kLast), 1);
+ EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kBackward), 1);
+ EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kLast), 2);
const int second_leaf_idx = 5;
EXPECT_EQ(type_list[second_leaf_idx], GopFrameType::kRegularLeaf);
@@ -710,10 +710,10 @@
EXPECT_EQ(ref_manager.GetRefFrameCount(), 5);
EXPECT_EQ(ref_manager.CurGlobalOrderIdx(), 4);
// After the kOverlay, the kRegularArf should be moved from
- // kForward to kBackward due to the cur_global_order_idx_ update
+ // kForward to kLast due to the cur_global_order_idx_ update
EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kForward), 0);
- EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kBackward), 3);
- EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kLast), 2);
+ EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kBackward), 2);
+ EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kLast), 3);
}
void TestRefFrameManagerPriority(const RefFrameManager &ref_manager,
@@ -772,9 +772,9 @@
ref_manager.UpdateRefFrameTable(&gop_frame);
}
- EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kBackward), 3);
+ EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kBackward), 2);
TestRefFrameManagerPriority(ref_manager, RefUpdateType::kBackward);
- EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kLast), 2);
+ EXPECT_EQ(ref_manager.GetRefFrameCountByType(RefUpdateType::kLast), 3);
TestRefFrameManagerPriority(ref_manager, RefUpdateType::kLast);
}