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