• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include <array>
13 #include <algorithm>
14 #include <cerrno>
15 #include <cstring>
16 #include <fstream>
17 #include <memory>
18 #include <numeric>
19 #include <string>
20 #include <vector>
21 
22 #include "av1/encoder/encoder.h"
23 #include "av1/qmode_rc/ducky_encode.h"
24 #include "av1/qmode_rc/ratectrl_qmode.h"
25 #include "av1/qmode_rc/ratectrl_qmode_interface.h"
26 #include "test/video_source.h"
27 #include "third_party/googletest/src/googlemock/include/gmock/gmock.h"
28 #include "third_party/googletest/src/googletest/include/gtest/gtest.h"
29 
30 namespace aom {
31 
32 constexpr int kMaxRefFrames = 7;
33 
TEST(DuckyEncodeTest,ComputeFirstPassStats)34 TEST(DuckyEncodeTest, ComputeFirstPassStats) {
35   aom_rational_t frame_rate = { 30, 1 };
36   VideoInfo video_info = { 352,        288,
37                            frame_rate, AOM_IMG_FMT_I420,
38                            1,          "bus_352x288_420_f20_b8.yuv" };
39   video_info.file_path =
40       libaom_test::GetDataPath() + "/" + video_info.file_path;
41   DuckyEncode ducky_encode(video_info, BLOCK_64X64, kMaxRefFrames, 3, 128);
42   std::vector<FIRSTPASS_STATS> frame_stats =
43       ducky_encode.ComputeFirstPassStats();
44   EXPECT_EQ(frame_stats.size(), static_cast<size_t>(video_info.frame_count));
45   for (size_t i = 0; i < frame_stats.size(); ++i) {
46     // FIRSTPASS_STATS's first element is frame
47     EXPECT_EQ(frame_stats[i].frame, i);
48   }
49 }
50 
TEST(DuckyEncodeTest,EncodeFrame)51 TEST(DuckyEncodeTest, EncodeFrame) {
52   aom_rational_t frame_rate = { 30, 1 };
53   VideoInfo video_info = { 352,        288,
54                            frame_rate, AOM_IMG_FMT_I420,
55                            17,         "bus_352x288_420_f20_b8.yuv" };
56   video_info.file_path =
57       libaom_test::GetDataPath() + "/" + video_info.file_path;
58   DuckyEncode ducky_encode(video_info, BLOCK_64X64, kMaxRefFrames, 3, 128);
59   std::vector<FIRSTPASS_STATS> frame_stats =
60       ducky_encode.ComputeFirstPassStats();
61   ducky_encode.StartEncode(frame_stats);
62   // We set coding_frame_count to a arbitrary number that smaller than
63   // 17 here.
64   // TODO(angiebird): Set coding_frame_count properly, once the DuckyEncode can
65   // provide proper information.
66   int coding_frame_count = 5;
67   EncodeFrameDecision decision = { aom::EncodeFrameMode::kNone,
68                                    aom::EncodeGopMode::kNone,
69                                    {} };
70   for (int i = 0; i < coding_frame_count; ++i) {
71     ducky_encode.AllocateBitstreamBuffer(video_info);
72     EncodeFrameResult encode_frame_result = ducky_encode.EncodeFrame(decision);
73   }
74   ducky_encode.EndEncode();
75 }
76 
TEST(DuckyEncodeTest,EncodeFrameWithQindex)77 TEST(DuckyEncodeTest, EncodeFrameWithQindex) {
78   aom_rational_t frame_rate = { 30, 1 };
79   VideoInfo video_info = { 352,        288,
80                            frame_rate, AOM_IMG_FMT_I420,
81                            17,         "bus_352x288_420_f20_b8.yuv" };
82   video_info.file_path =
83       libaom_test::GetDataPath() + "/" + video_info.file_path;
84   DuckyEncode ducky_encode(video_info, BLOCK_64X64, kMaxRefFrames, 3, 128);
85   std::vector<FIRSTPASS_STATS> frame_stats =
86       ducky_encode.ComputeFirstPassStats();
87   ducky_encode.StartEncode(frame_stats);
88   // We set coding_frame_count to a arbitrary number that smaller than
89   // 17 here.
90   // TODO(angiebird): Set coding_frame_count properly, once the DuckyEncode can
91   // provide proper information.
92   int coding_frame_count = 5;
93   int q_index = 0;
94   EncodeFrameDecision decision = { aom::EncodeFrameMode::kQindex,
95                                    aom::EncodeGopMode::kNone,
96                                    { q_index, -1, {}, {} } };
97   for (int i = 0; i < coding_frame_count; ++i) {
98     ducky_encode.AllocateBitstreamBuffer(video_info);
99     EncodeFrameResult encode_frame_result = ducky_encode.EncodeFrame(decision);
100     EXPECT_EQ(encode_frame_result.dist, 0);
101   }
102   ducky_encode.EndEncode();
103 }
104 
TEST(DuckyEncodeRCTest,EncodeVideoWithRC)105 TEST(DuckyEncodeRCTest, EncodeVideoWithRC) {
106   aom_rational_t frame_rate = { 30, 1 };
107   const int frame_number = 35;
108   const int frame_width = 352;
109   const int frame_height = 288;
110   VideoInfo video_info = { frame_width,  frame_height,
111                            frame_rate,   AOM_IMG_FMT_I420,
112                            frame_number, "bus_352x288_420_f20_b8.yuv" };
113   video_info.file_path =
114       libaom_test::GetDataPath() + "/" + video_info.file_path;
115   DuckyEncode ducky_encode(video_info, BLOCK_64X64, kMaxRefFrames, 3, 128);
116 
117   AV1RateControlQMode qmode_rc;
118   RateControlParam rc_param = {};
119   rc_param.max_gop_show_frame_count = 16;
120   rc_param.min_gop_show_frame_count = 4;
121   rc_param.ref_frame_table_size = 5;
122   rc_param.max_ref_frames = 3;
123   rc_param.base_q_index = 45;
124   rc_param.max_distinct_q_indices_per_frame = 8;
125   rc_param.max_distinct_lambda_scales_per_frame = 1;
126   rc_param.frame_width = frame_width;
127   rc_param.frame_height = frame_height;
128   rc_param.tpl_pass_count = TplPassCount::kOneTplPass;
129   rc_param.tpl_pass_index = 0;
130   const Status status = qmode_rc.SetRcParam(rc_param);
131   ASSERT_TRUE(status.ok());
132   FirstpassInfo firstpass_info;
133   firstpass_info.stats_list = ducky_encode.ComputeFirstPassStats();
134   constexpr int kBlockSize = 16;
135   firstpass_info.num_mbs_16x16 = ((frame_width + kBlockSize - 1) / kBlockSize) *
136                                  ((frame_height + kBlockSize - 1) / kBlockSize);
137   const auto gop_info = qmode_rc.DetermineGopInfo(firstpass_info);
138   ASSERT_TRUE(gop_info.status().ok());
139   const GopStructList &gop_list = gop_info.value();
140 
141   std::vector<aom::GopEncodeInfo> tpl_pass_gop_encode_info_list;
142   std::vector<aom::TplGopStats> tpl_gop_stats_list;
143   for (const auto &gop_struct : gop_list) {
144     const auto gop_encode_info =
145         qmode_rc.GetTplPassGopEncodeInfo(gop_struct, firstpass_info);
146     ASSERT_TRUE(gop_encode_info.status().ok());
147     tpl_pass_gop_encode_info_list.push_back(std::move(*gop_encode_info));
148   }
149 
150   tpl_gop_stats_list = ducky_encode.ComputeTplStats(
151       firstpass_info.stats_list, gop_list, tpl_pass_gop_encode_info_list);
152 
153   std::vector<aom::GopEncodeInfo> final_pass_gop_encode_info_list;
154   aom::RefFrameTable ref_frame_table;
155   for (size_t i = 0; i < gop_list.size(); ++i) {
156     const aom::GopStruct &gop_struct = gop_list[i];
157     const aom::TplGopStats &tpl_gop_stats = tpl_gop_stats_list[i];
158     std::vector<aom::LookaheadStats> lookahead_stats = {};
159     for (size_t lookahead_index = 1;
160          lookahead_index <= 1 && i + lookahead_index < gop_list.size();
161          ++lookahead_index) {
162       lookahead_stats.push_back({ &gop_list[i + lookahead_index],
163                                   &tpl_gop_stats_list[i + lookahead_index] });
164     }
165     const auto gop_encode_info =
166         qmode_rc.GetGopEncodeInfo(gop_struct, tpl_gop_stats, lookahead_stats,
167                                   firstpass_info, ref_frame_table);
168     ASSERT_TRUE(gop_encode_info.status().ok());
169     ref_frame_table = gop_encode_info.value().final_snapshot;
170     final_pass_gop_encode_info_list.push_back(std::move(*gop_encode_info));
171   }
172 
173   ducky_encode.StartEncode(firstpass_info.stats_list);
174   std::vector<aom::EncodeFrameResult> encoded_frames_list =
175       ducky_encode.EncodeVideo(gop_list, final_pass_gop_encode_info_list);
176   ducky_encode.EndEncode();
177 
178   EXPECT_THAT(encoded_frames_list,
179               testing::Each(testing::Field(
180                   "psnr", &aom::EncodeFrameResult::psnr, testing::Gt(37))));
181 }
182 
TEST(DuckyEncodeTest,EncodeFrameMode)183 TEST(DuckyEncodeTest, EncodeFrameMode) {
184   EXPECT_EQ(DUCKY_ENCODE_FRAME_MODE_NONE,
185             static_cast<DUCKY_ENCODE_FRAME_MODE>(EncodeFrameMode::kNone));
186   EXPECT_EQ(DUCKY_ENCODE_FRAME_MODE_QINDEX,
187             static_cast<DUCKY_ENCODE_FRAME_MODE>(EncodeFrameMode::kQindex));
188   EXPECT_EQ(
189       DUCKY_ENCODE_FRAME_MODE_QINDEX_RDMULT,
190       static_cast<DUCKY_ENCODE_FRAME_MODE>(EncodeFrameMode::kQindexRdmult));
191 }
192 
193 }  // namespace aom
194