1 /*
2 * Copyright 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 "video/config/simulcast.h"
12
13 #include "api/transport/field_trial_based_config.h"
14 #include "media/base/media_constants.h"
15 #include "test/field_trial.h"
16 #include "test/gtest.h"
17
18 namespace webrtc {
19 namespace {
20 constexpr int kQpMax = 55;
21 constexpr double kBitratePriority = 2.0;
22 constexpr bool kScreenshare = true;
23 constexpr int kDefaultTemporalLayers = 3; // Value from simulcast.cc.
24
25 // Values from kSimulcastConfigs in simulcast.cc.
GetSimulcastBitrates720p()26 const std::vector<VideoStream> GetSimulcastBitrates720p() {
27 std::vector<VideoStream> streams(3);
28 streams[0].min_bitrate_bps = 30000;
29 streams[0].target_bitrate_bps = 150000;
30 streams[0].max_bitrate_bps = 200000;
31 streams[1].min_bitrate_bps = 150000;
32 streams[1].target_bitrate_bps = 500000;
33 streams[1].max_bitrate_bps = 700000;
34 streams[2].min_bitrate_bps = 600000;
35 streams[2].target_bitrate_bps = 2500000;
36 streams[2].max_bitrate_bps = 2500000;
37 return streams;
38 }
39 } // namespace
40
TEST(SimulcastTest,TotalMaxBitrateIsZeroForNoStreams)41 TEST(SimulcastTest, TotalMaxBitrateIsZeroForNoStreams) {
42 std::vector<VideoStream> streams;
43 EXPECT_EQ(0, cricket::GetTotalMaxBitrate(streams).bps());
44 }
45
TEST(SimulcastTest,GetTotalMaxBitrateForSingleStream)46 TEST(SimulcastTest, GetTotalMaxBitrateForSingleStream) {
47 std::vector<VideoStream> streams(1);
48 streams[0].max_bitrate_bps = 100000;
49 EXPECT_EQ(100000, cricket::GetTotalMaxBitrate(streams).bps());
50 }
51
TEST(SimulcastTest,GetTotalMaxBitrateForMultipleStreams)52 TEST(SimulcastTest, GetTotalMaxBitrateForMultipleStreams) {
53 std::vector<VideoStream> streams(3);
54 streams[0].target_bitrate_bps = 100000;
55 streams[1].target_bitrate_bps = 200000;
56 streams[2].max_bitrate_bps = 400000;
57 EXPECT_EQ(700000, cricket::GetTotalMaxBitrate(streams).bps());
58 }
59
TEST(SimulcastTest,BandwidthAboveTotalMaxBitrateGivenToHighestStream)60 TEST(SimulcastTest, BandwidthAboveTotalMaxBitrateGivenToHighestStream) {
61 std::vector<VideoStream> streams(3);
62 streams[0].target_bitrate_bps = 100000;
63 streams[1].target_bitrate_bps = 200000;
64 streams[2].max_bitrate_bps = 400000;
65
66 const webrtc::DataRate one_bps = webrtc::DataRate::BitsPerSec(1);
67
68 // No bitrate above the total max to give to the highest stream.
69 const webrtc::DataRate max_total_bitrate =
70 cricket::GetTotalMaxBitrate(streams);
71 cricket::BoostMaxSimulcastLayer(max_total_bitrate, &streams);
72 EXPECT_EQ(400000, streams[2].max_bitrate_bps);
73 EXPECT_EQ(max_total_bitrate, cricket::GetTotalMaxBitrate(streams));
74
75 // The bitrate above the total max should be given to the highest stream.
76 cricket::BoostMaxSimulcastLayer(max_total_bitrate + one_bps, &streams);
77 EXPECT_EQ(400000 + 1, streams[2].max_bitrate_bps);
78 EXPECT_EQ(max_total_bitrate + one_bps, cricket::GetTotalMaxBitrate(streams));
79 }
80
TEST(SimulcastTest,GetConfig)81 TEST(SimulcastTest, GetConfig) {
82 const std::vector<VideoStream> kExpected = GetSimulcastBitrates720p();
83 const FieldTrialBasedConfig trials;
84
85 const size_t kMinLayers = 1;
86 const size_t kMaxLayers = 3;
87 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
88 kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
89 !kScreenshare, true, trials);
90
91 EXPECT_EQ(kMaxLayers, streams.size());
92 EXPECT_EQ(320u, streams[0].width);
93 EXPECT_EQ(180u, streams[0].height);
94 EXPECT_EQ(640u, streams[1].width);
95 EXPECT_EQ(360u, streams[1].height);
96 EXPECT_EQ(1280u, streams[2].width);
97 EXPECT_EQ(720u, streams[2].height);
98
99 for (size_t i = 0; i < streams.size(); ++i) {
100 EXPECT_EQ(size_t{kDefaultTemporalLayers}, streams[i].num_temporal_layers);
101 EXPECT_EQ(cricket::kDefaultVideoMaxFramerate, streams[i].max_framerate);
102 EXPECT_EQ(kQpMax, streams[i].max_qp);
103 EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps);
104 EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps);
105 EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps);
106 EXPECT_TRUE(streams[i].active);
107 }
108 // Currently set on lowest stream.
109 EXPECT_EQ(kBitratePriority, streams[0].bitrate_priority);
110 EXPECT_FALSE(streams[1].bitrate_priority);
111 EXPECT_FALSE(streams[2].bitrate_priority);
112 }
113
TEST(SimulcastTest,GetConfigWithBaseHeavyVP8TL3RateAllocation)114 TEST(SimulcastTest, GetConfigWithBaseHeavyVP8TL3RateAllocation) {
115 test::ScopedFieldTrials field_trials(
116 "WebRTC-UseBaseHeavyVP8TL3RateAllocation/Enabled/");
117 FieldTrialBasedConfig trials;
118
119 const std::vector<VideoStream> kExpected = GetSimulcastBitrates720p();
120
121 const size_t kMinLayers = 1;
122 const size_t kMaxLayers = 3;
123 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
124 kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
125 !kScreenshare, true, trials);
126
127 EXPECT_EQ(kExpected[0].min_bitrate_bps, streams[0].min_bitrate_bps);
128 EXPECT_EQ(static_cast<int>(0.4 * kExpected[0].target_bitrate_bps / 0.6),
129 streams[0].target_bitrate_bps);
130 EXPECT_EQ(static_cast<int>(0.4 * kExpected[0].max_bitrate_bps / 0.6),
131 streams[0].max_bitrate_bps);
132 for (size_t i = 1; i < streams.size(); ++i) {
133 EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps);
134 EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps);
135 EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps);
136 }
137 }
138
TEST(SimulcastTest,GetConfigWithLimitedMaxLayers)139 TEST(SimulcastTest, GetConfigWithLimitedMaxLayers) {
140 const size_t kMinLayers = 1;
141 const size_t kMaxLayers = 2;
142 FieldTrialBasedConfig trials;
143 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
144 kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
145 !kScreenshare, true, trials);
146
147 EXPECT_EQ(kMaxLayers, streams.size());
148 EXPECT_EQ(640u, streams[0].width);
149 EXPECT_EQ(360u, streams[0].height);
150 EXPECT_EQ(1280u, streams[1].width);
151 EXPECT_EQ(720u, streams[1].height);
152 }
153
TEST(SimulcastTest,GetConfigWithLimitedMaxLayersForResolution)154 TEST(SimulcastTest, GetConfigWithLimitedMaxLayersForResolution) {
155 test::ScopedFieldTrials field_trials(
156 "WebRTC-LegacySimulcastLayerLimit/Enabled/");
157 FieldTrialBasedConfig trials;
158 const size_t kMinLayers = 1;
159 const size_t kMaxLayers = 3;
160 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
161 kMinLayers, kMaxLayers, 800, 600, kBitratePriority, kQpMax, !kScreenshare,
162 true, trials);
163
164 EXPECT_EQ(2u, streams.size());
165 EXPECT_EQ(400u, streams[0].width);
166 EXPECT_EQ(300u, streams[0].height);
167 EXPECT_EQ(800u, streams[1].width);
168 EXPECT_EQ(600u, streams[1].height);
169 }
170
TEST(SimulcastTest,GetConfigWithLowResolutionScreenshare)171 TEST(SimulcastTest, GetConfigWithLowResolutionScreenshare) {
172 test::ScopedFieldTrials field_trials(
173 "WebRTC-LegacySimulcastLayerLimit/Enabled/");
174 FieldTrialBasedConfig trials;
175 const size_t kMinLayers = 1;
176 const size_t kMaxLayers = 3;
177 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
178 kMinLayers, kMaxLayers, 100, 100, kBitratePriority, kQpMax, kScreenshare,
179 true, trials);
180
181 // Simulcast streams number is never decreased for screenshare,
182 // even for very low resolution.
183 EXPECT_GT(streams.size(), 1u);
184 }
185
TEST(SimulcastTest,GetConfigWithNotLimitedMaxLayersForResolution)186 TEST(SimulcastTest, GetConfigWithNotLimitedMaxLayersForResolution) {
187 test::ScopedFieldTrials field_trials(
188 "WebRTC-LegacySimulcastLayerLimit/Disabled/");
189 FieldTrialBasedConfig trials;
190 const size_t kMinLayers = 1;
191 const size_t kMaxLayers = 3;
192 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
193 kMinLayers, kMaxLayers, 800, 600, kBitratePriority, kQpMax, !kScreenshare,
194 true, trials);
195
196 EXPECT_EQ(kMaxLayers, streams.size());
197 EXPECT_EQ(200u, streams[0].width);
198 EXPECT_EQ(150u, streams[0].height);
199 EXPECT_EQ(400u, streams[1].width);
200 EXPECT_EQ(300u, streams[1].height);
201 EXPECT_EQ(800u, streams[2].width);
202 EXPECT_EQ(600u, streams[2].height);
203 }
204
TEST(SimulcastTest,GetConfigWithNormalizedResolution)205 TEST(SimulcastTest, GetConfigWithNormalizedResolution) {
206 FieldTrialBasedConfig trials;
207 const size_t kMinLayers = 1;
208 const size_t kMaxLayers = 2;
209 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
210 kMinLayers, kMaxLayers, 640 + 1, 360 + 1, kBitratePriority, kQpMax,
211 !kScreenshare, true, trials);
212
213 // Must be divisible by |2 ^ (num_layers - 1)|.
214 EXPECT_EQ(kMaxLayers, streams.size());
215 EXPECT_EQ(320u, streams[0].width);
216 EXPECT_EQ(180u, streams[0].height);
217 EXPECT_EQ(640u, streams[1].width);
218 EXPECT_EQ(360u, streams[1].height);
219 }
220
TEST(SimulcastTest,GetConfigWithNormalizedResolutionDivisibleBy4)221 TEST(SimulcastTest, GetConfigWithNormalizedResolutionDivisibleBy4) {
222 test::ScopedFieldTrials field_trials(
223 "WebRTC-NormalizeSimulcastResolution/Enabled-2/");
224 FieldTrialBasedConfig trials;
225
226 const size_t kMinLayers = 1;
227 const size_t kMaxLayers = 2;
228 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
229 kMinLayers, kMaxLayers, 709, 501, kBitratePriority, kQpMax, !kScreenshare,
230 true, trials);
231
232 // Must be divisible by |2 ^ 2|.
233 EXPECT_EQ(kMaxLayers, streams.size());
234 EXPECT_EQ(354u, streams[0].width);
235 EXPECT_EQ(250u, streams[0].height);
236 EXPECT_EQ(708u, streams[1].width);
237 EXPECT_EQ(500u, streams[1].height);
238 }
239
TEST(SimulcastTest,GetConfigWithNormalizedResolutionDivisibleBy8)240 TEST(SimulcastTest, GetConfigWithNormalizedResolutionDivisibleBy8) {
241 test::ScopedFieldTrials field_trials(
242 "WebRTC-NormalizeSimulcastResolution/Enabled-3/");
243 FieldTrialBasedConfig trials;
244
245 const size_t kMinLayers = 1;
246 const size_t kMaxLayers = 2;
247 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
248 kMinLayers, kMaxLayers, 709, 501, kBitratePriority, kQpMax, !kScreenshare,
249 true, trials);
250
251 // Must be divisible by |2 ^ 3|.
252 EXPECT_EQ(kMaxLayers, streams.size());
253 EXPECT_EQ(352u, streams[0].width);
254 EXPECT_EQ(248u, streams[0].height);
255 EXPECT_EQ(704u, streams[1].width);
256 EXPECT_EQ(496u, streams[1].height);
257 }
258
TEST(SimulcastTest,GetConfigForLegacyLayerLimit)259 TEST(SimulcastTest, GetConfigForLegacyLayerLimit) {
260 test::ScopedFieldTrials field_trials(
261 "WebRTC-LegacySimulcastLayerLimit/Enabled/");
262 FieldTrialBasedConfig trials;
263
264 const size_t kMinLayers = 1;
265 const int kMaxLayers = 3;
266 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
267 kMinLayers, kMaxLayers, 320, 180, kBitratePriority, kQpMax, !kScreenshare,
268 true, trials);
269 EXPECT_EQ(1u, streams.size());
270
271 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
272 kBitratePriority, kQpMax, !kScreenshare,
273 true, trials);
274 EXPECT_EQ(2u, streams.size());
275
276 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
277 kBitratePriority, kQpMax, !kScreenshare,
278 true, trials);
279 EXPECT_EQ(3u, streams.size());
280 }
281
TEST(SimulcastTest,GetConfigForLegacyLayerLimitWithRequiredHD)282 TEST(SimulcastTest, GetConfigForLegacyLayerLimitWithRequiredHD) {
283 test::ScopedFieldTrials field_trials(
284 "WebRTC-LegacySimulcastLayerLimit/Enabled/");
285 FieldTrialBasedConfig trials;
286
287 const size_t kMinLayers = 3; // "HD" layer must be present!
288 const int kMaxLayers = 3;
289 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
290 kMinLayers, kMaxLayers, 320, 180, kBitratePriority, kQpMax, !kScreenshare,
291 true, trials);
292 EXPECT_EQ(3u, streams.size());
293
294 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
295 kBitratePriority, kQpMax, !kScreenshare,
296 true, trials);
297 EXPECT_EQ(3u, streams.size());
298
299 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
300 kBitratePriority, kQpMax, !kScreenshare,
301 true, trials);
302 EXPECT_EQ(3u, streams.size());
303 }
304
TEST(SimulcastTest,GetConfigForScreenshareSimulcast)305 TEST(SimulcastTest, GetConfigForScreenshareSimulcast) {
306 FieldTrialBasedConfig trials;
307 const size_t kMinLayers = 1;
308 const size_t kMaxLayers = 3;
309 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
310 kMinLayers, kMaxLayers, 1400, 800, kBitratePriority, kQpMax, kScreenshare,
311 true, trials);
312
313 EXPECT_GT(streams.size(), 1u);
314 for (size_t i = 0; i < streams.size(); ++i) {
315 EXPECT_EQ(1400u, streams[i].width) << "Screen content never scaled.";
316 EXPECT_EQ(800u, streams[i].height) << "Screen content never scaled.";
317 EXPECT_EQ(kQpMax, streams[i].max_qp);
318 EXPECT_TRUE(streams[i].active);
319 EXPECT_GT(streams[i].num_temporal_layers, size_t{1});
320 EXPECT_GT(streams[i].max_framerate, 0);
321 EXPECT_GT(streams[i].min_bitrate_bps, 0);
322 EXPECT_GT(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps);
323 EXPECT_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps);
324 }
325 }
326
TEST(SimulcastTest,GetConfigForScreenshareSimulcastWithLimitedMaxLayers)327 TEST(SimulcastTest, GetConfigForScreenshareSimulcastWithLimitedMaxLayers) {
328 FieldTrialBasedConfig trials;
329 const size_t kMinLayers = 1;
330 const size_t kMaxLayers = 1;
331 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
332 kMinLayers, kMaxLayers, 1400, 800, kBitratePriority, kQpMax, kScreenshare,
333 true, trials);
334
335 EXPECT_EQ(kMaxLayers, streams.size());
336 }
337
TEST(SimulcastTest,AveragesBitratesForNonStandardResolution)338 TEST(SimulcastTest, AveragesBitratesForNonStandardResolution) {
339 FieldTrialBasedConfig trials;
340 const size_t kMinLayers = 1;
341 const size_t kMaxLayers = 3;
342 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
343 kMinLayers, kMaxLayers, 900, 800, kBitratePriority, kQpMax, !kScreenshare,
344 true, trials);
345
346 EXPECT_EQ(kMaxLayers, streams.size());
347 EXPECT_EQ(900u, streams[2].width);
348 EXPECT_EQ(800u, streams[2].height);
349 EXPECT_EQ(1850000, streams[2].max_bitrate_bps);
350 EXPECT_EQ(1850000, streams[2].target_bitrate_bps);
351 EXPECT_EQ(475000, streams[2].min_bitrate_bps);
352 }
353
TEST(SimulcastTest,BitratesForCloseToStandardResolution)354 TEST(SimulcastTest, BitratesForCloseToStandardResolution) {
355 const size_t kMinLayers = 1;
356 const size_t kMaxLayers = 3;
357 // Resolution very close to 720p in number of pixels
358 const size_t kWidth = 1280;
359 const size_t kHeight = 716;
360 const std::vector<VideoStream> kExpectedNear = GetSimulcastBitrates720p();
361 FieldTrialBasedConfig trials;
362
363 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
364 kMinLayers, kMaxLayers, kWidth, kHeight, kBitratePriority, kQpMax,
365 !kScreenshare, true, trials);
366
367 EXPECT_EQ(kMaxLayers, streams.size());
368 EXPECT_EQ(kWidth, streams[2].width);
369 EXPECT_EQ(kHeight, streams[2].height);
370 for (size_t i = 0; i < streams.size(); ++i) {
371 EXPECT_NEAR(kExpectedNear[i].max_bitrate_bps, streams[i].max_bitrate_bps,
372 20000);
373 EXPECT_NEAR(kExpectedNear[i].target_bitrate_bps,
374 streams[i].target_bitrate_bps, 20000);
375 EXPECT_NEAR(kExpectedNear[i].min_bitrate_bps, streams[i].min_bitrate_bps,
376 20000);
377 }
378 }
379
TEST(SimulcastTest,MaxLayersWithRoundUpDisabled)380 TEST(SimulcastTest, MaxLayersWithRoundUpDisabled) {
381 test::ScopedFieldTrials field_trials(
382 "WebRTC-SimulcastLayerLimitRoundUp/max_ratio:0.0/");
383 FieldTrialBasedConfig trials;
384 const size_t kMinLayers = 1;
385 const int kMaxLayers = 3;
386
387 std::vector<VideoStream> streams;
388 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
389 kBitratePriority, kQpMax, !kScreenshare,
390 true, trials);
391 EXPECT_EQ(3u, streams.size());
392 // <960x540: 2 layers
393 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 539,
394 kBitratePriority, kQpMax, !kScreenshare,
395 true, trials);
396 EXPECT_EQ(2u, streams.size());
397 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
398 kBitratePriority, kQpMax, !kScreenshare,
399 true, trials);
400 EXPECT_EQ(2u, streams.size());
401 // <480x270: 1 layer
402 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 269,
403 kBitratePriority, kQpMax, !kScreenshare,
404 true, trials);
405 EXPECT_EQ(1u, streams.size());
406 }
407
TEST(SimulcastTest,MaxLayersWithDefaultRoundUpRatio)408 TEST(SimulcastTest, MaxLayersWithDefaultRoundUpRatio) {
409 // Default: "WebRTC-SimulcastLayerLimitRoundUp/max_ratio:0.1/"
410 FieldTrialBasedConfig trials;
411 const size_t kMinLayers = 1;
412 const int kMaxLayers = 3;
413
414 std::vector<VideoStream> streams;
415 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
416 kBitratePriority, kQpMax, !kScreenshare,
417 true, trials);
418 EXPECT_EQ(3u, streams.size());
419 // Lowest cropped height where max layers from higher resolution is used.
420 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 512,
421 kBitratePriority, kQpMax, !kScreenshare,
422 true, trials);
423 EXPECT_EQ(3u, streams.size());
424 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 508,
425 kBitratePriority, kQpMax, !kScreenshare,
426 true, trials);
427 EXPECT_EQ(2u, streams.size());
428 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
429 kBitratePriority, kQpMax, !kScreenshare,
430 true, trials);
431 EXPECT_EQ(2u, streams.size());
432 // Lowest cropped height where max layers from higher resolution is used.
433 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 256,
434 kBitratePriority, kQpMax, !kScreenshare,
435 true, trials);
436 EXPECT_EQ(2u, streams.size());
437 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 254,
438 kBitratePriority, kQpMax, !kScreenshare,
439 true, trials);
440 EXPECT_EQ(1u, streams.size());
441 }
442
TEST(SimulcastTest,MaxLayersWithRoundUpRatio)443 TEST(SimulcastTest, MaxLayersWithRoundUpRatio) {
444 test::ScopedFieldTrials field_trials(
445 "WebRTC-SimulcastLayerLimitRoundUp/max_ratio:0.13/");
446 FieldTrialBasedConfig trials;
447 const size_t kMinLayers = 1;
448 const int kMaxLayers = 3;
449
450 std::vector<VideoStream> streams;
451 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
452 kBitratePriority, kQpMax, !kScreenshare,
453 true, trials);
454 EXPECT_EQ(2u, streams.size());
455 // Lowest cropped height where max layers from higher resolution is used.
456 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 252,
457 kBitratePriority, kQpMax, !kScreenshare,
458 true, trials);
459 EXPECT_EQ(2u, streams.size());
460 streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 250,
461 kBitratePriority, kQpMax, !kScreenshare,
462 true, trials);
463 EXPECT_EQ(1u, streams.size());
464 }
465
TEST(SimulcastTest,BitratesInterpolatedForResBelow180p)466 TEST(SimulcastTest, BitratesInterpolatedForResBelow180p) {
467 // TODO(webrtc:12415): Remove when feature launches.
468 test::ScopedFieldTrials field_trials(
469 "WebRTC-LowresSimulcastBitrateInterpolation/Enabled/");
470
471 const size_t kMaxLayers = 3;
472 FieldTrialBasedConfig trials;
473
474 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
475 /* min_layers = */ 1, kMaxLayers, /* width = */ 960, /* height = */ 540,
476 kBitratePriority, kQpMax, !kScreenshare, true, trials);
477
478 ASSERT_EQ(streams.size(), kMaxLayers);
479 EXPECT_EQ(240u, streams[0].width);
480 EXPECT_EQ(135u, streams[0].height);
481 EXPECT_EQ(streams[0].max_bitrate_bps, 112500);
482 EXPECT_EQ(streams[0].target_bitrate_bps, 84375);
483 EXPECT_EQ(streams[0].min_bitrate_bps, 30000);
484 }
485
TEST(SimulcastTest,BitratesConsistentForVerySmallRes)486 TEST(SimulcastTest, BitratesConsistentForVerySmallRes) {
487 // TODO(webrtc:12415): Remove when feature launches.
488 test::ScopedFieldTrials field_trials(
489 "WebRTC-LowresSimulcastBitrateInterpolation/Enabled/");
490
491 FieldTrialBasedConfig trials;
492
493 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
494 /* min_layers = */ 1, /* max_layers = */ 3, /* width = */ 1,
495 /* height = */ 1, kBitratePriority, kQpMax, !kScreenshare, true, trials);
496
497 ASSERT_TRUE(!streams.empty());
498 EXPECT_EQ(1u, streams[0].width);
499 EXPECT_EQ(1u, streams[0].height);
500 EXPECT_EQ(streams[0].max_bitrate_bps, 30000);
501 EXPECT_EQ(streams[0].target_bitrate_bps, 30000);
502 EXPECT_EQ(streams[0].min_bitrate_bps, 30000);
503 }
504
TEST(SimulcastTest,BitratesNotInterpolatedForResBelow180pWhenDisabledTrialSet)505 TEST(SimulcastTest,
506 BitratesNotInterpolatedForResBelow180pWhenDisabledTrialSet) {
507 test::ScopedFieldTrials field_trials(
508 "WebRTC-LowresSimulcastBitrateInterpolation/Disabled/");
509
510 const size_t kMaxLayers = 3;
511 FieldTrialBasedConfig trials;
512
513 std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
514 /* min_layers = */ 1, kMaxLayers, /* width = */ 960, /* height = */ 540,
515 kBitratePriority, kQpMax, !kScreenshare, true, trials);
516
517 ASSERT_EQ(streams.size(), kMaxLayers);
518 EXPECT_EQ(240u, streams[0].width);
519 EXPECT_EQ(135u, streams[0].height);
520 EXPECT_EQ(streams[0].max_bitrate_bps, 200000);
521 EXPECT_EQ(streams[0].target_bitrate_bps, 150000);
522 EXPECT_EQ(streams[0].min_bitrate_bps, 30000);
523 }
524
525 } // namespace webrtc
526