1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2016 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "common_video/include/bitrate_adjuster.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include "api/units/time_delta.h"
14*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/fake_clock.h"
15*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker class BitrateAdjusterTest : public ::testing::Test {
20*d9f75844SAndroid Build Coastguard Worker public:
BitrateAdjusterTest()21*d9f75844SAndroid Build Coastguard Worker BitrateAdjusterTest()
22*d9f75844SAndroid Build Coastguard Worker : adjuster_(kMinAdjustedBitratePct, kMaxAdjustedBitratePct) {}
23*d9f75844SAndroid Build Coastguard Worker
24*d9f75844SAndroid Build Coastguard Worker // Simulate an output bitrate for one update cycle of BitrateAdjuster.
SimulateBitrateBps(uint32_t bitrate_bps)25*d9f75844SAndroid Build Coastguard Worker void SimulateBitrateBps(uint32_t bitrate_bps) {
26*d9f75844SAndroid Build Coastguard Worker const uint32_t update_interval_ms =
27*d9f75844SAndroid Build Coastguard Worker BitrateAdjuster::kBitrateUpdateIntervalMs;
28*d9f75844SAndroid Build Coastguard Worker const uint32_t update_frame_interval =
29*d9f75844SAndroid Build Coastguard Worker BitrateAdjuster::kBitrateUpdateFrameInterval;
30*d9f75844SAndroid Build Coastguard Worker // Round up frame interval so we get one cycle passes.
31*d9f75844SAndroid Build Coastguard Worker const uint32_t frame_interval_ms =
32*d9f75844SAndroid Build Coastguard Worker (update_interval_ms + update_frame_interval - 1) /
33*d9f75844SAndroid Build Coastguard Worker update_frame_interval;
34*d9f75844SAndroid Build Coastguard Worker const size_t frame_size_bytes =
35*d9f75844SAndroid Build Coastguard Worker (bitrate_bps * frame_interval_ms) / (8 * 1000);
36*d9f75844SAndroid Build Coastguard Worker for (size_t i = 0; i < update_frame_interval; ++i) {
37*d9f75844SAndroid Build Coastguard Worker clock_.AdvanceTime(webrtc::TimeDelta::Millis(frame_interval_ms));
38*d9f75844SAndroid Build Coastguard Worker adjuster_.Update(frame_size_bytes);
39*d9f75844SAndroid Build Coastguard Worker }
40*d9f75844SAndroid Build Coastguard Worker }
41*d9f75844SAndroid Build Coastguard Worker
GetTargetBitrateBpsPct(float pct)42*d9f75844SAndroid Build Coastguard Worker uint32_t GetTargetBitrateBpsPct(float pct) {
43*d9f75844SAndroid Build Coastguard Worker return pct * adjuster_.GetTargetBitrateBps();
44*d9f75844SAndroid Build Coastguard Worker }
45*d9f75844SAndroid Build Coastguard Worker
VerifyAdjustment()46*d9f75844SAndroid Build Coastguard Worker void VerifyAdjustment() {
47*d9f75844SAndroid Build Coastguard Worker // The adjusted bitrate should be between the estimated bitrate and the
48*d9f75844SAndroid Build Coastguard Worker // target bitrate within clamp.
49*d9f75844SAndroid Build Coastguard Worker uint32_t target_bitrate_bps = adjuster_.GetTargetBitrateBps();
50*d9f75844SAndroid Build Coastguard Worker uint32_t adjusted_bitrate_bps = adjuster_.GetAdjustedBitrateBps();
51*d9f75844SAndroid Build Coastguard Worker uint32_t estimated_bitrate_bps =
52*d9f75844SAndroid Build Coastguard Worker adjuster_.GetEstimatedBitrateBps().value_or(target_bitrate_bps);
53*d9f75844SAndroid Build Coastguard Worker uint32_t adjusted_lower_bound_bps =
54*d9f75844SAndroid Build Coastguard Worker GetTargetBitrateBpsPct(kMinAdjustedBitratePct);
55*d9f75844SAndroid Build Coastguard Worker uint32_t adjusted_upper_bound_bps =
56*d9f75844SAndroid Build Coastguard Worker GetTargetBitrateBpsPct(kMaxAdjustedBitratePct);
57*d9f75844SAndroid Build Coastguard Worker EXPECT_LE(adjusted_bitrate_bps, adjusted_upper_bound_bps);
58*d9f75844SAndroid Build Coastguard Worker EXPECT_GE(adjusted_bitrate_bps, adjusted_lower_bound_bps);
59*d9f75844SAndroid Build Coastguard Worker if (estimated_bitrate_bps > target_bitrate_bps) {
60*d9f75844SAndroid Build Coastguard Worker EXPECT_LT(adjusted_bitrate_bps, target_bitrate_bps);
61*d9f75844SAndroid Build Coastguard Worker }
62*d9f75844SAndroid Build Coastguard Worker }
63*d9f75844SAndroid Build Coastguard Worker
64*d9f75844SAndroid Build Coastguard Worker protected:
65*d9f75844SAndroid Build Coastguard Worker static const float kMinAdjustedBitratePct;
66*d9f75844SAndroid Build Coastguard Worker static const float kMaxAdjustedBitratePct;
67*d9f75844SAndroid Build Coastguard Worker rtc::ScopedFakeClock clock_;
68*d9f75844SAndroid Build Coastguard Worker BitrateAdjuster adjuster_;
69*d9f75844SAndroid Build Coastguard Worker };
70*d9f75844SAndroid Build Coastguard Worker
71*d9f75844SAndroid Build Coastguard Worker const float BitrateAdjusterTest::kMinAdjustedBitratePct = .5f;
72*d9f75844SAndroid Build Coastguard Worker const float BitrateAdjusterTest::kMaxAdjustedBitratePct = .95f;
73*d9f75844SAndroid Build Coastguard Worker
TEST_F(BitrateAdjusterTest,VaryingBitrates)74*d9f75844SAndroid Build Coastguard Worker TEST_F(BitrateAdjusterTest, VaryingBitrates) {
75*d9f75844SAndroid Build Coastguard Worker const uint32_t target_bitrate_bps = 640000;
76*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
77*d9f75844SAndroid Build Coastguard Worker
78*d9f75844SAndroid Build Coastguard Worker // Grossly overshoot for a little while. Adjusted bitrate should decrease.
79*d9f75844SAndroid Build Coastguard Worker uint32_t actual_bitrate_bps = 2 * target_bitrate_bps;
80*d9f75844SAndroid Build Coastguard Worker uint32_t last_adjusted_bitrate_bps = 0;
81*d9f75844SAndroid Build Coastguard Worker uint32_t adjusted_bitrate_bps = 0;
82*d9f75844SAndroid Build Coastguard Worker
83*d9f75844SAndroid Build Coastguard Worker SimulateBitrateBps(actual_bitrate_bps);
84*d9f75844SAndroid Build Coastguard Worker VerifyAdjustment();
85*d9f75844SAndroid Build Coastguard Worker last_adjusted_bitrate_bps = adjuster_.GetAdjustedBitrateBps();
86*d9f75844SAndroid Build Coastguard Worker
87*d9f75844SAndroid Build Coastguard Worker SimulateBitrateBps(actual_bitrate_bps);
88*d9f75844SAndroid Build Coastguard Worker VerifyAdjustment();
89*d9f75844SAndroid Build Coastguard Worker adjusted_bitrate_bps = adjuster_.GetAdjustedBitrateBps();
90*d9f75844SAndroid Build Coastguard Worker EXPECT_LE(adjusted_bitrate_bps, last_adjusted_bitrate_bps);
91*d9f75844SAndroid Build Coastguard Worker last_adjusted_bitrate_bps = adjusted_bitrate_bps;
92*d9f75844SAndroid Build Coastguard Worker // After two cycles we should've stabilized and hit the lower bound.
93*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(GetTargetBitrateBpsPct(kMinAdjustedBitratePct),
94*d9f75844SAndroid Build Coastguard Worker adjusted_bitrate_bps);
95*d9f75844SAndroid Build Coastguard Worker
96*d9f75844SAndroid Build Coastguard Worker // Simulate encoder settling down. Adjusted bitrate should increase.
97*d9f75844SAndroid Build Coastguard Worker SimulateBitrateBps(target_bitrate_bps);
98*d9f75844SAndroid Build Coastguard Worker adjusted_bitrate_bps = adjuster_.GetAdjustedBitrateBps();
99*d9f75844SAndroid Build Coastguard Worker VerifyAdjustment();
100*d9f75844SAndroid Build Coastguard Worker EXPECT_GT(adjusted_bitrate_bps, last_adjusted_bitrate_bps);
101*d9f75844SAndroid Build Coastguard Worker last_adjusted_bitrate_bps = adjusted_bitrate_bps;
102*d9f75844SAndroid Build Coastguard Worker
103*d9f75844SAndroid Build Coastguard Worker SimulateBitrateBps(target_bitrate_bps);
104*d9f75844SAndroid Build Coastguard Worker adjusted_bitrate_bps = adjuster_.GetAdjustedBitrateBps();
105*d9f75844SAndroid Build Coastguard Worker VerifyAdjustment();
106*d9f75844SAndroid Build Coastguard Worker EXPECT_GT(adjusted_bitrate_bps, last_adjusted_bitrate_bps);
107*d9f75844SAndroid Build Coastguard Worker last_adjusted_bitrate_bps = adjusted_bitrate_bps;
108*d9f75844SAndroid Build Coastguard Worker // After two cycles we should've stabilized and hit the upper bound.
109*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(GetTargetBitrateBpsPct(kMaxAdjustedBitratePct),
110*d9f75844SAndroid Build Coastguard Worker adjusted_bitrate_bps);
111*d9f75844SAndroid Build Coastguard Worker }
112*d9f75844SAndroid Build Coastguard Worker
113*d9f75844SAndroid Build Coastguard Worker // Tests that large changes in target bitrate will result in immediate change
114*d9f75844SAndroid Build Coastguard Worker // in adjusted bitrate.
TEST_F(BitrateAdjusterTest,LargeTargetDelta)115*d9f75844SAndroid Build Coastguard Worker TEST_F(BitrateAdjusterTest, LargeTargetDelta) {
116*d9f75844SAndroid Build Coastguard Worker uint32_t target_bitrate_bps = 640000;
117*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
118*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
119*d9f75844SAndroid Build Coastguard Worker
120*d9f75844SAndroid Build Coastguard Worker float delta_pct = BitrateAdjuster::kBitrateTolerancePct * 2;
121*d9f75844SAndroid Build Coastguard Worker
122*d9f75844SAndroid Build Coastguard Worker target_bitrate_bps = (1 + delta_pct) * target_bitrate_bps;
123*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
124*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
125*d9f75844SAndroid Build Coastguard Worker
126*d9f75844SAndroid Build Coastguard Worker target_bitrate_bps = (1 - delta_pct) * target_bitrate_bps;
127*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
128*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
129*d9f75844SAndroid Build Coastguard Worker }
130*d9f75844SAndroid Build Coastguard Worker
131*d9f75844SAndroid Build Coastguard Worker // Tests that small changes in target bitrate within tolerance will not affect
132*d9f75844SAndroid Build Coastguard Worker // adjusted bitrate immediately.
TEST_F(BitrateAdjusterTest,SmallTargetDelta)133*d9f75844SAndroid Build Coastguard Worker TEST_F(BitrateAdjusterTest, SmallTargetDelta) {
134*d9f75844SAndroid Build Coastguard Worker const uint32_t initial_target_bitrate_bps = 640000;
135*d9f75844SAndroid Build Coastguard Worker uint32_t target_bitrate_bps = initial_target_bitrate_bps;
136*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
137*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(initial_target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
138*d9f75844SAndroid Build Coastguard Worker
139*d9f75844SAndroid Build Coastguard Worker float delta_pct = BitrateAdjuster::kBitrateTolerancePct / 2;
140*d9f75844SAndroid Build Coastguard Worker
141*d9f75844SAndroid Build Coastguard Worker target_bitrate_bps = (1 + delta_pct) * target_bitrate_bps;
142*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
143*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(initial_target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
144*d9f75844SAndroid Build Coastguard Worker
145*d9f75844SAndroid Build Coastguard Worker target_bitrate_bps = (1 - delta_pct) * target_bitrate_bps;
146*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
147*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(initial_target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
148*d9f75844SAndroid Build Coastguard Worker }
149*d9f75844SAndroid Build Coastguard Worker
TEST_F(BitrateAdjusterTest,SmallTargetDeltaOverflow)150*d9f75844SAndroid Build Coastguard Worker TEST_F(BitrateAdjusterTest, SmallTargetDeltaOverflow) {
151*d9f75844SAndroid Build Coastguard Worker const uint32_t initial_target_bitrate_bps = 640000;
152*d9f75844SAndroid Build Coastguard Worker uint32_t target_bitrate_bps = initial_target_bitrate_bps;
153*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
154*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(initial_target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
155*d9f75844SAndroid Build Coastguard Worker
156*d9f75844SAndroid Build Coastguard Worker float delta_pct = BitrateAdjuster::kBitrateTolerancePct / 2;
157*d9f75844SAndroid Build Coastguard Worker
158*d9f75844SAndroid Build Coastguard Worker target_bitrate_bps = (1 + delta_pct) * target_bitrate_bps;
159*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
160*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(initial_target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
161*d9f75844SAndroid Build Coastguard Worker
162*d9f75844SAndroid Build Coastguard Worker // 1.05 * 1.05 is 1.1 which is greater than tolerance for the initial target
163*d9f75844SAndroid Build Coastguard Worker // bitrate. Since we didn't advance the clock the adjuster never updated.
164*d9f75844SAndroid Build Coastguard Worker target_bitrate_bps = (1 + delta_pct) * target_bitrate_bps;
165*d9f75844SAndroid Build Coastguard Worker adjuster_.SetTargetBitrateBps(target_bitrate_bps);
166*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(target_bitrate_bps, adjuster_.GetAdjustedBitrateBps());
167*d9f75844SAndroid Build Coastguard Worker }
168*d9f75844SAndroid Build Coastguard Worker
169*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
170