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 "modules/video_coding/svc/svc_rate_allocator.h"
12
13 #include <algorithm>
14 #include <vector>
15
16 #include "modules/video_coding/codecs/vp9/svc_config.h"
17 #include "rtc_base/checks.h"
18 #include "test/field_trial.h"
19 #include "test/gtest.h"
20
21 namespace webrtc {
22 namespace test {
23 namespace {
Configure(size_t width,size_t height,size_t num_spatial_layers,size_t num_temporal_layers,bool is_screen_sharing)24 static VideoCodec Configure(size_t width,
25 size_t height,
26 size_t num_spatial_layers,
27 size_t num_temporal_layers,
28 bool is_screen_sharing) {
29 VideoCodec codec;
30 codec.width = width;
31 codec.height = height;
32 codec.codecType = kVideoCodecVP9;
33 codec.mode = is_screen_sharing ? VideoCodecMode::kScreensharing
34 : VideoCodecMode::kRealtimeVideo;
35
36 std::vector<SpatialLayer> spatial_layers =
37 GetSvcConfig(width, height, 30, /*first_active_layer=*/0,
38 num_spatial_layers, num_temporal_layers, is_screen_sharing);
39 RTC_CHECK_LE(spatial_layers.size(), kMaxSpatialLayers);
40
41 codec.VP9()->numberOfSpatialLayers =
42 std::min<unsigned char>(num_spatial_layers, spatial_layers.size());
43 codec.VP9()->numberOfTemporalLayers = std::min<unsigned char>(
44 num_temporal_layers, spatial_layers.back().numberOfTemporalLayers);
45
46 for (size_t sl_idx = 0; sl_idx < spatial_layers.size(); ++sl_idx) {
47 codec.spatialLayers[sl_idx] = spatial_layers[sl_idx];
48 }
49
50 return codec;
51 }
52
53 } // namespace
54
TEST(SvcRateAllocatorTest,SingleLayerFor320x180Input)55 TEST(SvcRateAllocatorTest, SingleLayerFor320x180Input) {
56 VideoCodec codec = Configure(320, 180, 3, 3, false);
57 SvcRateAllocator allocator = SvcRateAllocator(codec);
58
59 VideoBitrateAllocation allocation =
60 allocator.Allocate(VideoBitrateAllocationParameters(1000 * 1000, 30));
61
62 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
63 EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0u);
64 }
65
TEST(SvcRateAllocatorTest,TwoLayersFor640x360Input)66 TEST(SvcRateAllocatorTest, TwoLayersFor640x360Input) {
67 VideoCodec codec = Configure(640, 360, 3, 3, false);
68 SvcRateAllocator allocator = SvcRateAllocator(codec);
69
70 VideoBitrateAllocation allocation =
71 allocator.Allocate(VideoBitrateAllocationParameters(1000 * 1000, 30));
72
73 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
74 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0u);
75 EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0u);
76 }
77
TEST(SvcRateAllocatorTest,ThreeLayersFor1280x720Input)78 TEST(SvcRateAllocatorTest, ThreeLayersFor1280x720Input) {
79 VideoCodec codec = Configure(1280, 720, 3, 3, false);
80 SvcRateAllocator allocator = SvcRateAllocator(codec);
81
82 VideoBitrateAllocation allocation =
83 allocator.Allocate(VideoBitrateAllocationParameters(1000 * 1000, 30));
84
85 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
86 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0u);
87 EXPECT_GT(allocation.GetSpatialLayerSum(2), 0u);
88 }
89
TEST(SvcRateAllocatorTest,BaseLayerNonZeroBitrateEvenIfTotalIfLessThanMinimum)90 TEST(SvcRateAllocatorTest,
91 BaseLayerNonZeroBitrateEvenIfTotalIfLessThanMinimum) {
92 VideoCodec codec = Configure(1280, 720, 3, 3, false);
93 SvcRateAllocator allocator = SvcRateAllocator(codec);
94
95 const SpatialLayer* layers = codec.spatialLayers;
96
97 VideoBitrateAllocation allocation = allocator.Allocate(
98 VideoBitrateAllocationParameters(layers[0].minBitrate * 1000 / 2, 30));
99
100 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
101 EXPECT_LT(allocation.GetSpatialLayerSum(0), layers[0].minBitrate * 1000);
102 EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0u);
103 }
104
TEST(SvcRateAllocatorTest,Disable640x360Layer)105 TEST(SvcRateAllocatorTest, Disable640x360Layer) {
106 VideoCodec codec = Configure(1280, 720, 3, 3, false);
107 SvcRateAllocator allocator = SvcRateAllocator(codec);
108
109 const SpatialLayer* layers = codec.spatialLayers;
110
111 size_t min_bitrate_for_640x360_layer_kbps =
112 layers[0].minBitrate + layers[1].minBitrate;
113
114 VideoBitrateAllocation allocation =
115 allocator.Allocate(VideoBitrateAllocationParameters(
116 min_bitrate_for_640x360_layer_kbps * 1000 - 1, 30));
117
118 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
119 EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0u);
120 }
121
TEST(SvcRateAllocatorTest,Disable1280x720Layer)122 TEST(SvcRateAllocatorTest, Disable1280x720Layer) {
123 VideoCodec codec = Configure(1280, 720, 3, 3, false);
124 SvcRateAllocator allocator = SvcRateAllocator(codec);
125
126 const SpatialLayer* layers = codec.spatialLayers;
127
128 size_t min_bitrate_for_1280x720_layer_kbps =
129 layers[0].minBitrate + layers[1].minBitrate + layers[2].minBitrate;
130
131 VideoBitrateAllocation allocation =
132 allocator.Allocate(VideoBitrateAllocationParameters(
133 min_bitrate_for_1280x720_layer_kbps * 1000 - 1, 30));
134
135 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
136 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0u);
137 EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0u);
138 }
139
TEST(SvcRateAllocatorTest,BitrateIsCapped)140 TEST(SvcRateAllocatorTest, BitrateIsCapped) {
141 VideoCodec codec = Configure(1280, 720, 3, 3, false);
142 SvcRateAllocator allocator = SvcRateAllocator(codec);
143
144 const SpatialLayer* layers = codec.spatialLayers;
145
146 const uint32_t link_mbps = 100;
147 VideoBitrateAllocation allocation = allocator.Allocate(
148 VideoBitrateAllocationParameters(link_mbps * 1000000, 30));
149
150 EXPECT_EQ(allocation.get_sum_kbps(),
151 layers[0].maxBitrate + layers[1].maxBitrate + layers[2].maxBitrate);
152 EXPECT_EQ(allocation.GetSpatialLayerSum(0) / 1000, layers[0].maxBitrate);
153 EXPECT_EQ(allocation.GetSpatialLayerSum(1) / 1000, layers[1].maxBitrate);
154 EXPECT_EQ(allocation.GetSpatialLayerSum(2) / 1000, layers[2].maxBitrate);
155 }
156
TEST(SvcRateAllocatorTest,MinBitrateToGetQualityLayer)157 TEST(SvcRateAllocatorTest, MinBitrateToGetQualityLayer) {
158 VideoCodec codec = Configure(1280, 720, 3, 1, true);
159 SvcRateAllocator allocator = SvcRateAllocator(codec);
160
161 const SpatialLayer* layers = codec.spatialLayers;
162
163 EXPECT_LE(codec.VP9()->numberOfSpatialLayers, 3U);
164
165 VideoBitrateAllocation allocation = allocator.Allocate(
166 VideoBitrateAllocationParameters(layers[0].minBitrate * 1000, 30));
167 EXPECT_EQ(allocation.GetSpatialLayerSum(0) / 1000, layers[0].minBitrate);
168 EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0UL);
169
170 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
171 (layers[0].targetBitrate + layers[1].minBitrate) * 1000, 30));
172 EXPECT_EQ(allocation.GetSpatialLayerSum(0) / 1000, layers[0].targetBitrate);
173 EXPECT_EQ(allocation.GetSpatialLayerSum(1) / 1000, layers[1].minBitrate);
174 }
175
TEST(SvcRateAllocatorTest,DeactivateHigherLayers)176 TEST(SvcRateAllocatorTest, DeactivateHigherLayers) {
177 for (int deactivated_idx = 2; deactivated_idx >= 0; --deactivated_idx) {
178 VideoCodec codec = Configure(1280, 720, 3, 1, false);
179 EXPECT_LE(codec.VP9()->numberOfSpatialLayers, 3U);
180
181 for (int i = deactivated_idx; i < 3; ++i)
182 codec.spatialLayers[i].active = false;
183
184 SvcRateAllocator allocator = SvcRateAllocator(codec);
185
186 VideoBitrateAllocation allocation = allocator.Allocate(
187 VideoBitrateAllocationParameters(10 * 1000 * 1000, 30));
188
189 // Ensure layers spatial_idx < deactivated_idx are activated.
190 for (int spatial_idx = 0; spatial_idx < deactivated_idx; ++spatial_idx) {
191 EXPECT_GT(allocation.GetSpatialLayerSum(spatial_idx), 0UL);
192 }
193
194 // Ensure layers spatial_idx >= deactivated_idx are deactivated.
195 for (int spatial_idx = deactivated_idx; spatial_idx < 3; ++spatial_idx) {
196 EXPECT_EQ(allocation.GetSpatialLayerSum(spatial_idx), 0UL);
197 }
198 }
199 }
200
TEST(SvcRateAllocatorTest,DeactivateLowerLayers)201 TEST(SvcRateAllocatorTest, DeactivateLowerLayers) {
202 for (int deactivated_idx = 0; deactivated_idx < 3; ++deactivated_idx) {
203 VideoCodec codec = Configure(1280, 720, 3, 1, false);
204 EXPECT_LE(codec.VP9()->numberOfSpatialLayers, 3U);
205
206 for (int i = deactivated_idx; i >= 0; --i)
207 codec.spatialLayers[i].active = false;
208
209 SvcRateAllocator allocator = SvcRateAllocator(codec);
210
211 VideoBitrateAllocation allocation = allocator.Allocate(
212 VideoBitrateAllocationParameters(10 * 1000 * 1000, 30));
213
214 // Ensure layers spatial_idx <= deactivated_idx are deactivated.
215 for (int spatial_idx = 0; spatial_idx <= deactivated_idx; ++spatial_idx) {
216 EXPECT_EQ(allocation.GetSpatialLayerSum(spatial_idx), 0UL);
217 }
218
219 // Ensure layers spatial_idx > deactivated_idx are activated.
220 for (int spatial_idx = deactivated_idx + 1; spatial_idx < 3;
221 ++spatial_idx) {
222 EXPECT_GT(allocation.GetSpatialLayerSum(spatial_idx), 0UL);
223 }
224 }
225 }
226
TEST(SvcRateAllocatorTest,SignalsBwLimited)227 TEST(SvcRateAllocatorTest, SignalsBwLimited) {
228 VideoCodec codec = Configure(1280, 720, 3, 1, false);
229 SvcRateAllocator allocator = SvcRateAllocator(codec);
230
231 // Rough estimate calculated by hand.
232 uint32_t min_to_enable_all = 900000;
233
234 EXPECT_TRUE(
235 allocator
236 .Allocate(VideoBitrateAllocationParameters(min_to_enable_all / 2, 30))
237 .is_bw_limited());
238
239 EXPECT_FALSE(
240 allocator
241 .Allocate(VideoBitrateAllocationParameters(min_to_enable_all, 30))
242 .is_bw_limited());
243 }
244
TEST(SvcRateAllocatorTest,NoPaddingIfAllLayersAreDeactivated)245 TEST(SvcRateAllocatorTest, NoPaddingIfAllLayersAreDeactivated) {
246 VideoCodec codec = Configure(1280, 720, 3, 1, false);
247 EXPECT_EQ(codec.VP9()->numberOfSpatialLayers, 3U);
248 // Deactivation of base layer deactivates all layers.
249 codec.spatialLayers[0].active = false;
250 codec.spatialLayers[1].active = false;
251 codec.spatialLayers[2].active = false;
252 DataRate padding_rate = SvcRateAllocator::GetPaddingBitrate(codec);
253 EXPECT_EQ(padding_rate, DataRate::Zero());
254 }
255
TEST(SvcRateAllocatorTest,FindLayerTogglingThreshold)256 TEST(SvcRateAllocatorTest, FindLayerTogglingThreshold) {
257 // Let's unit test a utility method of the unit test...
258
259 // Predetermined constants indicating the min bitrate needed for two and three
260 // layers to be enabled respectively, using the config from Configure() with
261 // 1280x720 resolution and three spatial layers.
262 const DataRate kTwoLayerMinRate = DataRate::BitsPerSec(299150);
263 const DataRate kThreeLayerMinRate = DataRate::BitsPerSec(891052);
264
265 VideoCodec codec = Configure(1280, 720, 3, 1, false);
266 absl::InlinedVector<DataRate, kMaxSpatialLayers> layer_start_bitrates =
267 SvcRateAllocator::GetLayerStartBitrates(codec);
268 ASSERT_EQ(layer_start_bitrates.size(), 3u);
269 EXPECT_EQ(layer_start_bitrates[1], kTwoLayerMinRate);
270 EXPECT_EQ(layer_start_bitrates[2], kThreeLayerMinRate);
271 }
272
TEST(SvcRateAllocatorTest,SupportsAv1)273 TEST(SvcRateAllocatorTest, SupportsAv1) {
274 VideoCodec codec;
275 codec.width = 640;
276 codec.height = 360;
277 codec.codecType = kVideoCodecAV1;
278 codec.SetScalabilityMode(ScalabilityMode::kL3T3);
279 codec.spatialLayers[0].active = true;
280 codec.spatialLayers[0].minBitrate = 30;
281 codec.spatialLayers[0].targetBitrate = 51;
282 codec.spatialLayers[0].maxBitrate = 73;
283 codec.spatialLayers[1].active = true;
284 codec.spatialLayers[1].minBitrate = 49;
285 codec.spatialLayers[1].targetBitrate = 64;
286 codec.spatialLayers[1].maxBitrate = 97;
287 codec.spatialLayers[2].active = true;
288 codec.spatialLayers[2].minBitrate = 193;
289 codec.spatialLayers[2].targetBitrate = 305;
290 codec.spatialLayers[2].maxBitrate = 418;
291
292 SvcRateAllocator allocator(codec);
293
294 VideoBitrateAllocation allocation =
295 allocator.Allocate(VideoBitrateAllocationParameters(1'000'000, 30));
296
297 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0u);
298 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0u);
299 EXPECT_GT(allocation.GetSpatialLayerSum(2), 0u);
300 }
301
TEST(SvcRateAllocatorTest,SupportsAv1WithSkippedLayer)302 TEST(SvcRateAllocatorTest, SupportsAv1WithSkippedLayer) {
303 VideoCodec codec;
304 codec.width = 640;
305 codec.height = 360;
306 codec.codecType = kVideoCodecAV1;
307 codec.SetScalabilityMode(ScalabilityMode::kL3T3);
308 codec.spatialLayers[0].active = false;
309 codec.spatialLayers[0].minBitrate = 30;
310 codec.spatialLayers[0].targetBitrate = 51;
311 codec.spatialLayers[0].maxBitrate = 73;
312 codec.spatialLayers[1].active = true;
313 codec.spatialLayers[1].minBitrate = 49;
314 codec.spatialLayers[1].targetBitrate = 64;
315 codec.spatialLayers[1].maxBitrate = 97;
316 codec.spatialLayers[2].active = true;
317 codec.spatialLayers[2].minBitrate = 193;
318 codec.spatialLayers[2].targetBitrate = 305;
319 codec.spatialLayers[2].maxBitrate = 418;
320
321 SvcRateAllocator allocator(codec);
322
323 VideoBitrateAllocation allocation =
324 allocator.Allocate(VideoBitrateAllocationParameters(1'000'000, 30));
325
326 EXPECT_EQ(allocation.GetSpatialLayerSum(0), 0u);
327 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0u);
328 EXPECT_GT(allocation.GetSpatialLayerSum(2), 0u);
329 }
330
TEST(SvcRateAllocatorTest,UsesScalabilityModeToGetNumberOfLayers)331 TEST(SvcRateAllocatorTest, UsesScalabilityModeToGetNumberOfLayers) {
332 VideoCodec codec;
333 codec.width = 640;
334 codec.height = 360;
335 codec.codecType = kVideoCodecAV1;
336 codec.SetScalabilityMode(ScalabilityMode::kL2T2);
337 codec.spatialLayers[0].active = true;
338 codec.spatialLayers[0].minBitrate = 30;
339 codec.spatialLayers[0].targetBitrate = 51;
340 codec.spatialLayers[0].maxBitrate = 73;
341 codec.spatialLayers[1].active = true;
342 codec.spatialLayers[1].minBitrate = 49;
343 codec.spatialLayers[1].targetBitrate = 64;
344 codec.spatialLayers[1].maxBitrate = 97;
345 codec.spatialLayers[2].active = true;
346 codec.spatialLayers[2].minBitrate = 193;
347 codec.spatialLayers[2].targetBitrate = 305;
348 codec.spatialLayers[2].maxBitrate = 418;
349
350 SvcRateAllocator allocator(codec);
351 VideoBitrateAllocation allocation =
352 allocator.Allocate(VideoBitrateAllocationParameters(1'000'000, 30));
353
354 // Expect bitrates for 2 temporal layers.
355 EXPECT_TRUE(allocation.HasBitrate(1, /*temporal_index=*/0));
356 EXPECT_TRUE(allocation.HasBitrate(1, /*temporal_index=*/1));
357 EXPECT_FALSE(allocation.HasBitrate(1, /*temporal_index=*/2));
358
359 // expect codec.spatialLayers[2].active is ignored because scability mode uses
360 // just 2 spatial layers.
361 EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0u);
362 }
363
364 class SvcRateAllocatorTestParametrizedContentType
365 : public ::testing::Test,
366 public ::testing::WithParamInterface<bool> {
367 public:
SvcRateAllocatorTestParametrizedContentType()368 SvcRateAllocatorTestParametrizedContentType()
369 : is_screen_sharing_(GetParam()) {}
370
371 const bool is_screen_sharing_;
372 };
373
TEST_P(SvcRateAllocatorTestParametrizedContentType,MaxBitrate)374 TEST_P(SvcRateAllocatorTestParametrizedContentType, MaxBitrate) {
375 VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_);
376 EXPECT_EQ(SvcRateAllocator::GetMaxBitrate(codec),
377 DataRate::KilobitsPerSec(codec.spatialLayers[0].maxBitrate +
378 codec.spatialLayers[1].maxBitrate +
379 codec.spatialLayers[2].maxBitrate));
380
381 // Deactivate middle layer. This causes deactivation of top layer as well.
382 codec.spatialLayers[1].active = false;
383 EXPECT_EQ(SvcRateAllocator::GetMaxBitrate(codec),
384 DataRate::KilobitsPerSec(codec.spatialLayers[0].maxBitrate));
385 }
386
TEST_P(SvcRateAllocatorTestParametrizedContentType,PaddingBitrate)387 TEST_P(SvcRateAllocatorTestParametrizedContentType, PaddingBitrate) {
388 VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_);
389 SvcRateAllocator allocator = SvcRateAllocator(codec);
390
391 DataRate padding_bitrate = SvcRateAllocator::GetPaddingBitrate(codec);
392
393 VideoBitrateAllocation allocation =
394 allocator.Allocate(VideoBitrateAllocationParameters(padding_bitrate, 30));
395 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
396 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL);
397 EXPECT_GT(allocation.GetSpatialLayerSum(2), 0UL);
398
399 // Allocate 90% of padding bitrate. Top layer should be disabled.
400 allocation = allocator.Allocate(
401 VideoBitrateAllocationParameters(9 * padding_bitrate / 10, 30));
402 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
403 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL);
404 EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL);
405
406 // Deactivate top layer.
407 codec.spatialLayers[2].active = false;
408
409 padding_bitrate = SvcRateAllocator::GetPaddingBitrate(codec);
410 allocation =
411 allocator.Allocate(VideoBitrateAllocationParameters(padding_bitrate, 30));
412 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
413 EXPECT_GT(allocation.GetSpatialLayerSum(1), 0UL);
414 EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL);
415
416 allocation = allocator.Allocate(
417 VideoBitrateAllocationParameters(9 * padding_bitrate / 10, 30));
418 EXPECT_GT(allocation.GetSpatialLayerSum(0), 0UL);
419 EXPECT_EQ(allocation.GetSpatialLayerSum(1), 0UL);
420 EXPECT_EQ(allocation.GetSpatialLayerSum(2), 0UL);
421
422 // Deactivate all layers.
423 codec.spatialLayers[0].active = false;
424 codec.spatialLayers[1].active = false;
425 codec.spatialLayers[2].active = false;
426
427 padding_bitrate = SvcRateAllocator::GetPaddingBitrate(codec);
428 // No padding expected.
429 EXPECT_EQ(DataRate::Zero(), padding_bitrate);
430 }
431
TEST_P(SvcRateAllocatorTestParametrizedContentType,StableBitrate)432 TEST_P(SvcRateAllocatorTestParametrizedContentType, StableBitrate) {
433 ScopedFieldTrials field_trial(
434 "WebRTC-StableTargetRate/enabled:true,video_hysteresis_factor:1.0,"
435 "screenshare_hysteresis_factor:1.0/");
436
437 const VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_);
438 const auto start_rates = SvcRateAllocator::GetLayerStartBitrates(codec);
439 const DataRate min_rate_two_layers = start_rates[1];
440 const DataRate min_rate_three_layers = start_rates[2];
441
442 const DataRate max_rate_one_layer =
443 DataRate::KilobitsPerSec(codec.spatialLayers[0].maxBitrate);
444 const DataRate max_rate_two_layers =
445 is_screen_sharing_
446 ? DataRate::KilobitsPerSec(codec.spatialLayers[0].targetBitrate +
447 codec.spatialLayers[1].maxBitrate)
448 : DataRate::KilobitsPerSec(codec.spatialLayers[0].maxBitrate +
449 codec.spatialLayers[1].maxBitrate);
450
451 SvcRateAllocator allocator = SvcRateAllocator(codec);
452
453 // Two layers, stable and target equal.
454 auto allocation = allocator.Allocate(VideoBitrateAllocationParameters(
455 /*total_bitrate=*/min_rate_two_layers,
456 /*stable_bitrate=*/min_rate_two_layers, /*fps=*/30.0));
457 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
458 EXPECT_EQ(allocation.get_sum_bps(), min_rate_two_layers.bps());
459
460 // Two layers, stable bitrate too low for two layers.
461 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
462 /*total_bitrate=*/min_rate_two_layers,
463 /*stable_bitrate=*/min_rate_two_layers - DataRate::BitsPerSec(1),
464 /*fps=*/30.0));
465 EXPECT_FALSE(allocation.IsSpatialLayerUsed(1));
466 EXPECT_EQ(DataRate::BitsPerSec(allocation.get_sum_bps()),
467 std::min(min_rate_two_layers - DataRate::BitsPerSec(1),
468 max_rate_one_layer));
469
470 // Three layers, stable and target equal.
471 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
472 /*total_bitrate=*/min_rate_three_layers,
473 /*stable_bitrate=*/min_rate_three_layers, /*fps=*/30.0));
474 EXPECT_TRUE(allocation.IsSpatialLayerUsed(2));
475 EXPECT_EQ(allocation.get_sum_bps(), min_rate_three_layers.bps());
476
477 // Three layers, stable bitrate too low for three layers.
478 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
479 /*total_bitrate=*/min_rate_three_layers,
480 /*stable_bitrate=*/min_rate_three_layers - DataRate::BitsPerSec(1),
481 /*fps=*/30.0));
482 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
483 EXPECT_EQ(DataRate::BitsPerSec(allocation.get_sum_bps()),
484 std::min(min_rate_three_layers - DataRate::BitsPerSec(1),
485 max_rate_two_layers));
486 }
487
TEST_P(SvcRateAllocatorTestParametrizedContentType,StableBitrateWithHysteresis)488 TEST_P(SvcRateAllocatorTestParametrizedContentType,
489 StableBitrateWithHysteresis) {
490 const VideoCodec codec = Configure(1280, 720, 3, 1, is_screen_sharing_);
491 const auto start_rates = SvcRateAllocator::GetLayerStartBitrates(codec);
492 const DataRate min_rate_single_layer = start_rates[0];
493 const DataRate min_rate_two_layers = start_rates[1];
494 const DataRate min_rate_three_layers = start_rates[2];
495
496 ScopedFieldTrials field_trial(
497 "WebRTC-StableTargetRate/enabled:true,video_hysteresis_factor:1.1,"
498 "screenshare_hysteresis_factor:1.1/");
499 SvcRateAllocator allocator = SvcRateAllocator(codec);
500 // Always use max bitrate as target, verify only stable is used for layer
501 // count selection.
502 const DataRate max_bitrate = allocator.GetMaxBitrate(codec);
503
504 // Start with a single layer.
505 auto allocation = allocator.Allocate(VideoBitrateAllocationParameters(
506 /*total_bitrate=*/max_bitrate,
507 /*stable_bitrate=*/min_rate_single_layer, /*fps=*/30.0));
508 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
509 EXPECT_FALSE(allocation.IsSpatialLayerUsed(1));
510 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
511
512 // Min bitrate not enough to enable second layer due to 10% hysteresis.
513 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
514 /*total_bitrate=*/max_bitrate,
515 /*stable_bitrate=*/min_rate_two_layers, /*fps=*/30.0));
516 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
517 EXPECT_FALSE(allocation.IsSpatialLayerUsed(1));
518 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
519
520 // Add hysteresis, second layer should turn on.
521 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
522 /*total_bitrate=*/max_bitrate,
523 /*stable_bitrate=*/min_rate_two_layers * 1.1, /*fps=*/30.0));
524 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
525 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
526 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
527
528 // Remove hysteresis, second layer should stay on.
529 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
530 /*total_bitrate=*/max_bitrate,
531 /*stable_bitrate=*/min_rate_two_layers, /*fps=*/30.0));
532 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
533 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
534 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
535
536 // Going below min for two layers, second layer should turn off again.
537 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
538 /*total_bitrate=*/max_bitrate,
539 /*stable_bitrate=*/min_rate_two_layers - DataRate::BitsPerSec(1),
540 /*fps=*/30.0));
541 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
542 EXPECT_FALSE(allocation.IsSpatialLayerUsed(1));
543 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
544
545 // Min bitrate not enough to enable third layer due to 10% hysteresis.
546 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
547 /*total_bitrate=*/max_bitrate,
548 /*stable_bitrate=*/min_rate_three_layers, /*fps=*/30.0));
549 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
550 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
551 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
552
553 // Add hysteresis, third layer should turn on.
554 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
555 /*total_bitrate=*/max_bitrate,
556 /*stable_bitrate=*/min_rate_three_layers * 1.1, /*fps=*/30.0));
557 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
558 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
559 EXPECT_TRUE(allocation.IsSpatialLayerUsed(2));
560
561 // Remove hysteresis, third layer should stay on.
562 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
563 /*total_bitrate=*/max_bitrate,
564 /*stable_bitrate=*/min_rate_three_layers, /*fps=*/30.0));
565 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
566 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
567 EXPECT_TRUE(allocation.IsSpatialLayerUsed(2));
568
569 // Going below min for three layers, third layer should turn off again.
570 allocation = allocator.Allocate(VideoBitrateAllocationParameters(
571 /*total_bitrate=*/max_bitrate,
572 /*stable_bitrate=*/min_rate_three_layers - DataRate::BitsPerSec(1),
573 /*fps=*/30.0));
574 EXPECT_TRUE(allocation.IsSpatialLayerUsed(0));
575 EXPECT_TRUE(allocation.IsSpatialLayerUsed(1));
576 EXPECT_FALSE(allocation.IsSpatialLayerUsed(2));
577 }
578
579 INSTANTIATE_TEST_SUITE_P(_,
580 SvcRateAllocatorTestParametrizedContentType,
581 ::testing::Bool());
582
583 } // namespace test
584 } // namespace webrtc
585