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