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));