Add test for qmode deltaq for ducky encode
This new test runs end to end encoding and verifies the psnr of each
encoded frame to be not too low.
Also:
- Fix a bug of delta-q flag being persistent.
- Populate encode results from ducky encode
Bug: b/256852795
Change-Id: I022fcbf785b7eab621262881095683f9606a48ef
diff --git a/av1/qmode_rc/ducky_encode.cc b/av1/qmode_rc/ducky_encode.cc
index dc71b6b..74bbf8a 100644
--- a/av1/qmode_rc/ducky_encode.cc
+++ b/av1/qmode_rc/ducky_encode.cc
@@ -399,12 +399,14 @@
static void DuckyEncodeInfoSetEncodeFrameDecision(
DuckyEncodeInfo *ducky_encode_info, const EncodeFrameDecision &decision) {
DuckyEncodeFrameInfo *frame_info = &ducky_encode_info->frame_info;
+ *frame_info = {};
frame_info->qp_mode = static_cast<DUCKY_ENCODE_FRAME_MODE>(decision.qp_mode);
frame_info->gop_mode = static_cast<DUCKY_ENCODE_GOP_MODE>(decision.gop_mode);
frame_info->q_index = decision.parameters.q_index;
frame_info->rdmult = decision.parameters.rdmult;
const size_t num_superblocks =
decision.parameters.superblock_encode_params.size();
+ frame_info->delta_q_enabled = 0;
if (num_superblocks > 1) {
frame_info->delta_q_enabled = 1;
frame_info->superblock_encode_qindex = new int[num_superblocks];
@@ -591,10 +593,10 @@
aom::EncodeFrameDecision frame_decision = { aom::EncodeFrameMode::kQindex,
aom::EncodeGopMode::kGopRcl,
frame_param };
- EncodeFrame(frame_decision);
+ EncodeFrameResult temp_result = EncodeFrame(frame_decision);
if (ppi->cpi->common.show_frame) {
bitstream_buf_.resize(pending_ctx_size_);
- EncodeFrameResult encode_frame_result = {};
+ EncodeFrameResult encode_frame_result = temp_result;
encode_frame_result.bitstream_buf = bitstream_buf_;
encoded_frame_list.push_back(encode_frame_result);
diff --git a/test/ducky_encode_test.cc b/test/ducky_encode_test.cc
index 4dcb3dc..ff6bc2f 100644
--- a/test/ducky_encode_test.cc
+++ b/test/ducky_encode_test.cc
@@ -21,7 +21,10 @@
#include "av1/encoder/encoder.h"
#include "av1/qmode_rc/ducky_encode.h"
+#include "av1/qmode_rc/ratectrl_qmode.h"
+#include "av1/qmode_rc/ratectrl_qmode_interface.h"
#include "test/video_source.h"
+#include "third_party/googletest/src/googlemock/include/gmock/gmock.h"
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
namespace aom {
@@ -94,12 +97,88 @@
for (int i = 0; i < coding_frame_count; ++i) {
ducky_encode.AllocateBitstreamBuffer(video_info);
EncodeFrameResult encode_frame_result = ducky_encode.EncodeFrame(decision);
- // TODO(angiebird): Check why distortion is not zero when q_index = 0
EXPECT_EQ(encode_frame_result.dist, 0);
}
ducky_encode.EndEncode();
}
+TEST(DuckyEncodeRCTest, EncodeVideoWithRC) {
+ aom_rational_t frame_rate = { 30, 1 };
+ const int frame_number = 35;
+ const int frame_width = 352;
+ const int frame_height = 288;
+ VideoInfo video_info = { frame_width, frame_height,
+ frame_rate, AOM_IMG_FMT_I420,
+ frame_number, "bus_352x288_420_f20_b8.yuv" };
+ video_info.file_path =
+ libaom_test::GetDataPath() + "/" + video_info.file_path;
+ DuckyEncode ducky_encode(video_info, BLOCK_64X64, kMaxRefFrames, 3, 128);
+
+ AV1RateControlQMode qmode_rc;
+ RateControlParam rc_param = {};
+ rc_param.max_gop_show_frame_count = 16;
+ rc_param.min_gop_show_frame_count = 4;
+ rc_param.ref_frame_table_size = 5;
+ rc_param.max_ref_frames = 3;
+ rc_param.base_q_index = 45;
+ rc_param.max_distinct_q_indices_per_frame = 8;
+ rc_param.max_distinct_lambda_scales_per_frame = 1;
+ rc_param.frame_width = frame_width;
+ rc_param.frame_height = frame_height;
+ rc_param.tpl_pass_count = TplPassCount::kOneTplPass;
+ rc_param.tpl_pass_index = 0;
+ const Status status = qmode_rc.SetRcParam(rc_param);
+ ASSERT_TRUE(status.ok());
+ FirstpassInfo firstpass_info;
+ firstpass_info.stats_list = ducky_encode.ComputeFirstPassStats();
+ constexpr int kBlockSize = 16;
+ firstpass_info.num_mbs_16x16 = ((frame_width + kBlockSize - 1) / kBlockSize) *
+ ((frame_height + kBlockSize - 1) / kBlockSize);
+ const auto gop_info = qmode_rc.DetermineGopInfo(firstpass_info);
+ ASSERT_TRUE(gop_info.status().ok());
+ const GopStructList &gop_list = gop_info.value();
+
+ std::vector<aom::GopEncodeInfo> tpl_pass_gop_encode_info_list;
+ std::vector<aom::TplGopStats> tpl_gop_stats_list;
+ for (const auto &gop_struct : gop_list) {
+ const auto gop_encode_info = qmode_rc.GetTplPassGopEncodeInfo(gop_struct);
+ ASSERT_TRUE(gop_encode_info.status().ok());
+ tpl_pass_gop_encode_info_list.push_back(std::move(*gop_encode_info));
+ }
+ ducky_encode.StartEncode(firstpass_info.stats_list);
+ tpl_gop_stats_list =
+ ducky_encode.ComputeTplStats(gop_list, tpl_pass_gop_encode_info_list);
+ ducky_encode.EndEncode();
+
+ std::vector<aom::GopEncodeInfo> final_pass_gop_encode_info_list;
+ aom::RefFrameTable ref_frame_table;
+ for (size_t i = 0; i < gop_list.size(); ++i) {
+ const aom::GopStruct &gop_struct = gop_list[i];
+ const aom::TplGopStats &tpl_gop_stats = tpl_gop_stats_list[i];
+ std::vector<aom::LookaheadStats> lookahead_stats = {};
+ for (size_t lookahead_index = 1;
+ lookahead_index <= 1 && i + lookahead_index < gop_list.size();
+ ++lookahead_index) {
+ lookahead_stats.push_back({ &gop_list[i + lookahead_index],
+ &tpl_gop_stats_list[i + lookahead_index] });
+ }
+ const auto gop_encode_info = qmode_rc.GetGopEncodeInfo(
+ gop_struct, tpl_gop_stats, lookahead_stats, ref_frame_table);
+ ASSERT_TRUE(gop_encode_info.status().ok());
+ ref_frame_table = gop_encode_info.value().final_snapshot;
+ final_pass_gop_encode_info_list.push_back(std::move(*gop_encode_info));
+ }
+
+ ducky_encode.StartEncode(firstpass_info.stats_list);
+ std::vector<aom::EncodeFrameResult> encoded_frames_list =
+ ducky_encode.EncodeVideo(gop_list, final_pass_gop_encode_info_list);
+ ducky_encode.EndEncode();
+
+ EXPECT_THAT(encoded_frames_list,
+ testing::Each(testing::Field(
+ "psnr", &aom::EncodeFrameResult::psnr, testing::Gt(37))));
+}
+
TEST(DuckyEncodeTest, EncodeFrameMode) {
EXPECT_EQ(DUCKY_ENCODE_FRAME_MODE_NONE,
static_cast<DUCKY_ENCODE_FRAME_MODE>(EncodeFrameMode::kNone));