xref: /aosp_15_r20/external/libvpx/test/vp9_ext_ratectrl_test.cc (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
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, &current_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