1 /*
2 * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <cstdint>
12 #include <new>
13 #include <memory>
14
15 #include "./vpx_config.h"
16
17 #include "gtest/gtest.h"
18 #include "test/codec_factory.h"
19 #include "test/encode_test_driver.h"
20 #include "test/util.h"
21 #include "test/yuv_video_source.h"
22 #if CONFIG_VP9_DECODER
23 #include "vpx/vp8dx.h"
24 #endif
25 #include "vp9/simple_encode.h"
26 #include "vpx/vpx_codec.h"
27 #include "vpx/vpx_encoder.h"
28 #include "vpx/vpx_ext_ratectrl.h"
29 #include "vpx/vpx_image.h"
30 #include "vpx/vpx_tpl.h"
31 #include "vpx_dsp/vpx_dsp_common.h"
32
33 namespace {
34
35 constexpr int kShowFrameCount = 10;
36 constexpr int kKeyframeQp = 10;
37 constexpr int kLeafQp = 40;
38 constexpr int kArfQp = 15;
39
40 // Simple external rate controller for testing.
41 class RateControllerForTest {
42 public:
RateControllerForTest()43 RateControllerForTest() : current_gop_(-1) {}
~RateControllerForTest()44 ~RateControllerForTest() {}
45
StartNextGop()46 void StartNextGop() { ++current_gop_; }
47
GetCurrentGop() const48 vpx_rc_gop_decision_t GetCurrentGop() const {
49 vpx_rc_gop_decision_t gop_decision;
50 if (current_gop_ == 0) {
51 gop_decision.use_key_frame = 1;
52 gop_decision.use_alt_ref = 1;
53 gop_decision.gop_coding_frames =
54 kShowFrameCount - 1 + gop_decision.use_alt_ref;
55 // key frame
56 gop_decision.update_type[0] = VPX_RC_KF_UPDATE;
57 gop_decision.update_ref_index[0] = 0;
58 gop_decision.ref_frame_list[0] = get_kf_ref_frame();
59 // arf
60 gop_decision.update_type[1] = VPX_RC_ARF_UPDATE;
61 gop_decision.update_ref_index[1] = 1;
62 gop_decision.ref_frame_list[1] = get_arf_ref_frame();
63 // leafs
64 for (int i = 2; i < gop_decision.gop_coding_frames; ++i) {
65 gop_decision.update_type[i] = VPX_RC_LF_UPDATE;
66 gop_decision.update_ref_index[i] = 2;
67 gop_decision.ref_frame_list[i] = get_leaf_ref_frame(i);
68 }
69 } else {
70 // Pad a overlay-only GOP as the last GOP.
71 EXPECT_EQ(current_gop_, 1);
72 gop_decision.use_key_frame = 0;
73 gop_decision.use_alt_ref = 0;
74 gop_decision.gop_coding_frames = 1;
75
76 gop_decision.update_type[0] = VPX_RC_OVERLAY_UPDATE;
77 gop_decision.update_ref_index[0] = 1;
78 gop_decision.ref_frame_list[0] = get_ovl_ref_frame();
79 }
80 return gop_decision;
81 }
82
CalculateFrameDecision(int frame_index)83 int CalculateFrameDecision(int frame_index) {
84 if (current_gop_ == 0 && frame_index == 0) {
85 // Key frame, first frame in the first GOP.
86 return kKeyframeQp;
87 } else if (frame_index == 1) {
88 // ARF, we always use ARF for this test.
89 return kArfQp;
90 } else {
91 return kLeafQp;
92 }
93 }
94
95 private:
get_kf_ref_frame() const96 vpx_rc_ref_frame_t get_kf_ref_frame() const {
97 vpx_rc_ref_frame_t ref_frame;
98 ref_frame.index[0] = -1;
99 ref_frame.index[1] = -1;
100 ref_frame.index[2] = -1;
101 ref_frame.name[0] = VPX_RC_INVALID_REF_FRAME;
102 ref_frame.name[1] = VPX_RC_INVALID_REF_FRAME;
103 ref_frame.name[2] = VPX_RC_INVALID_REF_FRAME;
104 return ref_frame;
105 }
get_arf_ref_frame() const106 vpx_rc_ref_frame_t get_arf_ref_frame() const {
107 vpx_rc_ref_frame_t ref_frame;
108 ref_frame.index[0] = 0;
109 ref_frame.index[1] = -1;
110 ref_frame.index[2] = -1;
111 ref_frame.name[0] = VPX_RC_GOLDEN_FRAME;
112 ref_frame.name[1] = VPX_RC_INVALID_REF_FRAME;
113 ref_frame.name[2] = VPX_RC_INVALID_REF_FRAME;
114 return ref_frame;
115 }
get_leaf_ref_frame(int count) const116 vpx_rc_ref_frame_t get_leaf_ref_frame(int count) const {
117 vpx_rc_ref_frame_t ref_frame;
118 ref_frame.index[0] = 0;
119 ref_frame.index[1] = 1;
120 ref_frame.index[2] = count > 2 ? 2 : -1;
121 ref_frame.name[0] = VPX_RC_GOLDEN_FRAME;
122 ref_frame.name[1] = VPX_RC_ALTREF_FRAME;
123 ref_frame.name[2] =
124 count > 2 ? VPX_RC_LAST_FRAME : VPX_RC_INVALID_REF_FRAME;
125 return ref_frame;
126 }
get_ovl_ref_frame() const127 vpx_rc_ref_frame_t get_ovl_ref_frame() const {
128 vpx_rc_ref_frame_t ref_frame;
129 ref_frame.index[0] = 1;
130 ref_frame.index[1] = -1;
131 ref_frame.index[2] = -1;
132 ref_frame.name[0] = VPX_RC_ALTREF_FRAME;
133 ref_frame.name[1] = VPX_RC_INVALID_REF_FRAME;
134 ref_frame.name[2] = VPX_RC_INVALID_REF_FRAME;
135 return ref_frame;
136 }
137
138 int current_gop_;
139 };
140
141 // Callbacks used in this test.
rc_test_create_model(void *,const vpx_rc_config_t *,vpx_rc_model_t * rate_ctrl_model_ptr)142 vpx_rc_status_t rc_test_create_model(
143 void * /*priv*/, const vpx_rc_config_t * /*ratectrl_config*/,
144 vpx_rc_model_t *rate_ctrl_model_ptr) {
145 std::unique_ptr<RateControllerForTest> test_controller(
146 new RateControllerForTest());
147 *rate_ctrl_model_ptr = test_controller.release();
148 return VPX_RC_OK;
149 }
150
rc_test_send_firstpass_stats(vpx_rc_model_t,const vpx_rc_firstpass_stats_t * first_pass_stats)151 vpx_rc_status_t rc_test_send_firstpass_stats(
152 vpx_rc_model_t /*rate_ctrl_model*/,
153 const vpx_rc_firstpass_stats_t *first_pass_stats) {
154 EXPECT_EQ(first_pass_stats->num_frames, kShowFrameCount);
155 for (int i = 0; i < first_pass_stats->num_frames; ++i) {
156 EXPECT_DOUBLE_EQ(first_pass_stats->frame_stats[i].frame, i);
157 }
158 return VPX_RC_OK;
159 }
160
rc_test_send_tpl_gop_stats(vpx_rc_model_t,const VpxTplGopStats * tpl_gop_stats)161 vpx_rc_status_t rc_test_send_tpl_gop_stats(
162 vpx_rc_model_t /*rate_ctrl_model*/, const VpxTplGopStats *tpl_gop_stats) {
163 EXPECT_GT(tpl_gop_stats->size, 0);
164
165 for (int i = 0; i < tpl_gop_stats->size; ++i) {
166 EXPECT_GT(tpl_gop_stats->frame_stats_list[i].num_blocks, 0);
167 }
168 return VPX_RC_OK;
169 }
170
rc_test_get_encodeframe_decision(vpx_rc_model_t rate_ctrl_model,const int frame_gop_index,vpx_rc_encodeframe_decision_t * frame_decision)171 vpx_rc_status_t rc_test_get_encodeframe_decision(
172 vpx_rc_model_t rate_ctrl_model, const int frame_gop_index,
173 vpx_rc_encodeframe_decision_t *frame_decision) {
174 RateControllerForTest *test_controller =
175 static_cast<RateControllerForTest *>(rate_ctrl_model);
176 frame_decision->q_index =
177 test_controller->CalculateFrameDecision(frame_gop_index);
178 return VPX_RC_OK;
179 }
180
rc_test_get_gop_decision(vpx_rc_model_t rate_ctrl_model,vpx_rc_gop_decision_t * gop_decision)181 vpx_rc_status_t rc_test_get_gop_decision(vpx_rc_model_t rate_ctrl_model,
182 vpx_rc_gop_decision_t *gop_decision) {
183 RateControllerForTest *test_controller =
184 static_cast<RateControllerForTest *>(rate_ctrl_model);
185 test_controller->StartNextGop();
186 *gop_decision = test_controller->GetCurrentGop();
187 return VPX_RC_OK;
188 }
189
rc_delete_model(vpx_rc_model_t rate_ctrl_model)190 vpx_rc_status_t rc_delete_model(vpx_rc_model_t rate_ctrl_model) {
191 RateControllerForTest *test_controller =
192 static_cast<RateControllerForTest *>(rate_ctrl_model);
193 delete test_controller;
194 return VPX_RC_OK;
195 }
196
197 class ExtRateCtrlTest : public ::libvpx_test::EncoderTest,
198 public ::testing::Test {
199 protected:
ExtRateCtrlTest()200 ExtRateCtrlTest()
201 : EncoderTest(&::libvpx_test::kVP9), received_show_frame_count_(0),
202 current_frame_qp_(0) {}
203
204 ~ExtRateCtrlTest() override = default;
205
SetUp()206 void SetUp() override {
207 InitializeConfig();
208 #if CONFIG_REALTIME_ONLY
209 SetMode(::libvpx_test::kRealTime);
210 #else
211 SetMode(::libvpx_test::kTwoPassGood);
212 #endif
213 }
214
PreEncodeFrameHook(::libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)215 void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
216 ::libvpx_test::Encoder *encoder) override {
217 if (video->frame() == 0) {
218 vpx_rc_funcs_t rc_funcs = {};
219 rc_funcs.rc_type = VPX_RC_GOP_QP;
220 rc_funcs.create_model = rc_test_create_model;
221 rc_funcs.send_firstpass_stats = rc_test_send_firstpass_stats;
222 rc_funcs.send_tpl_gop_stats = rc_test_send_tpl_gop_stats;
223 rc_funcs.get_gop_decision = rc_test_get_gop_decision;
224 rc_funcs.get_encodeframe_decision = rc_test_get_encodeframe_decision;
225 rc_funcs.delete_model = rc_delete_model;
226 encoder->Control(VP9E_SET_EXTERNAL_RATE_CONTROL, &rc_funcs);
227 }
228 }
229
230 #if CONFIG_VP9_DECODER
HandleDecodeResult(const vpx_codec_err_t res_dec,const::libvpx_test::VideoSource &,::libvpx_test::Decoder * decoder)231 bool HandleDecodeResult(const vpx_codec_err_t res_dec,
232 const ::libvpx_test::VideoSource & /*video*/,
233 ::libvpx_test::Decoder *decoder) override {
234 EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
235 decoder->Control(VPXD_GET_LAST_QUANTIZER, ¤t_frame_qp_);
236 return VPX_CODEC_OK == res_dec;
237 }
238
FramePktHook(const vpx_codec_cx_pkt_t * pkt)239 void FramePktHook(const vpx_codec_cx_pkt_t *pkt) override {
240 // We are not comparing current_frame_qp_ here because the encoder will
241 // pack ARF and the next show frame into one pkt. Therefore, we might
242 // receive two frames in one pkt. However, one thing we are sure is that
243 // each pkt will have just one show frame. Therefore, we can check if the
244 // received show frame count match the actual show frame count.
245 if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
246 ++received_show_frame_count_;
247 }
248 }
249 #endif // CONFIG_VP9_DECODER
250
251 int received_show_frame_count_;
252 int current_frame_qp_;
253 };
254
TEST_F(ExtRateCtrlTest,EncodeTest)255 TEST_F(ExtRateCtrlTest, EncodeTest) {
256 cfg_.rc_target_bitrate = 4000;
257 cfg_.g_lag_in_frames = 25;
258
259 std::unique_ptr<libvpx_test::VideoSource> video;
260 video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
261 "bus_352x288_420_f20_b8.yuv", VPX_IMG_FMT_I420, 352, 288, 30, 1, 0,
262 kShowFrameCount));
263
264 ASSERT_NE(video, nullptr);
265 ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
266 EXPECT_EQ(received_show_frame_count_, kShowFrameCount);
267 }
268
269 } // namespace
270