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