1 /*
2 * Copyright (c) 2018 The WebRTC 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 <string>
12
13 #include "api/test/video/function_video_encoder_factory.h"
14 #include "media/engine/internal_encoder_factory.h"
15 #include "modules/video_coding/codecs/h264/include/h264.h"
16 #include "modules/video_coding/codecs/vp8/include/vp8.h"
17 #include "modules/video_coding/codecs/vp9/include/vp9.h"
18 #include "test/call_test.h"
19 #include "test/field_trial.h"
20 #include "test/frame_generator_capturer.h"
21
22 namespace webrtc {
23 namespace {
24 constexpr int kWidth = 1280;
25 constexpr int kHeight = 720;
26 constexpr int kLowStartBps = 100000;
27 constexpr int kHighStartBps = 600000;
28 constexpr size_t kTimeoutMs = 10000; // Some tests are expected to time out.
29
SetEncoderSpecific(VideoEncoderConfig * encoder_config,VideoCodecType type,bool automatic_resize,bool frame_dropping)30 void SetEncoderSpecific(VideoEncoderConfig* encoder_config,
31 VideoCodecType type,
32 bool automatic_resize,
33 bool frame_dropping) {
34 if (type == kVideoCodecVP8) {
35 VideoCodecVP8 vp8 = VideoEncoder::GetDefaultVp8Settings();
36 vp8.automaticResizeOn = automatic_resize;
37 vp8.frameDroppingOn = frame_dropping;
38 encoder_config->encoder_specific_settings = new rtc::RefCountedObject<
39 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8);
40 } else if (type == kVideoCodecVP9) {
41 VideoCodecVP9 vp9 = VideoEncoder::GetDefaultVp9Settings();
42 vp9.automaticResizeOn = automatic_resize;
43 vp9.frameDroppingOn = frame_dropping;
44 encoder_config->encoder_specific_settings = new rtc::RefCountedObject<
45 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9);
46 } else if (type == kVideoCodecH264) {
47 VideoCodecH264 h264 = VideoEncoder::GetDefaultH264Settings();
48 h264.frameDroppingOn = frame_dropping;
49 encoder_config->encoder_specific_settings = new rtc::RefCountedObject<
50 VideoEncoderConfig::H264EncoderSpecificSettings>(h264);
51 }
52 }
53 } // namespace
54
55 class QualityScalingTest : public test::CallTest {
56 protected:
57 void RunTest(VideoEncoderFactory* encoder_factory,
58 const std::string& payload_name,
59 int start_bps,
60 bool automatic_resize,
61 bool frame_dropping,
62 bool expect_adaptation);
63
64 const std::string kPrefix = "WebRTC-Video-QualityScaling/Enabled-";
65 const std::string kEnd = ",0,0,0.9995,0.9999,1/";
66 };
67
RunTest(VideoEncoderFactory * encoder_factory,const std::string & payload_name,int start_bps,bool automatic_resize,bool frame_dropping,bool expect_adaptation)68 void QualityScalingTest::RunTest(VideoEncoderFactory* encoder_factory,
69 const std::string& payload_name,
70 int start_bps,
71 bool automatic_resize,
72 bool frame_dropping,
73 bool expect_adaptation) {
74 class ScalingObserver
75 : public test::SendTest,
76 public test::FrameGeneratorCapturer::SinkWantsObserver {
77 public:
78 ScalingObserver(VideoEncoderFactory* encoder_factory,
79 const std::string& payload_name,
80 int start_bps,
81 bool automatic_resize,
82 bool frame_dropping,
83 bool expect_adaptation)
84 : SendTest(expect_adaptation ? kDefaultTimeoutMs : kTimeoutMs),
85 encoder_factory_(encoder_factory),
86 payload_name_(payload_name),
87 start_bps_(start_bps),
88 automatic_resize_(automatic_resize),
89 frame_dropping_(frame_dropping),
90 expect_adaptation_(expect_adaptation) {}
91
92 private:
93 void OnFrameGeneratorCapturerCreated(
94 test::FrameGeneratorCapturer* frame_generator_capturer) override {
95 frame_generator_capturer->SetSinkWantsObserver(this);
96 // Set initial resolution.
97 frame_generator_capturer->ChangeResolution(kWidth, kHeight);
98 }
99
100 // Called when FrameGeneratorCapturer::AddOrUpdateSink is called.
101 void OnSinkWantsChanged(rtc::VideoSinkInterface<VideoFrame>* sink,
102 const rtc::VideoSinkWants& wants) override {
103 if (wants.max_pixel_count < kWidth * kHeight)
104 observation_complete_.Set();
105 }
106 void ModifySenderBitrateConfig(
107 BitrateConstraints* bitrate_config) override {
108 bitrate_config->start_bitrate_bps = start_bps_;
109 }
110
111 void ModifyVideoConfigs(
112 VideoSendStream::Config* send_config,
113 std::vector<VideoReceiveStream::Config>* receive_configs,
114 VideoEncoderConfig* encoder_config) override {
115 send_config->encoder_settings.encoder_factory = encoder_factory_;
116 send_config->rtp.payload_name = payload_name_;
117 send_config->rtp.payload_type = kVideoSendPayloadType;
118 const VideoCodecType codec_type = PayloadStringToCodecType(payload_name_);
119 encoder_config->codec_type = codec_type;
120 encoder_config->max_bitrate_bps = start_bps_;
121 SetEncoderSpecific(encoder_config, codec_type, automatic_resize_,
122 frame_dropping_);
123 }
124
125 void PerformTest() override {
126 EXPECT_EQ(expect_adaptation_, Wait())
127 << "Timed out while waiting for a scale down.";
128 }
129
130 VideoEncoderFactory* const encoder_factory_;
131 const std::string payload_name_;
132 const int start_bps_;
133 const bool automatic_resize_;
134 const bool frame_dropping_;
135 const bool expect_adaptation_;
136 } test(encoder_factory, payload_name, start_bps, automatic_resize,
137 frame_dropping, expect_adaptation);
138
139 RunBaseTest(&test);
140 }
141
TEST_F(QualityScalingTest,AdaptsDownForHighQp_Vp8)142 TEST_F(QualityScalingTest, AdaptsDownForHighQp_Vp8) {
143 // VP8 QP thresholds, low:1, high:1 -> high QP.
144 test::ScopedFieldTrials field_trials(kPrefix + "1,1,0,0,0,0" + kEnd);
145
146 // QualityScaler enabled.
147 const bool kAutomaticResize = true;
148 const bool kFrameDropping = true;
149 const bool kExpectAdapt = true;
150
151 test::FunctionVideoEncoderFactory encoder_factory(
152 []() { return VP8Encoder::Create(); });
153 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
154 kFrameDropping, kExpectAdapt);
155 }
156
TEST_F(QualityScalingTest,NoAdaptDownForHighQpWithResizeOff_Vp8)157 TEST_F(QualityScalingTest, NoAdaptDownForHighQpWithResizeOff_Vp8) {
158 // VP8 QP thresholds, low:1, high:1 -> high QP.
159 test::ScopedFieldTrials field_trials(kPrefix + "1,1,0,0,0,0" + kEnd);
160
161 // QualityScaler disabled.
162 const bool kAutomaticResize = false;
163 const bool kFrameDropping = true;
164 const bool kExpectAdapt = false;
165
166 test::FunctionVideoEncoderFactory encoder_factory(
167 []() { return VP8Encoder::Create(); });
168 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
169 kFrameDropping, kExpectAdapt);
170 }
171
172 // TODO(bugs.webrtc.org/10388): Fix and re-enable.
TEST_F(QualityScalingTest,DISABLED_NoAdaptDownForHighQpWithFrameDroppingOff_Vp8)173 TEST_F(QualityScalingTest,
174 DISABLED_NoAdaptDownForHighQpWithFrameDroppingOff_Vp8) {
175 // VP8 QP thresholds, low:1, high:1 -> high QP.
176 test::ScopedFieldTrials field_trials(kPrefix + "1,1,0,0,0,0" + kEnd);
177
178 // QualityScaler disabled.
179 const bool kAutomaticResize = true;
180 const bool kFrameDropping = false;
181 const bool kExpectAdapt = false;
182
183 test::FunctionVideoEncoderFactory encoder_factory(
184 []() { return VP8Encoder::Create(); });
185 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
186 kFrameDropping, kExpectAdapt);
187 }
188
TEST_F(QualityScalingTest,NoAdaptDownForNormalQp_Vp8)189 TEST_F(QualityScalingTest, NoAdaptDownForNormalQp_Vp8) {
190 // VP8 QP thresholds, low:1, high:127 -> normal QP.
191 test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
192
193 // QualityScaler enabled.
194 const bool kAutomaticResize = true;
195 const bool kFrameDropping = true;
196 const bool kExpectAdapt = false;
197
198 test::FunctionVideoEncoderFactory encoder_factory(
199 []() { return VP8Encoder::Create(); });
200 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
201 kFrameDropping, kExpectAdapt);
202 }
203
TEST_F(QualityScalingTest,AdaptsDownForLowStartBitrate)204 TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate) {
205 // VP8 QP thresholds, low:1, high:127 -> normal QP.
206 test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
207
208 // QualityScaler enabled.
209 const bool kAutomaticResize = true;
210 const bool kFrameDropping = true;
211 const bool kExpectAdapt = true;
212
213 test::FunctionVideoEncoderFactory encoder_factory(
214 []() { return VP8Encoder::Create(); });
215 RunTest(&encoder_factory, "VP8", kLowStartBps, kAutomaticResize,
216 kFrameDropping, kExpectAdapt);
217 }
218
TEST_F(QualityScalingTest,NoAdaptDownForLowStartBitrateWithScalingOff)219 TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateWithScalingOff) {
220 // VP8 QP thresholds, low:1, high:127 -> normal QP.
221 test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
222
223 // QualityScaler disabled.
224 const bool kAutomaticResize = false;
225 const bool kFrameDropping = true;
226 const bool kExpectAdapt = false;
227
228 test::FunctionVideoEncoderFactory encoder_factory(
229 []() { return VP8Encoder::Create(); });
230 RunTest(&encoder_factory, "VP8", kLowStartBps, kAutomaticResize,
231 kFrameDropping, kExpectAdapt);
232 }
233
TEST_F(QualityScalingTest,NoAdaptDownForHighQp_Vp9)234 TEST_F(QualityScalingTest, NoAdaptDownForHighQp_Vp9) {
235 // VP9 QP thresholds, low:1, high:1 -> high QP.
236 test::ScopedFieldTrials field_trials(kPrefix + "0,0,1,1,0,0" + kEnd +
237 "WebRTC-VP9QualityScaler/Disabled/");
238
239 // QualityScaler always disabled.
240 const bool kAutomaticResize = true;
241 const bool kFrameDropping = true;
242 const bool kExpectAdapt = false;
243
244 test::FunctionVideoEncoderFactory encoder_factory(
245 []() { return VP9Encoder::Create(); });
246 RunTest(&encoder_factory, "VP9", kHighStartBps, kAutomaticResize,
247 kFrameDropping, kExpectAdapt);
248 }
249
250 #if defined(WEBRTC_USE_H264)
TEST_F(QualityScalingTest,AdaptsDownForHighQp_H264)251 TEST_F(QualityScalingTest, AdaptsDownForHighQp_H264) {
252 // H264 QP thresholds, low:1, high:1 -> high QP.
253 test::ScopedFieldTrials field_trials(kPrefix + "0,0,0,0,1,1" + kEnd);
254
255 // QualityScaler always enabled.
256 const bool kAutomaticResize = false;
257 const bool kFrameDropping = false;
258 const bool kExpectAdapt = true;
259
260 test::FunctionVideoEncoderFactory encoder_factory(
261 []() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
262 RunTest(&encoder_factory, "H264", kHighStartBps, kAutomaticResize,
263 kFrameDropping, kExpectAdapt);
264 }
265 #endif // defined(WEBRTC_USE_H264)
266
267 } // namespace webrtc
268