2 * Copyright (c) 2020 The WebM project authors. All Rights Reserved.
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.
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"
23 constexpr int kModelMagicNumber = 51396;
24 constexpr uintptr_t PrivMagicNumber = 5566;
25 constexpr int kFrameNum = 5;
26 constexpr int kLosslessCodingIndex = 2;
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);
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);
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;
71 EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
73 EXPECT_LT(encode_frame_info->show_index, kFrameNum);
74 EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
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
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
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*/);
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
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;
130 frame_decision->q_index = 100;
132 frame_decision->max_frame_size = 0;
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);
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);
148 if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
149 EXPECT_EQ(encode_frame_result->actual_encoding_qindex, 0);
151 EXPECT_EQ(encode_frame_result->actual_encoding_qindex, 100);
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;
163 class ExtRateCtrlTest : public ::libvpx_test::EncoderTest,
164 public ::testing::Test {
166 ExtRateCtrlTest() : EncoderTest(&::libvpx_test::kVP9) {}
168 ~ExtRateCtrlTest() override = default;
170 void SetUp() override {
172 SetMode(::libvpx_test::kTwoPassGood);
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);
190 TEST_F(ExtRateCtrlTest, EncodeTest) {
191 cfg_.rc_target_bitrate = 24000;
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,
198 ASSERT_NE(video.get(), nullptr);
199 ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));