1 /*
2 * Copyright (c) 2019 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 "video/encoder_bitrate_adjuster.h"
12
13 #include <memory>
14 #include <vector>
15
16 #include "api/units/data_rate.h"
17 #include "rtc_base/fake_clock.h"
18 #include "rtc_base/numerics/safe_conversions.h"
19 #include "test/field_trial.h"
20 #include "test/gtest.h"
21
22 namespace webrtc {
23 namespace test {
24
25 class EncoderBitrateAdjusterTest : public ::testing::Test {
26 public:
27 static constexpr int64_t kWindowSizeMs = 3000;
28 static constexpr int kDefaultBitrateBps = 300000;
29 static constexpr int kDefaultFrameRateFps = 30;
30 // For network utilization higher than media utilization, loop over a
31 // sequence where the first half undershoots and the second half overshoots
32 // by the same amount.
33 static constexpr int kSequenceLength = 4;
34 static_assert(kSequenceLength % 2 == 0, "Sequence length must be even.");
35
EncoderBitrateAdjusterTest()36 EncoderBitrateAdjusterTest()
37 : target_bitrate_(DataRate::BitsPerSec(kDefaultBitrateBps)),
38 target_framerate_fps_(kDefaultFrameRateFps),
39 tl_pattern_idx_{},
40 sequence_idx_{} {}
41
42 protected:
SetUpAdjuster(size_t num_spatial_layers,size_t num_temporal_layers,bool vp9_svc)43 void SetUpAdjuster(size_t num_spatial_layers,
44 size_t num_temporal_layers,
45 bool vp9_svc) {
46 // Initialize some default VideoCodec instance with the given number of
47 // layers.
48 if (vp9_svc) {
49 codec_.codecType = VideoCodecType::kVideoCodecVP9;
50 codec_.numberOfSimulcastStreams = 1;
51 codec_.VP9()->numberOfSpatialLayers = num_spatial_layers;
52 codec_.VP9()->numberOfTemporalLayers = num_temporal_layers;
53 for (size_t si = 0; si < num_spatial_layers; ++si) {
54 codec_.spatialLayers[si].minBitrate = 100 * (1 << si);
55 codec_.spatialLayers[si].targetBitrate = 200 * (1 << si);
56 codec_.spatialLayers[si].maxBitrate = 300 * (1 << si);
57 codec_.spatialLayers[si].active = true;
58 codec_.spatialLayers[si].numberOfTemporalLayers = num_temporal_layers;
59 }
60 } else {
61 codec_.codecType = VideoCodecType::kVideoCodecVP8;
62 codec_.numberOfSimulcastStreams = num_spatial_layers;
63 codec_.VP8()->numberOfTemporalLayers = num_temporal_layers;
64 for (size_t si = 0; si < num_spatial_layers; ++si) {
65 codec_.simulcastStream[si].minBitrate = 100 * (1 << si);
66 codec_.simulcastStream[si].targetBitrate = 200 * (1 << si);
67 codec_.simulcastStream[si].maxBitrate = 300 * (1 << si);
68 codec_.simulcastStream[si].active = true;
69 codec_.simulcastStream[si].numberOfTemporalLayers = num_temporal_layers;
70 }
71 }
72
73 for (size_t si = 0; si < num_spatial_layers; ++si) {
74 encoder_info_.fps_allocation[si].resize(num_temporal_layers);
75 double fraction = 1.0;
76 for (int ti = num_temporal_layers - 1; ti >= 0; --ti) {
77 encoder_info_.fps_allocation[si][ti] = static_cast<uint8_t>(
78 VideoEncoder::EncoderInfo::kMaxFramerateFraction * fraction + 0.5);
79 fraction /= 2.0;
80 }
81 }
82
83 adjuster_ = std::make_unique<EncoderBitrateAdjuster>(codec_);
84 adjuster_->OnEncoderInfo(encoder_info_);
85 current_adjusted_allocation_ =
86 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
87 current_input_allocation_, target_framerate_fps_));
88 }
89
InsertFrames(std::vector<std::vector<double>> media_utilization_factors,int64_t duration_ms)90 void InsertFrames(std::vector<std::vector<double>> media_utilization_factors,
91 int64_t duration_ms) {
92 InsertFrames(media_utilization_factors, media_utilization_factors,
93 duration_ms);
94 }
95
InsertFrames(std::vector<std::vector<double>> media_utilization_factors,std::vector<std::vector<double>> network_utilization_factors,int64_t duration_ms)96 void InsertFrames(
97 std::vector<std::vector<double>> media_utilization_factors,
98 std::vector<std::vector<double>> network_utilization_factors,
99 int64_t duration_ms) {
100 RTC_DCHECK_EQ(media_utilization_factors.size(),
101 network_utilization_factors.size());
102
103 const int64_t start_us = rtc::TimeMicros();
104 while (rtc::TimeMicros() <
105 start_us + (duration_ms * rtc::kNumMicrosecsPerMillisec)) {
106 clock_.AdvanceTime(TimeDelta::Seconds(1) / target_framerate_fps_);
107 for (size_t si = 0; si < NumSpatialLayers(); ++si) {
108 const std::vector<int>& tl_pattern =
109 kTlPatterns[NumTemporalLayers(si) - 1];
110 const size_t ti =
111 tl_pattern[(tl_pattern_idx_[si]++) % tl_pattern.size()];
112
113 uint32_t layer_bitrate_bps =
114 current_adjusted_allocation_.GetBitrate(si, ti);
115 double layer_framerate_fps = target_framerate_fps_;
116 if (encoder_info_.fps_allocation[si].size() > ti) {
117 uint8_t layer_fps_fraction = encoder_info_.fps_allocation[si][ti];
118 if (ti > 0) {
119 // We're interested in the frame rate for this layer only, not
120 // cumulative frame rate.
121 layer_fps_fraction -= encoder_info_.fps_allocation[si][ti - 1];
122 }
123 layer_framerate_fps =
124 (target_framerate_fps_ * layer_fps_fraction) /
125 VideoEncoder::EncoderInfo::kMaxFramerateFraction;
126 }
127 double media_utilization_factor = 1.0;
128 double network_utilization_factor = 1.0;
129 if (media_utilization_factors.size() > si) {
130 RTC_DCHECK_EQ(media_utilization_factors[si].size(),
131 network_utilization_factors[si].size());
132 if (media_utilization_factors[si].size() > ti) {
133 media_utilization_factor = media_utilization_factors[si][ti];
134 network_utilization_factor = network_utilization_factors[si][ti];
135 }
136 }
137 RTC_DCHECK_GE(network_utilization_factor, media_utilization_factor);
138
139 // Frame size based on constant (media) overshoot.
140 const size_t media_frame_size = media_utilization_factor *
141 (layer_bitrate_bps / 8.0) /
142 layer_framerate_fps;
143
144 constexpr int kFramesWithPenalty = (kSequenceLength / 2) - 1;
145 RTC_DCHECK_GT(kFramesWithPenalty, 0);
146
147 // The positive/negative size diff needed to achieve network rate but
148 // not media rate penalty is the difference between the utilization
149 // factors times the media rate frame size, then scaled by the fraction
150 // between total frames and penalized frames in the sequence.
151 // Cap to media frame size to avoid negative size undershoot.
152 const size_t network_frame_size_diff_bytes = std::min(
153 media_frame_size,
154 static_cast<size_t>(
155 (((network_utilization_factor - media_utilization_factor) *
156 media_frame_size) *
157 kSequenceLength) /
158 kFramesWithPenalty +
159 0.5));
160
161 int sequence_idx = sequence_idx_[si][ti];
162 sequence_idx_[si][ti] = (sequence_idx_[si][ti] + 1) % kSequenceLength;
163 const DataSize frame_size = DataSize::Bytes(
164 (sequence_idx < kSequenceLength / 2)
165 ? media_frame_size - network_frame_size_diff_bytes
166 : media_frame_size + network_frame_size_diff_bytes);
167
168 adjuster_->OnEncodedFrame(frame_size, si, ti);
169 sequence_idx = ++sequence_idx % kSequenceLength;
170 }
171 }
172 }
173
NumSpatialLayers() const174 size_t NumSpatialLayers() const {
175 if (codec_.codecType == VideoCodecType::kVideoCodecVP9) {
176 return codec_.VP9().numberOfSpatialLayers;
177 }
178 return codec_.numberOfSimulcastStreams;
179 }
180
NumTemporalLayers(int spatial_index)181 size_t NumTemporalLayers(int spatial_index) {
182 if (codec_.codecType == VideoCodecType::kVideoCodecVP9) {
183 return codec_.spatialLayers[spatial_index].numberOfTemporalLayers;
184 }
185 return codec_.simulcastStream[spatial_index].numberOfTemporalLayers;
186 }
187
ExpectNear(const VideoBitrateAllocation & expected_allocation,const VideoBitrateAllocation & actual_allocation,double allowed_error_fraction)188 void ExpectNear(const VideoBitrateAllocation& expected_allocation,
189 const VideoBitrateAllocation& actual_allocation,
190 double allowed_error_fraction) {
191 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
192 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
193 if (expected_allocation.HasBitrate(si, ti)) {
194 EXPECT_TRUE(actual_allocation.HasBitrate(si, ti));
195 uint32_t expected_layer_bitrate_bps =
196 expected_allocation.GetBitrate(si, ti);
197 EXPECT_NEAR(expected_layer_bitrate_bps,
198 actual_allocation.GetBitrate(si, ti),
199 static_cast<uint32_t>(expected_layer_bitrate_bps *
200 allowed_error_fraction));
201 } else {
202 EXPECT_FALSE(actual_allocation.HasBitrate(si, ti));
203 }
204 }
205 }
206 }
207
MultiplyAllocation(const VideoBitrateAllocation & allocation,double factor)208 VideoBitrateAllocation MultiplyAllocation(
209 const VideoBitrateAllocation& allocation,
210 double factor) {
211 VideoBitrateAllocation multiplied_allocation;
212 for (size_t si = 0; si < kMaxSpatialLayers; ++si) {
213 for (size_t ti = 0; ti < kMaxTemporalStreams; ++ti) {
214 if (allocation.HasBitrate(si, ti)) {
215 multiplied_allocation.SetBitrate(
216 si, ti,
217 static_cast<uint32_t>(factor * allocation.GetBitrate(si, ti) +
218 0.5));
219 }
220 }
221 }
222 return multiplied_allocation;
223 }
224
225 VideoCodec codec_;
226 VideoEncoder::EncoderInfo encoder_info_;
227 std::unique_ptr<EncoderBitrateAdjuster> adjuster_;
228 VideoBitrateAllocation current_input_allocation_;
229 VideoBitrateAllocation current_adjusted_allocation_;
230 rtc::ScopedFakeClock clock_;
231 DataRate target_bitrate_;
232 double target_framerate_fps_;
233 int tl_pattern_idx_[kMaxSpatialLayers];
234 int sequence_idx_[kMaxSpatialLayers][kMaxTemporalStreams];
235
236 const std::vector<int> kTlPatterns[kMaxTemporalStreams] = {
237 {0},
238 {0, 1},
239 {0, 2, 1, 2},
240 {0, 3, 2, 3, 1, 3, 2, 3}};
241 };
242
TEST_F(EncoderBitrateAdjusterTest,SingleLayerOptimal)243 TEST_F(EncoderBitrateAdjusterTest, SingleLayerOptimal) {
244 // Single layer, well behaved encoder.
245 current_input_allocation_.SetBitrate(0, 0, 300000);
246 target_framerate_fps_ = 30;
247 SetUpAdjuster(1, 1, false);
248 InsertFrames({{1.0}}, kWindowSizeMs);
249 current_adjusted_allocation_ =
250 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
251 current_input_allocation_, target_framerate_fps_));
252 // Adjusted allocation near input. Allow 1% error margin due to rounding
253 // errors etc.
254 ExpectNear(current_input_allocation_, current_adjusted_allocation_, 0.01);
255 }
256
TEST_F(EncoderBitrateAdjusterTest,SingleLayerOveruse)257 TEST_F(EncoderBitrateAdjusterTest, SingleLayerOveruse) {
258 // Single layer, well behaved encoder.
259 current_input_allocation_.SetBitrate(0, 0, 300000);
260 target_framerate_fps_ = 30;
261 SetUpAdjuster(1, 1, false);
262 InsertFrames({{1.2}}, kWindowSizeMs);
263 current_adjusted_allocation_ =
264 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
265 current_input_allocation_, target_framerate_fps_));
266 // Adjusted allocation lowered by 20%.
267 ExpectNear(MultiplyAllocation(current_input_allocation_, 1 / 1.2),
268 current_adjusted_allocation_, 0.01);
269 }
270
TEST_F(EncoderBitrateAdjusterTest,SingleLayerUnderuse)271 TEST_F(EncoderBitrateAdjusterTest, SingleLayerUnderuse) {
272 // Single layer, well behaved encoder.
273 current_input_allocation_.SetBitrate(0, 0, 300000);
274 target_framerate_fps_ = 30;
275 SetUpAdjuster(1, 1, false);
276 InsertFrames({{0.5}}, kWindowSizeMs);
277 current_adjusted_allocation_ =
278 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
279 current_input_allocation_, target_framerate_fps_));
280 // Undershoot, adjusted should exactly match input.
281 ExpectNear(current_input_allocation_, current_adjusted_allocation_, 0.00);
282 }
283
TEST_F(EncoderBitrateAdjusterTest,ThreeTemporalLayersOptimalSize)284 TEST_F(EncoderBitrateAdjusterTest, ThreeTemporalLayersOptimalSize) {
285 // Three temporal layers, 60%/20%/20% bps distro, well behaved encoder.
286 current_input_allocation_.SetBitrate(0, 0, 180000);
287 current_input_allocation_.SetBitrate(0, 1, 60000);
288 current_input_allocation_.SetBitrate(0, 2, 60000);
289 target_framerate_fps_ = 30;
290 SetUpAdjuster(1, 3, false);
291 InsertFrames({{1.0, 1.0, 1.0}}, kWindowSizeMs);
292 current_adjusted_allocation_ =
293 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
294 current_input_allocation_, target_framerate_fps_));
295 ExpectNear(current_input_allocation_, current_adjusted_allocation_, 0.01);
296 }
297
TEST_F(EncoderBitrateAdjusterTest,ThreeTemporalLayersOvershoot)298 TEST_F(EncoderBitrateAdjusterTest, ThreeTemporalLayersOvershoot) {
299 // Three temporal layers, 60%/20%/20% bps distro.
300 // 10% overshoot on all layers.
301 current_input_allocation_.SetBitrate(0, 0, 180000);
302 current_input_allocation_.SetBitrate(0, 1, 60000);
303 current_input_allocation_.SetBitrate(0, 2, 60000);
304 target_framerate_fps_ = 30;
305 SetUpAdjuster(1, 3, false);
306 InsertFrames({{1.1, 1.1, 1.1}}, kWindowSizeMs);
307 current_adjusted_allocation_ =
308 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
309 current_input_allocation_, target_framerate_fps_));
310 // Adjusted allocation lowered by 10%.
311 ExpectNear(MultiplyAllocation(current_input_allocation_, 1 / 1.1),
312 current_adjusted_allocation_, 0.01);
313 }
314
TEST_F(EncoderBitrateAdjusterTest,ThreeTemporalLayersUndershoot)315 TEST_F(EncoderBitrateAdjusterTest, ThreeTemporalLayersUndershoot) {
316 // Three temporal layers, 60%/20%/20% bps distro, undershoot all layers.
317 current_input_allocation_.SetBitrate(0, 0, 180000);
318 current_input_allocation_.SetBitrate(0, 1, 60000);
319 current_input_allocation_.SetBitrate(0, 2, 60000);
320 target_framerate_fps_ = 30;
321 SetUpAdjuster(1, 3, false);
322 InsertFrames({{0.8, 0.8, 0.8}}, kWindowSizeMs);
323 current_adjusted_allocation_ =
324 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
325 current_input_allocation_, target_framerate_fps_));
326 // Adjusted allocation identical since we don't boost bitrates.
327 ExpectNear(current_input_allocation_, current_adjusted_allocation_, 0.0);
328 }
329
TEST_F(EncoderBitrateAdjusterTest,ThreeTemporalLayersSkewedOvershoot)330 TEST_F(EncoderBitrateAdjusterTest, ThreeTemporalLayersSkewedOvershoot) {
331 // Three temporal layers, 60%/20%/20% bps distro.
332 // 10% overshoot on base layer, 20% on higher layers.
333 current_input_allocation_.SetBitrate(0, 0, 180000);
334 current_input_allocation_.SetBitrate(0, 1, 60000);
335 current_input_allocation_.SetBitrate(0, 2, 60000);
336 target_framerate_fps_ = 30;
337 SetUpAdjuster(1, 3, false);
338 InsertFrames({{1.1, 1.2, 1.2}}, kWindowSizeMs);
339 current_adjusted_allocation_ =
340 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
341 current_input_allocation_, target_framerate_fps_));
342 // Expected overshoot is weighted by bitrate:
343 // (0.6 * 1.1 + 0.2 * 1.2 + 0.2 * 1.2) = 1.14
344 ExpectNear(MultiplyAllocation(current_input_allocation_, 1 / 1.14),
345 current_adjusted_allocation_, 0.01);
346 }
347
TEST_F(EncoderBitrateAdjusterTest,ThreeTemporalLayersNonLayeredEncoder)348 TEST_F(EncoderBitrateAdjusterTest, ThreeTemporalLayersNonLayeredEncoder) {
349 // Three temporal layers, 60%/20%/20% bps allocation, 10% overshoot,
350 // encoder does not actually support temporal layers.
351 current_input_allocation_.SetBitrate(0, 0, 180000);
352 current_input_allocation_.SetBitrate(0, 1, 60000);
353 current_input_allocation_.SetBitrate(0, 2, 60000);
354 target_framerate_fps_ = 30;
355 SetUpAdjuster(1, 1, false);
356 InsertFrames({{1.1}}, kWindowSizeMs);
357 current_adjusted_allocation_ =
358 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
359 current_input_allocation_, target_framerate_fps_));
360 // Expect the actual 10% overuse to be detected and the allocation to
361 // only contain the one entry.
362 VideoBitrateAllocation expected_allocation;
363 expected_allocation.SetBitrate(
364 0, 0,
365 static_cast<uint32_t>(current_input_allocation_.get_sum_bps() / 1.10));
366 ExpectNear(expected_allocation, current_adjusted_allocation_, 0.01);
367 }
368
TEST_F(EncoderBitrateAdjusterTest,IgnoredStream)369 TEST_F(EncoderBitrateAdjusterTest, IgnoredStream) {
370 // Encoder with three temporal layers, but in a mode that does not support
371 // deterministic frame rate. Those are ignored, even if bitrate overshoots.
372 current_input_allocation_.SetBitrate(0, 0, 180000);
373 current_input_allocation_.SetBitrate(0, 1, 60000);
374 target_framerate_fps_ = 30;
375 SetUpAdjuster(1, 1, false);
376 encoder_info_.fps_allocation[0].clear();
377 adjuster_->OnEncoderInfo(encoder_info_);
378
379 InsertFrames({{1.1}}, kWindowSizeMs);
380 current_adjusted_allocation_ =
381 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
382 current_input_allocation_, target_framerate_fps_));
383
384 // Values passed through.
385 ExpectNear(current_input_allocation_, current_adjusted_allocation_, 0.00);
386 }
387
TEST_F(EncoderBitrateAdjusterTest,DifferentSpatialOvershoots)388 TEST_F(EncoderBitrateAdjusterTest, DifferentSpatialOvershoots) {
389 // Two streams, both with three temporal layers.
390 // S0 has 5% overshoot, S1 has 25% overshoot.
391 current_input_allocation_.SetBitrate(0, 0, 180000);
392 current_input_allocation_.SetBitrate(0, 1, 60000);
393 current_input_allocation_.SetBitrate(0, 2, 60000);
394 current_input_allocation_.SetBitrate(1, 0, 400000);
395 current_input_allocation_.SetBitrate(1, 1, 150000);
396 current_input_allocation_.SetBitrate(1, 2, 150000);
397 target_framerate_fps_ = 30;
398 // Run twice, once configured as simulcast and once as VP9 SVC.
399 for (int i = 0; i < 2; ++i) {
400 SetUpAdjuster(2, 3, i == 0);
401 InsertFrames({{1.05, 1.05, 1.05}, {1.25, 1.25, 1.25}}, kWindowSizeMs);
402 current_adjusted_allocation_ =
403 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
404 current_input_allocation_, target_framerate_fps_));
405 VideoBitrateAllocation expected_allocation;
406 for (size_t ti = 0; ti < 3; ++ti) {
407 expected_allocation.SetBitrate(
408 0, ti,
409 static_cast<uint32_t>(current_input_allocation_.GetBitrate(0, ti) /
410 1.05));
411 expected_allocation.SetBitrate(
412 1, ti,
413 static_cast<uint32_t>(current_input_allocation_.GetBitrate(1, ti) /
414 1.25));
415 }
416 ExpectNear(expected_allocation, current_adjusted_allocation_, 0.01);
417 }
418 }
419
TEST_F(EncoderBitrateAdjusterTest,HeadroomAllowsOvershootToMediaRate)420 TEST_F(EncoderBitrateAdjusterTest, HeadroomAllowsOvershootToMediaRate) {
421 // Two streams, both with three temporal layers.
422 // Media rate is 1.0, but network rate is higher.
423 ScopedFieldTrials field_trial(
424 "WebRTC-VideoRateControl/adjuster_use_headroom:true/");
425
426 const uint32_t kS0Bitrate = 300000;
427 const uint32_t kS1Bitrate = 900000;
428 current_input_allocation_.SetBitrate(0, 0, kS0Bitrate / 3);
429 current_input_allocation_.SetBitrate(0, 1, kS0Bitrate / 3);
430 current_input_allocation_.SetBitrate(0, 2, kS0Bitrate / 3);
431 current_input_allocation_.SetBitrate(1, 0, kS1Bitrate / 3);
432 current_input_allocation_.SetBitrate(1, 1, kS1Bitrate / 3);
433 current_input_allocation_.SetBitrate(1, 2, kS1Bitrate / 3);
434
435 target_framerate_fps_ = 30;
436
437 // Run twice, once configured as simulcast and once as VP9 SVC.
438 for (int i = 0; i < 2; ++i) {
439 SetUpAdjuster(2, 3, i == 0);
440 // Network rate has 10% overshoot, but media rate is correct at 1.0.
441 InsertFrames({{1.0, 1.0, 1.0}, {1.0, 1.0, 1.0}},
442 {{1.1, 1.1, 1.1}, {1.1, 1.1, 1.1}},
443 kWindowSizeMs * kSequenceLength);
444
445 // Push back by 10%.
446 current_adjusted_allocation_ =
447 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
448 current_input_allocation_, target_framerate_fps_));
449 ExpectNear(MultiplyAllocation(current_input_allocation_, 1 / 1.1),
450 current_adjusted_allocation_, 0.01);
451
452 // Add 10% link headroom, overshoot is now allowed.
453 current_adjusted_allocation_ =
454 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
455 current_input_allocation_, target_framerate_fps_,
456 DataRate::BitsPerSec(current_input_allocation_.get_sum_bps() *
457 1.1)));
458 ExpectNear(current_input_allocation_, current_adjusted_allocation_, 0.01);
459 }
460 }
461
TEST_F(EncoderBitrateAdjusterTest,DontExceedMediaRateEvenWithHeadroom)462 TEST_F(EncoderBitrateAdjusterTest, DontExceedMediaRateEvenWithHeadroom) {
463 // Two streams, both with three temporal layers.
464 // Media rate is 1.1, but network rate is higher.
465 ScopedFieldTrials field_trial(
466 "WebRTC-VideoRateControl/adjuster_use_headroom:true/");
467
468 const uint32_t kS0Bitrate = 300000;
469 const uint32_t kS1Bitrate = 900000;
470 current_input_allocation_.SetBitrate(0, 0, kS0Bitrate / 3);
471 current_input_allocation_.SetBitrate(0, 1, kS0Bitrate / 3);
472 current_input_allocation_.SetBitrate(0, 2, kS0Bitrate / 3);
473 current_input_allocation_.SetBitrate(1, 0, kS1Bitrate / 3);
474 current_input_allocation_.SetBitrate(1, 1, kS1Bitrate / 3);
475 current_input_allocation_.SetBitrate(1, 2, kS1Bitrate / 3);
476
477 target_framerate_fps_ = 30;
478
479 // Run twice, once configured as simulcast and once as VP9 SVC.
480 for (int i = 0; i < 2; ++i) {
481 SetUpAdjuster(2, 3, i == 0);
482 // Network rate has 30% overshoot, media rate has 10% overshoot.
483 InsertFrames({{1.1, 1.1, 1.1}, {1.1, 1.1, 1.1}},
484 {{1.3, 1.3, 1.3}, {1.3, 1.3, 1.3}},
485 kWindowSizeMs * kSequenceLength);
486
487 // Push back by 30%.
488 current_adjusted_allocation_ =
489 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
490 current_input_allocation_, target_framerate_fps_));
491 // The up-down causes a bit more noise, allow slightly more error margin.
492 ExpectNear(MultiplyAllocation(current_input_allocation_, 1 / 1.3),
493 current_adjusted_allocation_, 0.015);
494
495 // Add 100% link headroom, overshoot from network to media rate is allowed.
496 current_adjusted_allocation_ =
497 adjuster_->AdjustRateAllocation(VideoEncoder::RateControlParameters(
498 current_input_allocation_, target_framerate_fps_,
499 DataRate::BitsPerSec(current_input_allocation_.get_sum_bps() * 2)));
500 ExpectNear(MultiplyAllocation(current_input_allocation_, 1 / 1.1),
501 current_adjusted_allocation_, 0.015);
502 }
503 }
504
505 } // namespace test
506 } // namespace webrtc
507