1 /*
2 * Copyright 2021 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 "video/adaptation/bitrate_constraint.h"
12
13 #include <utility>
14 #include <vector>
15
16 #include "api/video_codecs/scalability_mode.h"
17 #include "api/video_codecs/video_encoder.h"
18 #include "call/adaptation/encoder_settings.h"
19 #include "call/adaptation/test/fake_frame_rate_provider.h"
20 #include "call/adaptation/video_source_restrictions.h"
21 #include "call/adaptation/video_stream_input_state_provider.h"
22 #include "test/gtest.h"
23
24 namespace webrtc {
25
26 namespace {
27 const VideoSourceRestrictions k180p{/*max_pixels_per_frame=*/320 * 180,
28 /*target_pixels_per_frame=*/320 * 180,
29 /*max_frame_rate=*/30};
30 const VideoSourceRestrictions k360p{/*max_pixels_per_frame=*/640 * 360,
31 /*target_pixels_per_frame=*/640 * 360,
32 /*max_frame_rate=*/30};
33 const VideoSourceRestrictions k720p{/*max_pixels_per_frame=*/1280 * 720,
34 /*target_pixels_per_frame=*/1280 * 720,
35 /*max_frame_rate=*/30};
36
37 struct TestParams {
38 bool active;
39 absl::optional<ScalabilityMode> scalability_mode;
40 };
41
FillCodecConfig(VideoCodec * video_codec,VideoEncoderConfig * encoder_config,int width_px,int height_px,const std::vector<TestParams> & params,bool svc)42 void FillCodecConfig(VideoCodec* video_codec,
43 VideoEncoderConfig* encoder_config,
44 int width_px,
45 int height_px,
46 const std::vector<TestParams>& params,
47 bool svc) {
48 size_t num_layers = params.size();
49 video_codec->codecType = kVideoCodecVP8;
50 video_codec->numberOfSimulcastStreams = num_layers;
51
52 encoder_config->number_of_streams = svc ? 1 : num_layers;
53 encoder_config->simulcast_layers.resize(num_layers);
54
55 for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
56 int layer_width_px = width_px >> (num_layers - 1 - layer_idx);
57 int layer_height_px = height_px >> (num_layers - 1 - layer_idx);
58
59 if (params[layer_idx].scalability_mode)
60 video_codec->SetScalabilityMode(*params[layer_idx].scalability_mode);
61 video_codec->simulcastStream[layer_idx].active = params[layer_idx].active;
62 video_codec->simulcastStream[layer_idx].width = layer_width_px;
63 video_codec->simulcastStream[layer_idx].height = layer_height_px;
64
65 encoder_config->simulcast_layers[layer_idx].scalability_mode =
66 params[layer_idx].scalability_mode;
67 encoder_config->simulcast_layers[layer_idx].active =
68 params[layer_idx].active;
69 encoder_config->simulcast_layers[layer_idx].width = layer_width_px;
70 encoder_config->simulcast_layers[layer_idx].height = layer_height_px;
71 }
72 }
73
74 constexpr int kStartBitrateBps360p = 500000;
75 constexpr int kStartBitrateBps720p = 1000000;
76
MakeEncoderInfo()77 VideoEncoder::EncoderInfo MakeEncoderInfo() {
78 VideoEncoder::EncoderInfo encoder_info;
79 encoder_info.resolution_bitrate_limits = {
80 {640 * 360, kStartBitrateBps360p, 0, 5000000},
81 {1280 * 720, kStartBitrateBps720p, 0, 5000000},
82 {1920 * 1080, 2000000, 0, 5000000}};
83 return encoder_info;
84 }
85
86 } // namespace
87
88 class BitrateConstraintTest : public ::testing::Test {
89 public:
BitrateConstraintTest()90 BitrateConstraintTest()
91 : frame_rate_provider_(), input_state_provider_(&frame_rate_provider_) {}
92
93 protected:
OnEncoderSettingsUpdated(int width_px,int height_px,const std::vector<TestParams> & params,bool svc=false)94 void OnEncoderSettingsUpdated(int width_px,
95 int height_px,
96 const std::vector<TestParams>& params,
97 bool svc = false) {
98 VideoCodec video_codec;
99 VideoEncoderConfig encoder_config;
100 FillCodecConfig(&video_codec, &encoder_config, width_px, height_px, params,
101 svc);
102
103 EncoderSettings encoder_settings(MakeEncoderInfo(),
104 std::move(encoder_config), video_codec);
105 bitrate_constraint_.OnEncoderSettingsUpdated(encoder_settings);
106 input_state_provider_.OnEncoderSettingsChanged(encoder_settings);
107 }
108
109 FakeFrameRateProvider frame_rate_provider_;
110 VideoStreamInputStateProvider input_state_provider_;
111 BitrateConstraint bitrate_constraint_;
112 };
113
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastIfBitrateIsEnough)114 TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSinglecastIfBitrateIsEnough) {
115 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
116 {{.active = true}});
117
118 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
119
120 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
121 input_state_provider_.InputState(),
122 /*restrictions_before=*/k360p,
123 /*restrictions_after=*/k720p));
124 }
125
TEST_F(BitrateConstraintTest,AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnough)126 TEST_F(BitrateConstraintTest,
127 AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnough) {
128 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
129 {{.active = true}});
130
131 // 1 bps less than needed for 720p.
132 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
133
134 EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
135 input_state_provider_.InputState(),
136 /*restrictions_before=*/k360p,
137 /*restrictions_after=*/k720p));
138 }
139
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastIfBitrateIsEnoughForOneSpatialLayer)140 TEST_F(BitrateConstraintTest,
141 AdaptUpAllowedAtSinglecastIfBitrateIsEnoughForOneSpatialLayer) {
142 OnEncoderSettingsUpdated(
143 /*width_px=*/640, /*height_px=*/360,
144 {{.active = true, .scalability_mode = ScalabilityMode::kL1T1}});
145
146 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
147
148 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
149 input_state_provider_.InputState(),
150 /*restrictions_before=*/k360p,
151 /*restrictions_after=*/k720p));
152 }
153
TEST_F(BitrateConstraintTest,AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnoughForOneSpatialLayer)154 TEST_F(BitrateConstraintTest,
155 AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnoughForOneSpatialLayer) {
156 OnEncoderSettingsUpdated(
157 /*width_px=*/640, /*height_px=*/360,
158 {{.active = true, .scalability_mode = ScalabilityMode::kL1T1}});
159
160 // 1 bps less than needed for 720p.
161 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
162
163 EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
164 input_state_provider_.InputState(),
165 /*restrictions_before=*/k360p,
166 /*restrictions_after=*/k720p));
167 }
168
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastIfBitrateIsNotEnoughForMultipleSpatialLayers)169 TEST_F(BitrateConstraintTest,
170 AdaptUpAllowedAtSinglecastIfBitrateIsNotEnoughForMultipleSpatialLayers) {
171 OnEncoderSettingsUpdated(
172 /*width_px=*/640, /*height_px=*/360,
173 {{.active = true, .scalability_mode = ScalabilityMode::kL2T1}});
174
175 // 1 bps less than needed for 720p.
176 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
177
178 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
179 input_state_provider_.InputState(),
180 /*restrictions_before=*/k360p,
181 /*restrictions_after=*/k720p));
182 }
183
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastUpperLayerActiveIfBitrateIsEnough)184 TEST_F(BitrateConstraintTest,
185 AdaptUpAllowedAtSinglecastUpperLayerActiveIfBitrateIsEnough) {
186 OnEncoderSettingsUpdated(
187 /*width_px=*/640, /*height_px=*/360,
188 {{.active = false, .scalability_mode = ScalabilityMode::kL2T1},
189 {.active = true}});
190
191 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
192
193 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
194 input_state_provider_.InputState(),
195 /*restrictions_before=*/k360p,
196 /*restrictions_after=*/k720p));
197 }
198
TEST_F(BitrateConstraintTest,AdaptUpDisallowedAtSinglecastUpperLayerActiveIfBitrateIsNotEnough)199 TEST_F(BitrateConstraintTest,
200 AdaptUpDisallowedAtSinglecastUpperLayerActiveIfBitrateIsNotEnough) {
201 OnEncoderSettingsUpdated(
202 /*width_px=*/640, /*height_px=*/360,
203 {{.active = false, .scalability_mode = ScalabilityMode::kL2T1},
204 {.active = true}});
205
206 // 1 bps less than needed for 720p.
207 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
208
209 EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
210 input_state_provider_.InputState(),
211 /*restrictions_before=*/k360p,
212 /*restrictions_after=*/k720p));
213 }
214
TEST_F(BitrateConstraintTest,AdaptUpAllowedLowestActiveIfBitrateIsNotEnough)215 TEST_F(BitrateConstraintTest, AdaptUpAllowedLowestActiveIfBitrateIsNotEnough) {
216 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
217 {{.active = true}, {.active = false}});
218
219 // 1 bps less than needed for 360p.
220 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
221
222 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
223 input_state_provider_.InputState(),
224 /*restrictions_before=*/k180p,
225 /*restrictions_after=*/k360p));
226 }
227
TEST_F(BitrateConstraintTest,AdaptUpAllowedLowestActiveIfBitrateIsNotEnoughForOneSpatialLayer)228 TEST_F(BitrateConstraintTest,
229 AdaptUpAllowedLowestActiveIfBitrateIsNotEnoughForOneSpatialLayer) {
230 OnEncoderSettingsUpdated(
231 /*width_px=*/640, /*height_px=*/360,
232 {{.active = true, .scalability_mode = ScalabilityMode::kL1T2},
233 {.active = false}});
234
235 // 1 bps less than needed for 360p.
236 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
237
238 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
239 input_state_provider_.InputState(),
240 /*restrictions_before=*/k180p,
241 /*restrictions_after=*/k360p));
242 }
243
TEST_F(BitrateConstraintTest,AdaptUpAllowedLowestActiveIfBitrateIsEnoughForOneSpatialLayerSvc)244 TEST_F(BitrateConstraintTest,
245 AdaptUpAllowedLowestActiveIfBitrateIsEnoughForOneSpatialLayerSvc) {
246 OnEncoderSettingsUpdated(
247 /*width_px=*/640, /*height_px=*/360,
248 {{.active = true, .scalability_mode = ScalabilityMode::kL1T1},
249 {.active = false}},
250 /*svc=*/true);
251
252 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p);
253
254 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
255 input_state_provider_.InputState(),
256 /*restrictions_before=*/k180p,
257 /*restrictions_after=*/k360p));
258 }
259
TEST_F(BitrateConstraintTest,AdaptUpDisallowedLowestActiveIfBitrateIsNotEnoughForOneSpatialLayerSvc)260 TEST_F(BitrateConstraintTest,
261 AdaptUpDisallowedLowestActiveIfBitrateIsNotEnoughForOneSpatialLayerSvc) {
262 OnEncoderSettingsUpdated(
263 /*width_px=*/640, /*height_px=*/360,
264 {{.active = true, .scalability_mode = ScalabilityMode::kL1T1},
265 {.active = false}},
266 /*svc=*/true);
267
268 // 1 bps less than needed for 360p.
269 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
270
271 EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
272 input_state_provider_.InputState(),
273 /*restrictions_before=*/k180p,
274 /*restrictions_after=*/k360p));
275 }
276
TEST_F(BitrateConstraintTest,AdaptUpAllowedLowestActiveIfBitrateIsNotEnoughForTwoSpatialLayersSvc)277 TEST_F(BitrateConstraintTest,
278 AdaptUpAllowedLowestActiveIfBitrateIsNotEnoughForTwoSpatialLayersSvc) {
279 OnEncoderSettingsUpdated(
280 /*width_px=*/640, /*height_px=*/360,
281 {{.active = true, .scalability_mode = ScalabilityMode::kL2T1},
282 {.active = false}},
283 /*svc=*/true);
284
285 // 1 bps less than needed for 360p.
286 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps360p - 1);
287
288 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
289 input_state_provider_.InputState(),
290 /*restrictions_before=*/k180p,
291 /*restrictions_after=*/k360p));
292 }
293
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSimulcastIfBitrateIsNotEnough)294 TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSimulcastIfBitrateIsNotEnough) {
295 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
296 {{.active = true}, {.active = true}});
297
298 // 1 bps less than needed for 720p.
299 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
300
301 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
302 input_state_provider_.InputState(),
303 /*restrictions_before=*/k360p,
304 /*restrictions_after=*/k720p));
305 }
306
TEST_F(BitrateConstraintTest,AdaptUpInFpsAllowedAtNoResolutionIncreaseIfBitrateIsNotEnough)307 TEST_F(BitrateConstraintTest,
308 AdaptUpInFpsAllowedAtNoResolutionIncreaseIfBitrateIsNotEnough) {
309 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
310 {{.active = true}});
311
312 bitrate_constraint_.OnEncoderTargetBitrateUpdated(1);
313
314 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
315 input_state_provider_.InputState(),
316 /*restrictions_before=*/k360p,
317 /*restrictions_after=*/k360p));
318 }
319
320 } // namespace webrtc
321