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