• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
14 #include "test/codec_factory.h"
15 #include "test/encode_test_driver.h"
16 #include "test/util.h"
17 #include "test/yuv_video_source.h"
18 #include "third_party/googletest/src/include/gtest/gtest.h"
19 #include "vpx/vpx_ext_ratectrl.h"
20 
21 namespace {
22 
23 constexpr int kModelMagicNumber = 51396;
24 constexpr uintptr_t PrivMagicNumber = 5566;
25 constexpr int kFrameNum = 5;
26 constexpr int kLosslessCodingIndex = 2;
27 
28 struct ToyRateCtrl {
29   int magic_number;
30   int coding_index;
31 };
32 
rc_create_model(void * priv,const vpx_rc_config_t * ratectrl_config,vpx_rc_model_t * rate_ctrl_model_pt)33 vpx_rc_status_t rc_create_model(void *priv,
34                                 const vpx_rc_config_t *ratectrl_config,
35                                 vpx_rc_model_t *rate_ctrl_model_pt) {
36   ToyRateCtrl *toy_rate_ctrl = new (std::nothrow) ToyRateCtrl;
37   EXPECT_NE(toy_rate_ctrl, nullptr);
38   toy_rate_ctrl->magic_number = kModelMagicNumber;
39   toy_rate_ctrl->coding_index = -1;
40   *rate_ctrl_model_pt = toy_rate_ctrl;
41   EXPECT_EQ(priv, reinterpret_cast<void *>(PrivMagicNumber));
42   EXPECT_EQ(ratectrl_config->frame_width, 352);
43   EXPECT_EQ(ratectrl_config->frame_height, 288);
44   EXPECT_EQ(ratectrl_config->show_frame_count, kFrameNum);
45   EXPECT_EQ(ratectrl_config->target_bitrate_kbps, 24000);
46   EXPECT_EQ(ratectrl_config->frame_rate_num, 30);
47   EXPECT_EQ(ratectrl_config->frame_rate_den, 1);
48   return VPX_RC_OK;
49 }
50 
rc_send_firstpass_stats(vpx_rc_model_t rate_ctrl_model,const vpx_rc_firstpass_stats_t * first_pass_stats)51 vpx_rc_status_t rc_send_firstpass_stats(
52     vpx_rc_model_t rate_ctrl_model,
53     const vpx_rc_firstpass_stats_t *first_pass_stats) {
54   const ToyRateCtrl *toy_rate_ctrl =
55       static_cast<ToyRateCtrl *>(rate_ctrl_model);
56   EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
57   EXPECT_EQ(first_pass_stats->num_frames, kFrameNum);
58   for (int i = 0; i < first_pass_stats->num_frames; ++i) {
59     EXPECT_DOUBLE_EQ(first_pass_stats->frame_stats[i].frame, i);
60   }
61   return VPX_RC_OK;
62 }
63 
rc_get_encodeframe_decision(vpx_rc_model_t rate_ctrl_model,const vpx_rc_encodeframe_info_t * encode_frame_info,vpx_rc_encodeframe_decision_t * frame_decision)64 vpx_rc_status_t rc_get_encodeframe_decision(
65     vpx_rc_model_t rate_ctrl_model,
66     const vpx_rc_encodeframe_info_t *encode_frame_info,
67     vpx_rc_encodeframe_decision_t *frame_decision) {
68   ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
69   toy_rate_ctrl->coding_index += 1;
70 
71   EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
72 
73   EXPECT_LT(encode_frame_info->show_index, kFrameNum);
74   EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
75 
76   if (encode_frame_info->coding_index == 0) {
77     EXPECT_EQ(encode_frame_info->show_index, 0);
78     EXPECT_EQ(encode_frame_info->gop_index, 0);
79     EXPECT_EQ(encode_frame_info->frame_type, 0 /*kFrameTypeKey*/);
80     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
81               0);  // kRefFrameTypeLast
82     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
83               0);  // kRefFrameTypePast
84     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
85               0);  // kRefFrameTypeFuture
86   }
87 
88   if (encode_frame_info->coding_index == 1) {
89     EXPECT_EQ(encode_frame_info->show_index, 4);
90     EXPECT_EQ(encode_frame_info->gop_index, 1);
91     EXPECT_EQ(encode_frame_info->frame_type, 2 /*kFrameTypeAltRef*/);
92     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
93               1);  // kRefFrameTypeLast
94     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
95               0);  // kRefFrameTypePast
96     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
97               0);  // kRefFrameTypeFuture
98     EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
99               0);  // kRefFrameTypeLast
100   }
101 
102   if (encode_frame_info->coding_index >= 2 &&
103       encode_frame_info->coding_index < 5) {
104     // In the first group of pictures, coding_index and gop_index are equal.
105     EXPECT_EQ(encode_frame_info->gop_index, encode_frame_info->coding_index);
106     EXPECT_EQ(encode_frame_info->frame_type, 1 /*kFrameTypeInter*/);
107   }
108 
109   if (encode_frame_info->coding_index == 5) {
110     EXPECT_EQ(encode_frame_info->show_index, 4);
111     EXPECT_EQ(encode_frame_info->gop_index, 0);
112     EXPECT_EQ(encode_frame_info->frame_type, 3 /*kFrameTypeOverlay*/);
113     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
114               1);  // kRefFrameTypeLast
115     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[1],
116               1);  // kRefFrameTypePast
117     EXPECT_EQ(encode_frame_info->ref_frame_valid_list[2],
118               1);  // kRefFrameTypeFuture
119     EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[0],
120               4);  // kRefFrameTypeLast
121     EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[1],
122               0);  // kRefFrameTypePast
123     EXPECT_EQ(encode_frame_info->ref_frame_coding_indexes[2],
124               1);  // kRefFrameTypeFuture
125   }
126   if (encode_frame_info->coding_index == kLosslessCodingIndex) {
127     // We should get sse == 0 at rc_update_encodeframe_result()
128     frame_decision->q_index = 0;
129   } else {
130     frame_decision->q_index = 100;
131   }
132   frame_decision->max_frame_size = 0;
133   return VPX_RC_OK;
134 }
135 
rc_update_encodeframe_result(vpx_rc_model_t rate_ctrl_model,const vpx_rc_encodeframe_result_t * encode_frame_result)136 vpx_rc_status_t rc_update_encodeframe_result(
137     vpx_rc_model_t rate_ctrl_model,
138     const vpx_rc_encodeframe_result_t *encode_frame_result) {
139   const ToyRateCtrl *toy_rate_ctrl =
140       static_cast<ToyRateCtrl *>(rate_ctrl_model);
141   EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
142 
143   const int64_t ref_pixel_count = 352 * 288 * 3 / 2;
144   EXPECT_EQ(encode_frame_result->pixel_count, ref_pixel_count);
145   if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
146     EXPECT_EQ(encode_frame_result->sse, 0);
147   }
148   if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
149     EXPECT_EQ(encode_frame_result->actual_encoding_qindex, 0);
150   } else {
151     EXPECT_EQ(encode_frame_result->actual_encoding_qindex, 100);
152   }
153   return VPX_RC_OK;
154 }
155 
rc_delete_model(vpx_rc_model_t rate_ctrl_model)156 vpx_rc_status_t rc_delete_model(vpx_rc_model_t rate_ctrl_model) {
157   ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
158   EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
159   delete toy_rate_ctrl;
160   return VPX_RC_OK;
161 }
162 
163 class ExtRateCtrlTest : public ::libvpx_test::EncoderTest,
164                         public ::testing::Test {
165  protected:
ExtRateCtrlTest()166   ExtRateCtrlTest() : EncoderTest(&::libvpx_test::kVP9) {}
167 
168   ~ExtRateCtrlTest() override = default;
169 
SetUp()170   void SetUp() override {
171     InitializeConfig();
172     SetMode(::libvpx_test::kTwoPassGood);
173   }
174 
PreEncodeFrameHook(::libvpx_test::VideoSource * video,::libvpx_test::Encoder * encoder)175   void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
176                           ::libvpx_test::Encoder *encoder) override {
177     if (video->frame() == 0) {
178       vpx_rc_funcs_t rc_funcs;
179       rc_funcs.create_model = rc_create_model;
180       rc_funcs.send_firstpass_stats = rc_send_firstpass_stats;
181       rc_funcs.get_encodeframe_decision = rc_get_encodeframe_decision;
182       rc_funcs.update_encodeframe_result = rc_update_encodeframe_result;
183       rc_funcs.delete_model = rc_delete_model;
184       rc_funcs.priv = reinterpret_cast<void *>(PrivMagicNumber);
185       encoder->Control(VP9E_SET_EXTERNAL_RATE_CONTROL, &rc_funcs);
186     }
187   }
188 };
189 
TEST_F(ExtRateCtrlTest,EncodeTest)190 TEST_F(ExtRateCtrlTest, EncodeTest) {
191   cfg_.rc_target_bitrate = 24000;
192 
193   std::unique_ptr<libvpx_test::VideoSource> video;
194   video.reset(new (std::nothrow) libvpx_test::YUVVideoSource(
195       "bus_352x288_420_f20_b8.yuv", VPX_IMG_FMT_I420, 352, 288, 30, 1, 0,
196       kFrameNum));
197 
198   ASSERT_NE(video.get(), nullptr);
199   ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
200 }
201 
202 }  // namespace
203