• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "media/engine/simulcast.h"
12 
13 #include "media/base/media_constants.h"
14 #include "media/engine/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 
84   const size_t kMinLayers = 1;
85   const size_t kMaxLayers = 3;
86   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
87       kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
88       !kScreenshare, true);
89 
90   EXPECT_EQ(kMaxLayers, streams.size());
91   EXPECT_EQ(320u, streams[0].width);
92   EXPECT_EQ(180u, streams[0].height);
93   EXPECT_EQ(640u, streams[1].width);
94   EXPECT_EQ(360u, streams[1].height);
95   EXPECT_EQ(1280u, streams[2].width);
96   EXPECT_EQ(720u, streams[2].height);
97 
98   for (size_t i = 0; i < streams.size(); ++i) {
99     EXPECT_EQ(size_t{kDefaultTemporalLayers}, streams[i].num_temporal_layers);
100     EXPECT_EQ(cricket::kDefaultVideoMaxFramerate, streams[i].max_framerate);
101     EXPECT_EQ(kQpMax, streams[i].max_qp);
102     EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps);
103     EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps);
104     EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps);
105     EXPECT_TRUE(streams[i].active);
106   }
107   // Currently set on lowest stream.
108   EXPECT_EQ(kBitratePriority, streams[0].bitrate_priority);
109   EXPECT_FALSE(streams[1].bitrate_priority);
110   EXPECT_FALSE(streams[2].bitrate_priority);
111 }
112 
TEST(SimulcastTest,GetConfigWithBaseHeavyVP8TL3RateAllocation)113 TEST(SimulcastTest, GetConfigWithBaseHeavyVP8TL3RateAllocation) {
114   test::ScopedFieldTrials field_trials(
115       "WebRTC-UseBaseHeavyVP8TL3RateAllocation/Enabled/");
116 
117   const std::vector<VideoStream> kExpected = GetSimulcastBitrates720p();
118 
119   const size_t kMinLayers = 1;
120   const size_t kMaxLayers = 3;
121   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
122       kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
123       !kScreenshare, true);
124 
125   EXPECT_EQ(kExpected[0].min_bitrate_bps, streams[0].min_bitrate_bps);
126   EXPECT_EQ(static_cast<int>(0.4 * kExpected[0].target_bitrate_bps / 0.6),
127             streams[0].target_bitrate_bps);
128   EXPECT_EQ(static_cast<int>(0.4 * kExpected[0].max_bitrate_bps / 0.6),
129             streams[0].max_bitrate_bps);
130   for (size_t i = 1; i < streams.size(); ++i) {
131     EXPECT_EQ(kExpected[i].min_bitrate_bps, streams[i].min_bitrate_bps);
132     EXPECT_EQ(kExpected[i].target_bitrate_bps, streams[i].target_bitrate_bps);
133     EXPECT_EQ(kExpected[i].max_bitrate_bps, streams[i].max_bitrate_bps);
134   }
135 }
136 
TEST(SimulcastTest,GetConfigWithLimitedMaxLayers)137 TEST(SimulcastTest, GetConfigWithLimitedMaxLayers) {
138   const size_t kMinLayers = 1;
139   const size_t kMaxLayers = 2;
140   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
141       kMinLayers, kMaxLayers, 1280, 720, kBitratePriority, kQpMax,
142       !kScreenshare, true);
143 
144   EXPECT_EQ(kMaxLayers, streams.size());
145   EXPECT_EQ(640u, streams[0].width);
146   EXPECT_EQ(360u, streams[0].height);
147   EXPECT_EQ(1280u, streams[1].width);
148   EXPECT_EQ(720u, streams[1].height);
149 }
150 
TEST(SimulcastTest,GetConfigWithLimitedMaxLayersForResolution)151 TEST(SimulcastTest, GetConfigWithLimitedMaxLayersForResolution) {
152   test::ScopedFieldTrials field_trials(
153       "WebRTC-LegacySimulcastLayerLimit/Enabled/");
154   const size_t kMinLayers = 1;
155   const size_t kMaxLayers = 3;
156   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
157       kMinLayers, kMaxLayers, 800, 600, kBitratePriority, kQpMax, !kScreenshare,
158       true);
159 
160   EXPECT_EQ(2u, streams.size());
161   EXPECT_EQ(400u, streams[0].width);
162   EXPECT_EQ(300u, streams[0].height);
163   EXPECT_EQ(800u, streams[1].width);
164   EXPECT_EQ(600u, streams[1].height);
165 }
166 
TEST(SimulcastTest,GetConfigWithLowResolutionScreenshare)167 TEST(SimulcastTest, GetConfigWithLowResolutionScreenshare) {
168   test::ScopedFieldTrials field_trials(
169       "WebRTC-LegacySimulcastLayerLimit/Enabled/");
170   const size_t kMinLayers = 1;
171   const size_t kMaxLayers = 3;
172   std::vector<VideoStream> streams =
173       cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 100, 100,
174                                   kBitratePriority, kQpMax, kScreenshare, true);
175 
176   // Simulcast streams number is never decreased for screenshare,
177   // even for very low resolution.
178   EXPECT_GT(streams.size(), 1u);
179 }
180 
TEST(SimulcastTest,GetConfigWithNotLimitedMaxLayersForResolution)181 TEST(SimulcastTest, GetConfigWithNotLimitedMaxLayersForResolution) {
182   test::ScopedFieldTrials field_trials(
183       "WebRTC-LegacySimulcastLayerLimit/Disabled/");
184   const size_t kMinLayers = 1;
185   const size_t kMaxLayers = 3;
186   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
187       kMinLayers, kMaxLayers, 800, 600, kBitratePriority, kQpMax, !kScreenshare,
188       true);
189 
190   EXPECT_EQ(kMaxLayers, streams.size());
191   EXPECT_EQ(200u, streams[0].width);
192   EXPECT_EQ(150u, streams[0].height);
193   EXPECT_EQ(400u, streams[1].width);
194   EXPECT_EQ(300u, streams[1].height);
195   EXPECT_EQ(800u, streams[2].width);
196   EXPECT_EQ(600u, streams[2].height);
197 }
198 
TEST(SimulcastTest,GetConfigWithNormalizedResolution)199 TEST(SimulcastTest, GetConfigWithNormalizedResolution) {
200   const size_t kMinLayers = 1;
201   const size_t kMaxLayers = 2;
202   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
203       kMinLayers, kMaxLayers, 640 + 1, 360 + 1, kBitratePriority, kQpMax,
204       !kScreenshare, true);
205 
206   // Must be divisible by |2 ^ (num_layers - 1)|.
207   EXPECT_EQ(kMaxLayers, streams.size());
208   EXPECT_EQ(320u, streams[0].width);
209   EXPECT_EQ(180u, streams[0].height);
210   EXPECT_EQ(640u, streams[1].width);
211   EXPECT_EQ(360u, streams[1].height);
212 }
213 
TEST(SimulcastTest,GetConfigWithNormalizedResolutionDivisibleBy4)214 TEST(SimulcastTest, GetConfigWithNormalizedResolutionDivisibleBy4) {
215   test::ScopedFieldTrials field_trials(
216       "WebRTC-NormalizeSimulcastResolution/Enabled-2/");
217 
218   const size_t kMinLayers = 1;
219   const size_t kMaxLayers = 2;
220   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
221       kMinLayers, kMaxLayers, 709, 501, kBitratePriority, kQpMax, !kScreenshare,
222       true);
223 
224   // Must be divisible by |2 ^ 2|.
225   EXPECT_EQ(kMaxLayers, streams.size());
226   EXPECT_EQ(354u, streams[0].width);
227   EXPECT_EQ(250u, streams[0].height);
228   EXPECT_EQ(708u, streams[1].width);
229   EXPECT_EQ(500u, streams[1].height);
230 }
231 
TEST(SimulcastTest,GetConfigWithNormalizedResolutionDivisibleBy8)232 TEST(SimulcastTest, GetConfigWithNormalizedResolutionDivisibleBy8) {
233   test::ScopedFieldTrials field_trials(
234       "WebRTC-NormalizeSimulcastResolution/Enabled-3/");
235 
236   const size_t kMinLayers = 1;
237   const size_t kMaxLayers = 2;
238   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
239       kMinLayers, kMaxLayers, 709, 501, kBitratePriority, kQpMax, !kScreenshare,
240       true);
241 
242   // Must be divisible by |2 ^ 3|.
243   EXPECT_EQ(kMaxLayers, streams.size());
244   EXPECT_EQ(352u, streams[0].width);
245   EXPECT_EQ(248u, streams[0].height);
246   EXPECT_EQ(704u, streams[1].width);
247   EXPECT_EQ(496u, streams[1].height);
248 }
249 
TEST(SimulcastTest,GetConfigForLegacyLayerLimit)250 TEST(SimulcastTest, GetConfigForLegacyLayerLimit) {
251   test::ScopedFieldTrials field_trials(
252       "WebRTC-LegacySimulcastLayerLimit/Enabled/");
253 
254   const size_t kMinLayers = 1;
255   const int kMaxLayers = 3;
256   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
257       kMinLayers, kMaxLayers, 320, 180, kBitratePriority, kQpMax, !kScreenshare,
258       true);
259   EXPECT_EQ(1u, streams.size());
260 
261   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
262                                         kBitratePriority, kQpMax, !kScreenshare,
263                                         true);
264   EXPECT_EQ(2u, streams.size());
265 
266   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
267                                         kBitratePriority, kQpMax, !kScreenshare,
268                                         true);
269   EXPECT_EQ(3u, streams.size());
270 }
271 
TEST(SimulcastTest,GetConfigForLegacyLayerLimitWithRequiredHD)272 TEST(SimulcastTest, GetConfigForLegacyLayerLimitWithRequiredHD) {
273   test::ScopedFieldTrials field_trials(
274       "WebRTC-LegacySimulcastLayerLimit/Enabled/");
275 
276   const size_t kMinLayers = 3;  // "HD" layer must be present!
277   const int kMaxLayers = 3;
278   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
279       kMinLayers, kMaxLayers, 320, 180, kBitratePriority, kQpMax, !kScreenshare,
280       true);
281   EXPECT_EQ(3u, streams.size());
282 
283   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 640, 360,
284                                         kBitratePriority, kQpMax, !kScreenshare,
285                                         true);
286   EXPECT_EQ(3u, streams.size());
287 
288   streams = cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
289                                         kBitratePriority, kQpMax, !kScreenshare,
290                                         true);
291   EXPECT_EQ(3u, streams.size());
292 }
293 
TEST(SimulcastTest,GetConfigForScreenshareSimulcast)294 TEST(SimulcastTest, GetConfigForScreenshareSimulcast) {
295   const size_t kMinLayers = 1;
296   const size_t kMaxLayers = 3;
297   std::vector<VideoStream> streams =
298       cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1400, 800,
299                                   kBitratePriority, kQpMax, kScreenshare, true);
300 
301   EXPECT_GT(streams.size(), 1u);
302   for (size_t i = 0; i < streams.size(); ++i) {
303     EXPECT_EQ(1400u, streams[i].width) << "Screen content never scaled.";
304     EXPECT_EQ(800u, streams[i].height) << "Screen content never scaled.";
305     EXPECT_EQ(kQpMax, streams[i].max_qp);
306     EXPECT_TRUE(streams[i].active);
307     EXPECT_GT(streams[i].num_temporal_layers, size_t{1});
308     EXPECT_GT(streams[i].max_framerate, 0);
309     EXPECT_GT(streams[i].min_bitrate_bps, 0);
310     EXPECT_GT(streams[i].target_bitrate_bps, streams[i].min_bitrate_bps);
311     EXPECT_GE(streams[i].max_bitrate_bps, streams[i].target_bitrate_bps);
312   }
313 }
314 
TEST(SimulcastTest,GetConfigForScreenshareSimulcastWithLimitedMaxLayers)315 TEST(SimulcastTest, GetConfigForScreenshareSimulcastWithLimitedMaxLayers) {
316   const size_t kMinLayers = 1;
317   const size_t kMaxLayers = 1;
318   std::vector<VideoStream> streams =
319       cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1400, 800,
320                                   kBitratePriority, kQpMax, kScreenshare, true);
321 
322   EXPECT_EQ(kMaxLayers, streams.size());
323 }
324 
TEST(SimulcastTest,SimulcastScreenshareMaxBitrateAdjustedForResolution)325 TEST(SimulcastTest, SimulcastScreenshareMaxBitrateAdjustedForResolution) {
326   constexpr int kScreenshareHighStreamMinBitrateBps = 600000;
327   constexpr int kScreenshareHighStreamMaxBitrateBps = 1250000;
328   constexpr int kMaxBitrate960_540 = 1200000;
329 
330   // Normal case, max bitrate not limited by resolution.
331   const size_t kMinLayers = 1;
332   const size_t kMaxLayers = 2;
333   std::vector<VideoStream> streams =
334       cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 1920, 1080,
335                                   kBitratePriority, kQpMax, kScreenshare, true);
336   EXPECT_EQ(kMaxLayers, streams.size());
337   EXPECT_EQ(streams[1].max_bitrate_bps, kScreenshareHighStreamMaxBitrateBps);
338   EXPECT_EQ(streams[1].min_bitrate_bps, kScreenshareHighStreamMinBitrateBps);
339   EXPECT_GE(streams[1].max_bitrate_bps, streams[1].min_bitrate_bps);
340 
341   // At 960x540, the max bitrate is limited to 900kbps.
342   streams =
343       cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 960, 540,
344                                   kBitratePriority, kQpMax, kScreenshare, true);
345   EXPECT_EQ(kMaxLayers, streams.size());
346   EXPECT_EQ(streams[1].max_bitrate_bps, kMaxBitrate960_540);
347   EXPECT_EQ(streams[1].min_bitrate_bps, kScreenshareHighStreamMinBitrateBps);
348   EXPECT_GE(streams[1].max_bitrate_bps, streams[1].min_bitrate_bps);
349 
350   // At 480x270, the max bitrate is limited to 450kbps. This is lower than
351   // the min bitrate, so use that as a lower bound.
352   streams =
353       cricket::GetSimulcastConfig(kMinLayers, kMaxLayers, 480, 270,
354                                   kBitratePriority, kQpMax, kScreenshare, true);
355   EXPECT_EQ(kMaxLayers, streams.size());
356   EXPECT_EQ(streams[1].max_bitrate_bps, kScreenshareHighStreamMinBitrateBps);
357   EXPECT_EQ(streams[1].min_bitrate_bps, kScreenshareHighStreamMinBitrateBps);
358   EXPECT_GE(streams[1].max_bitrate_bps, streams[1].min_bitrate_bps);
359 }
360 
TEST(SimulcastTest,AveragesBitratesForNonStandardResolution)361 TEST(SimulcastTest, AveragesBitratesForNonStandardResolution) {
362   const size_t kMinLayers = 1;
363   const size_t kMaxLayers = 3;
364   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
365       kMinLayers, kMaxLayers, 900, 800, kBitratePriority, kQpMax, !kScreenshare,
366       true);
367 
368   EXPECT_EQ(kMaxLayers, streams.size());
369   EXPECT_EQ(900u, streams[2].width);
370   EXPECT_EQ(800u, streams[2].height);
371   EXPECT_EQ(1850000, streams[2].max_bitrate_bps);
372   EXPECT_EQ(1850000, streams[2].target_bitrate_bps);
373   EXPECT_EQ(475000, streams[2].min_bitrate_bps);
374 }
375 
TEST(SimulcastTest,BitratesForCloseToStandardResolution)376 TEST(SimulcastTest, BitratesForCloseToStandardResolution) {
377   const size_t kMinLayers = 1;
378   const size_t kMaxLayers = 3;
379   // Resolution very close to 720p in number of pixels
380   const size_t kWidth = 1280;
381   const size_t kHeight = 716;
382   const std::vector<VideoStream> kExpectedNear = GetSimulcastBitrates720p();
383 
384   std::vector<VideoStream> streams = cricket::GetSimulcastConfig(
385       kMinLayers, kMaxLayers, kWidth, kHeight, kBitratePriority, kQpMax,
386       !kScreenshare, true);
387 
388   EXPECT_EQ(kMaxLayers, streams.size());
389   EXPECT_EQ(kWidth, streams[2].width);
390   EXPECT_EQ(kHeight, streams[2].height);
391   for (size_t i = 0; i < streams.size(); ++i) {
392     EXPECT_NEAR(kExpectedNear[i].max_bitrate_bps, streams[i].max_bitrate_bps,
393                 20000);
394     EXPECT_NEAR(kExpectedNear[i].target_bitrate_bps,
395                 streams[i].target_bitrate_bps, 20000);
396     EXPECT_NEAR(kExpectedNear[i].min_bitrate_bps, streams[i].min_bitrate_bps,
397                 20000);
398   }
399 }
400 
401 }  // namespace webrtc
402