1 /*
2 * Copyright 2021 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/adaptation/bitrate_constraint.h"
12
13 #include <utility>
14 #include <vector>
15
16 #include "api/video_codecs/video_encoder.h"
17 #include "call/adaptation/encoder_settings.h"
18 #include "call/adaptation/test/fake_frame_rate_provider.h"
19 #include "call/adaptation/video_source_restrictions.h"
20 #include "call/adaptation/video_stream_input_state_provider.h"
21 #include "test/gtest.h"
22
23 namespace webrtc {
24
25 namespace {
26 const VideoSourceRestrictions k360p{/*max_pixels_per_frame=*/640 * 360,
27 /*target_pixels_per_frame=*/640 * 360,
28 /*max_frame_rate=*/30};
29 const VideoSourceRestrictions k720p{/*max_pixels_per_frame=*/1280 * 720,
30 /*target_pixels_per_frame=*/1280 * 720,
31 /*max_frame_rate=*/30};
32
FillCodecConfig(VideoCodec * video_codec,VideoEncoderConfig * encoder_config,int width_px,int height_px,std::vector<bool> active_flags)33 void FillCodecConfig(VideoCodec* video_codec,
34 VideoEncoderConfig* encoder_config,
35 int width_px,
36 int height_px,
37 std::vector<bool> active_flags) {
38 size_t num_layers = active_flags.size();
39 video_codec->codecType = kVideoCodecVP8;
40 video_codec->numberOfSimulcastStreams = num_layers;
41
42 encoder_config->number_of_streams = num_layers;
43 encoder_config->simulcast_layers.resize(num_layers);
44
45 for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) {
46 int layer_width_px = width_px >> (num_layers - 1 - layer_idx);
47 int layer_height_px = height_px >> (num_layers - 1 - layer_idx);
48
49 video_codec->simulcastStream[layer_idx].active = active_flags[layer_idx];
50 video_codec->simulcastStream[layer_idx].width = layer_width_px;
51 video_codec->simulcastStream[layer_idx].height = layer_height_px;
52
53 encoder_config->simulcast_layers[layer_idx].active =
54 active_flags[layer_idx];
55 encoder_config->simulcast_layers[layer_idx].width = layer_width_px;
56 encoder_config->simulcast_layers[layer_idx].height = layer_height_px;
57 }
58 }
59
60 constexpr int kStartBitrateBps720p = 1000000;
61
MakeEncoderInfo()62 VideoEncoder::EncoderInfo MakeEncoderInfo() {
63 VideoEncoder::EncoderInfo encoder_info;
64 encoder_info.resolution_bitrate_limits = {
65 {640 * 360, 500000, 0, 5000000},
66 {1280 * 720, kStartBitrateBps720p, 0, 5000000},
67 {1920 * 1080, 2000000, 0, 5000000}};
68 return encoder_info;
69 }
70
71 } // namespace
72
73 class BitrateConstraintTest : public ::testing::Test {
74 public:
BitrateConstraintTest()75 BitrateConstraintTest()
76 : frame_rate_provider_(), input_state_provider_(&frame_rate_provider_) {}
77
78 protected:
OnEncoderSettingsUpdated(int width_px,int height_px,std::vector<bool> active_flags)79 void OnEncoderSettingsUpdated(int width_px,
80 int height_px,
81 std::vector<bool> active_flags) {
82 VideoCodec video_codec;
83 VideoEncoderConfig encoder_config;
84 FillCodecConfig(&video_codec, &encoder_config, width_px, height_px,
85 active_flags);
86
87 EncoderSettings encoder_settings(MakeEncoderInfo(),
88 std::move(encoder_config), video_codec);
89 bitrate_constraint_.OnEncoderSettingsUpdated(encoder_settings);
90 input_state_provider_.OnEncoderSettingsChanged(encoder_settings);
91 }
92
93 FakeFrameRateProvider frame_rate_provider_;
94 VideoStreamInputStateProvider input_state_provider_;
95 BitrateConstraint bitrate_constraint_;
96 };
97
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastIfBitrateIsEnough)98 TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSinglecastIfBitrateIsEnough) {
99 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
100 /*active_flags=*/{true});
101
102 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
103
104 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
105 input_state_provider_.InputState(),
106 /*restrictions_before=*/k360p,
107 /*restrictions_after=*/k720p));
108 }
109
TEST_F(BitrateConstraintTest,AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnough)110 TEST_F(BitrateConstraintTest,
111 AdaptUpDisallowedAtSinglecastIfBitrateIsNotEnough) {
112 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
113 /*active_flags=*/{true});
114
115 // 1 bps less than needed for 720p.
116 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
117
118 EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
119 input_state_provider_.InputState(),
120 /*restrictions_before=*/k360p,
121 /*restrictions_after=*/k720p));
122 }
123
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastUpperLayerActiveIfBitrateIsEnough)124 TEST_F(BitrateConstraintTest,
125 AdaptUpAllowedAtSinglecastUpperLayerActiveIfBitrateIsEnough) {
126 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
127 /*active_flags=*/{false, true});
128
129 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p);
130
131 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
132 input_state_provider_.InputState(),
133 /*restrictions_before=*/k360p,
134 /*restrictions_after=*/k720p));
135 }
136
TEST_F(BitrateConstraintTest,AdaptUpDisallowedAtSinglecastUpperLayerActiveIfBitrateIsNotEnough)137 TEST_F(BitrateConstraintTest,
138 AdaptUpDisallowedAtSinglecastUpperLayerActiveIfBitrateIsNotEnough) {
139 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
140 /*active_flags=*/{false, true});
141
142 // 1 bps less than needed for 720p.
143 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
144
145 EXPECT_FALSE(bitrate_constraint_.IsAdaptationUpAllowed(
146 input_state_provider_.InputState(),
147 /*restrictions_before=*/k360p,
148 /*restrictions_after=*/k720p));
149 }
150
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSinglecastLowestLayerActiveIfBitrateIsNotEnough)151 TEST_F(BitrateConstraintTest,
152 AdaptUpAllowedAtSinglecastLowestLayerActiveIfBitrateIsNotEnough) {
153 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
154 /*active_flags=*/{true, false});
155
156 // 1 bps less than needed for 720p.
157 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
158
159 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
160 input_state_provider_.InputState(),
161 /*restrictions_before=*/k360p,
162 /*restrictions_after=*/k720p));
163 }
164
TEST_F(BitrateConstraintTest,AdaptUpAllowedAtSimulcastIfBitrateIsNotEnough)165 TEST_F(BitrateConstraintTest, AdaptUpAllowedAtSimulcastIfBitrateIsNotEnough) {
166 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
167 /*active_flags=*/{true, true});
168
169 // 1 bps less than needed for 720p.
170 bitrate_constraint_.OnEncoderTargetBitrateUpdated(kStartBitrateBps720p - 1);
171
172 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
173 input_state_provider_.InputState(),
174 /*restrictions_before=*/k360p,
175 /*restrictions_after=*/k720p));
176 }
177
TEST_F(BitrateConstraintTest,AdaptUpInFpsAllowedAtNoResolutionIncreaseIfBitrateIsNotEnough)178 TEST_F(BitrateConstraintTest,
179 AdaptUpInFpsAllowedAtNoResolutionIncreaseIfBitrateIsNotEnough) {
180 OnEncoderSettingsUpdated(/*width_px=*/640, /*height_px=*/360,
181 /*active_flags=*/{true});
182
183 bitrate_constraint_.OnEncoderTargetBitrateUpdated(1);
184
185 EXPECT_TRUE(bitrate_constraint_.IsAdaptationUpAllowed(
186 input_state_provider_.InputState(),
187 /*restrictions_before=*/k360p,
188 /*restrictions_after=*/k360p));
189 }
190
191 } // namespace webrtc
192