blob: bb12edcc82c2ac6f0757b6c139f7981dec904399 [file] [log] [blame]
Åsa Persson2027b662018-05-02 18:08:06 +02001/*
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 "media/engine/internalencoderfactory.h"
14#include "modules/video_coding/codecs/h264/include/h264.h"
15#include "modules/video_coding/codecs/vp8/include/vp8.h"
16#include "modules/video_coding/codecs/vp9/include/vp9.h"
17#include "test/call_test.h"
18#include "test/field_trial.h"
19#include "test/frame_generator_capturer.h"
20#include "test/function_video_encoder_factory.h"
21
22namespace webrtc {
23namespace {
24constexpr int kWidth = 1280;
25constexpr int kHeight = 720;
26constexpr int kLowStartBps = 100000;
27constexpr int kHighStartBps = 600000;
28constexpr size_t kTimeoutMs = 10000; // Some tests are expected to time out.
29
30void 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
55class 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
68void 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 {
Mirko Bonadei948b7e32018-08-14 07:23:21 +0000103 EXPECT_LT(wants.max_pixel_count, kWidth * kHeight) << "Not a downscale.";
104 observation_complete_.Set();
Åsa Persson2027b662018-05-02 18:08:06 +0200105 }
Sebastian Jansson72582242018-07-13 13:19:42 +0200106 void ModifySenderCallConfig(Call::Config* config) override {
107 config->bitrate_config.start_bitrate_bps = start_bps_;
Åsa Persson2027b662018-05-02 18:08:06 +0200108 }
109
110 void ModifyVideoConfigs(
111 VideoSendStream::Config* send_config,
112 std::vector<VideoReceiveStream::Config>* receive_configs,
113 VideoEncoderConfig* encoder_config) override {
114 send_config->encoder_settings.encoder_factory = encoder_factory_;
115 send_config->rtp.payload_name = payload_name_;
116 send_config->rtp.payload_type = kVideoSendPayloadType;
117 const VideoCodecType codec_type = PayloadStringToCodecType(payload_name_);
118 encoder_config->codec_type = codec_type;
119 encoder_config->max_bitrate_bps = start_bps_;
120 SetEncoderSpecific(encoder_config, codec_type, automatic_resize_,
121 frame_dropping_);
122 }
123
124 void PerformTest() override {
125 EXPECT_EQ(expect_adaptation_, Wait())
126 << "Timed out while waiting for a scale down.";
127 }
128
129 VideoEncoderFactory* const encoder_factory_;
130 const std::string payload_name_;
131 const int start_bps_;
132 const bool automatic_resize_;
133 const bool frame_dropping_;
134 const bool expect_adaptation_;
135 } test(encoder_factory, payload_name, start_bps, automatic_resize,
136 frame_dropping, expect_adaptation);
137
138 RunBaseTest(&test);
139}
140
141TEST_F(QualityScalingTest, AdaptsDownForHighQp_Vp8) {
142 // VP8 QP thresholds, low:1, high:1 -> high QP.
143 test::ScopedFieldTrials field_trials(kPrefix + "1,1,0,0,0,0" + kEnd);
144
145 // QualityScaler enabled.
146 const bool kAutomaticResize = true;
147 const bool kFrameDropping = true;
148 const bool kExpectAdapt = true;
149
150 test::FunctionVideoEncoderFactory encoder_factory(
151 []() { return VP8Encoder::Create(); });
152 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
153 kFrameDropping, kExpectAdapt);
154}
155
156TEST_F(QualityScalingTest, NoAdaptDownForHighQpWithResizeOff_Vp8) {
157 // VP8 QP thresholds, low:1, high:1 -> high QP.
158 test::ScopedFieldTrials field_trials(kPrefix + "1,1,0,0,0,0" + kEnd);
159
160 // QualityScaler disabled.
161 const bool kAutomaticResize = false;
162 const bool kFrameDropping = true;
163 const bool kExpectAdapt = false;
164
165 test::FunctionVideoEncoderFactory encoder_factory(
166 []() { return VP8Encoder::Create(); });
167 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
168 kFrameDropping, kExpectAdapt);
169}
170
171TEST_F(QualityScalingTest, NoAdaptDownForHighQpWithFrameDroppingOff_Vp8) {
172 // VP8 QP thresholds, low:1, high:1 -> high QP.
173 test::ScopedFieldTrials field_trials(kPrefix + "1,1,0,0,0,0" + kEnd);
174
175 // QualityScaler disabled.
176 const bool kAutomaticResize = true;
177 const bool kFrameDropping = false;
178 const bool kExpectAdapt = false;
179
180 test::FunctionVideoEncoderFactory encoder_factory(
181 []() { return VP8Encoder::Create(); });
182 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
183 kFrameDropping, kExpectAdapt);
184}
185
186TEST_F(QualityScalingTest, NoAdaptDownForNormalQp_Vp8) {
187 // VP8 QP thresholds, low:1, high:127 -> normal QP.
188 test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
189
190 // QualityScaler enabled.
191 const bool kAutomaticResize = true;
192 const bool kFrameDropping = true;
193 const bool kExpectAdapt = false;
194
195 test::FunctionVideoEncoderFactory encoder_factory(
196 []() { return VP8Encoder::Create(); });
197 RunTest(&encoder_factory, "VP8", kHighStartBps, kAutomaticResize,
198 kFrameDropping, kExpectAdapt);
199}
200
201TEST_F(QualityScalingTest, AdaptsDownForLowStartBitrate) {
202 // VP8 QP thresholds, low:1, high:127 -> normal QP.
203 test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
204
205 // QualityScaler enabled.
206 const bool kAutomaticResize = true;
207 const bool kFrameDropping = true;
208 const bool kExpectAdapt = true;
209
210 test::FunctionVideoEncoderFactory encoder_factory(
211 []() { return VP8Encoder::Create(); });
212 RunTest(&encoder_factory, "VP8", kLowStartBps, kAutomaticResize,
213 kFrameDropping, kExpectAdapt);
214}
215
216TEST_F(QualityScalingTest, NoAdaptDownForLowStartBitrateWithScalingOff) {
217 // VP8 QP thresholds, low:1, high:127 -> normal QP.
218 test::ScopedFieldTrials field_trials(kPrefix + "1,127,0,0,0,0" + kEnd);
219
220 // QualityScaler disabled.
221 const bool kAutomaticResize = false;
222 const bool kFrameDropping = true;
223 const bool kExpectAdapt = false;
224
225 test::FunctionVideoEncoderFactory encoder_factory(
226 []() { return VP8Encoder::Create(); });
227 RunTest(&encoder_factory, "VP8", kLowStartBps, kAutomaticResize,
228 kFrameDropping, kExpectAdapt);
229}
230
231TEST_F(QualityScalingTest, NoAdaptDownForHighQp_Vp9) {
232 // VP9 QP thresholds, low:1, high:1 -> high QP.
233 test::ScopedFieldTrials field_trials(kPrefix + "0,0,1,1,0,0" + kEnd);
234
235 // QualityScaler always disabled.
236 const bool kAutomaticResize = true;
237 const bool kFrameDropping = true;
238 const bool kExpectAdapt = false;
239
240 test::FunctionVideoEncoderFactory encoder_factory(
241 []() { return VP9Encoder::Create(); });
242 RunTest(&encoder_factory, "VP9", kHighStartBps, kAutomaticResize,
243 kFrameDropping, kExpectAdapt);
244}
245
246#if defined(WEBRTC_USE_H264)
247TEST_F(QualityScalingTest, AdaptsDownForHighQp_H264) {
248 // H264 QP thresholds, low:1, high:1 -> high QP.
249 test::ScopedFieldTrials field_trials(kPrefix + "0,0,0,0,1,1" + kEnd);
250
251 // QualityScaler always enabled.
252 const bool kAutomaticResize = false;
253 const bool kFrameDropping = false;
254 const bool kExpectAdapt = true;
255
256 test::FunctionVideoEncoderFactory encoder_factory(
257 []() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
258 RunTest(&encoder_factory, "H264", kHighStartBps, kAutomaticResize,
259 kFrameDropping, kExpectAdapt);
260}
261#endif // defined(WEBRTC_USE_H264)
262
263} // namespace webrtc