1 /*
2 * Copyright (c) 2016 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 "webrtc/modules/video_coding/utility/simulcast_rate_allocator.h"
12
13 #include <limits>
14 #include <memory>
15 #include <utility>
16 #include <vector>
17
18 #include "webrtc/test/gmock.h"
19 #include "webrtc/test/gtest.h"
20
21 namespace webrtc {
22 namespace {
23 using ::testing::_;
24
25 constexpr uint32_t kMinBitrateKbps = 50;
26 constexpr uint32_t kTargetBitrateKbps = 100;
27 constexpr uint32_t kMaxBitrateKbps = 1000;
28 constexpr uint32_t kFramerateFps = 5;
29
30 class MockTemporalLayers : public TemporalLayers {
31 public:
32 MOCK_METHOD1(EncodeFlags, int(uint32_t));
33 MOCK_METHOD3(OnRatesUpdated, std::vector<uint32_t>(int, int, int));
34 MOCK_METHOD1(UpdateConfiguration, bool(vpx_codec_enc_cfg_t*));
35 MOCK_METHOD3(PopulateCodecSpecific,
36 void(bool, CodecSpecificInfoVP8*, uint32_t));
37 MOCK_METHOD3(FrameEncoded, void(unsigned int, uint32_t, int));
38 MOCK_CONST_METHOD0(CurrentLayerId, int());
39 };
40 } // namespace
41
42 class SimulcastRateAllocatorTest : public ::testing::TestWithParam<bool> {
43 public:
SimulcastRateAllocatorTest()44 SimulcastRateAllocatorTest() {
45 memset(&codec_, 0, sizeof(VideoCodec));
46 codec_.minBitrate = kMinBitrateKbps;
47 codec_.targetBitrate = kTargetBitrateKbps;
48 codec_.maxBitrate = kMaxBitrateKbps;
49 CreateAllocator();
50 }
~SimulcastRateAllocatorTest()51 virtual ~SimulcastRateAllocatorTest() {}
52
53 template <size_t S>
ExpectEqual(uint32_t (& expected)[S],const std::vector<uint32_t> & actual)54 void ExpectEqual(uint32_t (&expected)[S],
55 const std::vector<uint32_t>& actual) {
56 EXPECT_EQ(S, actual.size());
57 for (size_t i = 0; i < S; ++i)
58 EXPECT_EQ(expected[i], actual[i]) << "Mismatch at index " << i;
59 }
60
61 template <size_t S>
ExpectEqual(uint32_t (& expected)[S],const BitrateAllocation & actual)62 void ExpectEqual(uint32_t (&expected)[S], const BitrateAllocation& actual) {
63 // EXPECT_EQ(S, actual.size());
64 uint32_t sum = 0;
65 for (size_t i = 0; i < S; ++i) {
66 uint32_t layer_bitrate = actual.GetSpatialLayerSum(i);
67 EXPECT_EQ(expected[i] * 1000U, layer_bitrate) << "Mismatch at index "
68 << i;
69 sum += layer_bitrate;
70 }
71 EXPECT_EQ(sum, actual.get_sum_bps());
72 }
73
CreateAllocator()74 void CreateAllocator() {
75 std::unique_ptr<TemporalLayersFactory> tl_factory(GetTlFactory());
76 codec_.VP8()->tl_factory = tl_factory.get();
77 allocator_.reset(new SimulcastRateAllocator(codec_, std::move(tl_factory)));
78
79 // Simulate InitEncode().
80 tl_factories_.clear();
81 if (codec_.numberOfSimulcastStreams == 0) {
82 tl_factories_.push_back(
83 std::unique_ptr<TemporalLayers>(codec_.VP8()->tl_factory->Create(
84 0, codec_.VP8()->numberOfTemporalLayers, 0)));
85 } else {
86 for (uint32_t i = 0; i < codec_.numberOfSimulcastStreams; ++i) {
87 tl_factories_.push_back(
88 std::unique_ptr<TemporalLayers>(codec_.VP8()->tl_factory->Create(
89 i, codec_.simulcastStream[i].numberOfTemporalLayers, 0)));
90 }
91 }
92 }
93
GetTlFactory()94 virtual std::unique_ptr<TemporalLayersFactory> GetTlFactory() {
95 return std::unique_ptr<TemporalLayersFactory>(new TemporalLayersFactory());
96 }
97
GetAllocation(uint32_t target_bitrate)98 BitrateAllocation GetAllocation(uint32_t target_bitrate) {
99 return allocator_->GetAllocation(target_bitrate * 1000U, kDefaultFrameRate);
100 }
101
102 protected:
103 static const int kDefaultFrameRate = 30;
104 VideoCodec codec_;
105 std::unique_ptr<SimulcastRateAllocator> allocator_;
106 std::vector<std::unique_ptr<TemporalLayers>> tl_factories_;
107 };
108
TEST_F(SimulcastRateAllocatorTest,NoSimulcastBelowMin)109 TEST_F(SimulcastRateAllocatorTest, NoSimulcastBelowMin) {
110 uint32_t expected[] = {codec_.minBitrate};
111 ExpectEqual(expected, GetAllocation(codec_.minBitrate - 1));
112 ExpectEqual(expected, GetAllocation(1));
113 ExpectEqual(expected, GetAllocation(0));
114 }
115
TEST_F(SimulcastRateAllocatorTest,NoSimulcastAboveMax)116 TEST_F(SimulcastRateAllocatorTest, NoSimulcastAboveMax) {
117 uint32_t expected[] = {codec_.maxBitrate};
118 ExpectEqual(expected, GetAllocation(codec_.maxBitrate + 1));
119 ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
120 }
121
TEST_F(SimulcastRateAllocatorTest,NoSimulcastNoMax)122 TEST_F(SimulcastRateAllocatorTest, NoSimulcastNoMax) {
123 const uint32_t kMax = BitrateAllocation::kMaxBitrateBps / 1000;
124 codec_.maxBitrate = 0;
125 CreateAllocator();
126
127 uint32_t expected[] = {kMax};
128 ExpectEqual(expected, GetAllocation(kMax));
129 }
130
TEST_F(SimulcastRateAllocatorTest,NoSimulcastWithinLimits)131 TEST_F(SimulcastRateAllocatorTest, NoSimulcastWithinLimits) {
132 for (uint32_t bitrate = codec_.minBitrate; bitrate <= codec_.maxBitrate;
133 ++bitrate) {
134 uint32_t expected[] = {bitrate};
135 ExpectEqual(expected, GetAllocation(bitrate));
136 }
137 }
138
TEST_F(SimulcastRateAllocatorTest,SingleSimulcastBelowMin)139 TEST_F(SimulcastRateAllocatorTest, SingleSimulcastBelowMin) {
140 // With simulcast, use the min bitrate from the ss spec instead of the global.
141 codec_.numberOfSimulcastStreams = 1;
142 const uint32_t kMin = codec_.minBitrate - 10;
143 codec_.simulcastStream[0].minBitrate = kMin;
144 codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
145 CreateAllocator();
146
147 uint32_t expected[] = {kMin};
148 ExpectEqual(expected, GetAllocation(kMin - 1));
149 ExpectEqual(expected, GetAllocation(1));
150 ExpectEqual(expected, GetAllocation(0));
151 }
152
TEST_F(SimulcastRateAllocatorTest,SingleSimulcastAboveMax)153 TEST_F(SimulcastRateAllocatorTest, SingleSimulcastAboveMax) {
154 codec_.numberOfSimulcastStreams = 1;
155 codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
156 const uint32_t kMax = codec_.simulcastStream[0].maxBitrate + 1000;
157 codec_.simulcastStream[0].maxBitrate = kMax;
158 CreateAllocator();
159
160 uint32_t expected[] = {kMax};
161 ExpectEqual(expected, GetAllocation(kMax));
162 ExpectEqual(expected, GetAllocation(kMax + 1));
163 ExpectEqual(expected, GetAllocation(std::numeric_limits<uint32_t>::max()));
164 }
165
TEST_F(SimulcastRateAllocatorTest,SingleSimulcastWithinLimits)166 TEST_F(SimulcastRateAllocatorTest, SingleSimulcastWithinLimits) {
167 codec_.numberOfSimulcastStreams = 1;
168 codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
169 codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
170 codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
171 CreateAllocator();
172
173 for (uint32_t bitrate = kMinBitrateKbps; bitrate <= kMaxBitrateKbps;
174 ++bitrate) {
175 uint32_t expected[] = {bitrate};
176 ExpectEqual(expected, GetAllocation(bitrate));
177 }
178 }
179
TEST_F(SimulcastRateAllocatorTest,OneToThreeStreams)180 TEST_F(SimulcastRateAllocatorTest, OneToThreeStreams) {
181 codec_.numberOfSimulcastStreams = 3;
182 codec_.maxBitrate = 0;
183 codec_.simulcastStream[0].minBitrate = 10;
184 codec_.simulcastStream[0].targetBitrate = 100;
185 codec_.simulcastStream[0].maxBitrate = 500;
186 codec_.simulcastStream[1].minBitrate = 50;
187 codec_.simulcastStream[1].targetBitrate = 500;
188 codec_.simulcastStream[1].maxBitrate = 1000;
189 codec_.simulcastStream[2].minBitrate = 2000;
190 codec_.simulcastStream[2].targetBitrate = 3000;
191 codec_.simulcastStream[2].maxBitrate = 4000;
192 CreateAllocator();
193
194 {
195 // Single stream, min bitrate.
196 const uint32_t bitrate = codec_.simulcastStream[0].minBitrate;
197 uint32_t expected[] = {bitrate, 0, 0};
198 ExpectEqual(expected, GetAllocation(bitrate));
199 }
200
201 {
202 // Single stream at target bitrate.
203 const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate;
204 uint32_t expected[] = {bitrate, 0, 0};
205 ExpectEqual(expected, GetAllocation(bitrate));
206 }
207
208 {
209 // Bitrate above target for first stream, but below min for the next one.
210 const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
211 codec_.simulcastStream[1].minBitrate - 1;
212 uint32_t expected[] = {bitrate, 0, 0};
213 ExpectEqual(expected, GetAllocation(bitrate));
214 }
215
216 {
217 // Just enough for two streams.
218 const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
219 codec_.simulcastStream[1].minBitrate;
220 uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
221 codec_.simulcastStream[1].minBitrate, 0};
222 ExpectEqual(expected, GetAllocation(bitrate));
223 }
224
225 {
226 // Second stream maxed out, but not enough for third.
227 const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
228 codec_.simulcastStream[1].maxBitrate;
229 uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
230 codec_.simulcastStream[1].maxBitrate, 0};
231 ExpectEqual(expected, GetAllocation(bitrate));
232 }
233
234 {
235 // First two streams maxed out, but not enough for third. Nowhere to put
236 // remaining bits.
237 const uint32_t bitrate = codec_.simulcastStream[0].maxBitrate +
238 codec_.simulcastStream[1].maxBitrate + 499;
239 uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
240 codec_.simulcastStream[1].maxBitrate, 0};
241 ExpectEqual(expected, GetAllocation(bitrate));
242 }
243
244 {
245 // Just enough for all three streams.
246 const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
247 codec_.simulcastStream[1].targetBitrate +
248 codec_.simulcastStream[2].minBitrate;
249 uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
250 codec_.simulcastStream[1].targetBitrate,
251 codec_.simulcastStream[2].minBitrate};
252 ExpectEqual(expected, GetAllocation(bitrate));
253 }
254
255 {
256 // Third maxed out.
257 const uint32_t bitrate = codec_.simulcastStream[0].targetBitrate +
258 codec_.simulcastStream[1].targetBitrate +
259 codec_.simulcastStream[2].maxBitrate;
260 uint32_t expected[] = {codec_.simulcastStream[0].targetBitrate,
261 codec_.simulcastStream[1].targetBitrate,
262 codec_.simulcastStream[2].maxBitrate};
263 ExpectEqual(expected, GetAllocation(bitrate));
264 }
265 }
266
TEST_F(SimulcastRateAllocatorTest,GetPreferredBitrateBps)267 TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateBps) {
268 MockTemporalLayers mock_layers;
269 allocator_.reset(new SimulcastRateAllocator(codec_, nullptr));
270 allocator_->OnTemporalLayersCreated(0, &mock_layers);
271 EXPECT_CALL(mock_layers, OnRatesUpdated(_, _, _)).Times(0);
272 EXPECT_EQ(codec_.maxBitrate * 1000,
273 allocator_->GetPreferredBitrateBps(codec_.maxFramerate));
274 }
275
TEST_F(SimulcastRateAllocatorTest,GetPreferredBitrateSimulcast)276 TEST_F(SimulcastRateAllocatorTest, GetPreferredBitrateSimulcast) {
277 codec_.numberOfSimulcastStreams = 3;
278 codec_.maxBitrate = 999999;
279 codec_.simulcastStream[0].minBitrate = 10;
280 codec_.simulcastStream[0].targetBitrate = 100;
281
282 codec_.simulcastStream[0].maxBitrate = 500;
283 codec_.simulcastStream[1].minBitrate = 50;
284 codec_.simulcastStream[1].targetBitrate = 500;
285 codec_.simulcastStream[1].maxBitrate = 1000;
286
287 codec_.simulcastStream[2].minBitrate = 2000;
288 codec_.simulcastStream[2].targetBitrate = 3000;
289 codec_.simulcastStream[2].maxBitrate = 4000;
290 CreateAllocator();
291
292 uint32_t preferred_bitrate_kbps;
293 preferred_bitrate_kbps = codec_.simulcastStream[0].targetBitrate;
294 preferred_bitrate_kbps += codec_.simulcastStream[1].targetBitrate;
295 preferred_bitrate_kbps += codec_.simulcastStream[2].maxBitrate;
296
297 EXPECT_EQ(preferred_bitrate_kbps * 1000,
298 allocator_->GetPreferredBitrateBps(codec_.maxFramerate));
299 }
300
301 class ScreenshareRateAllocationTest : public SimulcastRateAllocatorTest {
302 public:
SetupConferenceScreenshare(bool use_simulcast)303 void SetupConferenceScreenshare(bool use_simulcast) {
304 codec_.mode = VideoCodecMode::kScreensharing;
305 codec_.minBitrate = kMinBitrateKbps;
306 codec_.maxBitrate = kMaxBitrateKbps;
307 if (use_simulcast) {
308 codec_.numberOfSimulcastStreams = 1;
309 codec_.simulcastStream[0].minBitrate = kMinBitrateKbps;
310 codec_.simulcastStream[0].targetBitrate = kTargetBitrateKbps;
311 codec_.simulcastStream[0].maxBitrate = kMaxBitrateKbps;
312 codec_.simulcastStream[0].numberOfTemporalLayers = 2;
313 } else {
314 codec_.numberOfSimulcastStreams = 0;
315 codec_.targetBitrate = kTargetBitrateKbps;
316 codec_.VP8()->numberOfTemporalLayers = 2;
317 }
318 }
319
GetTlFactory()320 std::unique_ptr<TemporalLayersFactory> GetTlFactory() override {
321 return std::unique_ptr<TemporalLayersFactory>(
322 new ScreenshareTemporalLayersFactory());
323 }
324 };
325
326 INSTANTIATE_TEST_CASE_P(ScreenshareTest,
327 ScreenshareRateAllocationTest,
328 ::testing::Bool());
329
TEST_P(ScreenshareRateAllocationTest,BitrateBelowTl0)330 TEST_P(ScreenshareRateAllocationTest, BitrateBelowTl0) {
331 SetupConferenceScreenshare(GetParam());
332 CreateAllocator();
333
334 BitrateAllocation allocation =
335 allocator_->GetAllocation(kTargetBitrateKbps * 1000, kFramerateFps);
336
337 // All allocation should go in TL0.
338 EXPECT_EQ(kTargetBitrateKbps, allocation.get_sum_kbps());
339 EXPECT_EQ(kTargetBitrateKbps, allocation.GetBitrate(0, 0) / 1000);
340 }
341
TEST_P(ScreenshareRateAllocationTest,BitrateAboveTl0)342 TEST_P(ScreenshareRateAllocationTest, BitrateAboveTl0) {
343 SetupConferenceScreenshare(GetParam());
344 CreateAllocator();
345
346 uint32_t target_bitrate_kbps = (kTargetBitrateKbps + kMaxBitrateKbps) / 2;
347 BitrateAllocation allocation =
348 allocator_->GetAllocation(target_bitrate_kbps * 1000, kFramerateFps);
349
350 // Fill TL0, then put the rest in TL1.
351 EXPECT_EQ(target_bitrate_kbps, allocation.get_sum_kbps());
352 EXPECT_EQ(kTargetBitrateKbps, allocation.GetBitrate(0, 0) / 1000);
353 EXPECT_EQ(target_bitrate_kbps - kTargetBitrateKbps,
354 allocation.GetBitrate(0, 1) / 1000);
355 }
356
TEST_P(ScreenshareRateAllocationTest,BitrateAboveTl1)357 TEST_P(ScreenshareRateAllocationTest, BitrateAboveTl1) {
358 SetupConferenceScreenshare(GetParam());
359 CreateAllocator();
360
361 BitrateAllocation allocation =
362 allocator_->GetAllocation(kMaxBitrateKbps * 2000, kFramerateFps);
363
364 // Fill both TL0 and TL1, but no more.
365 EXPECT_EQ(kMaxBitrateKbps, allocation.get_sum_kbps());
366 EXPECT_EQ(kTargetBitrateKbps, allocation.GetBitrate(0, 0) / 1000);
367 EXPECT_EQ(kMaxBitrateKbps - kTargetBitrateKbps,
368 allocation.GetBitrate(0, 1) / 1000);
369 }
370
371 } // namespace webrtc
372