blob: 36db33ac4e8371b4899f5911fc8c9dd0f3aed023 [file] [log] [blame]
sprang429600d2017-01-26 06:12:26 -08001/*
2 * Copyright (c) 2017 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/video_coding/include/video_codec_initializer.h"
Yves Gerey3e707812018-11-28 16:47:49 +010012
13#include <stddef.h>
14#include <stdint.h>
15#include <memory>
16
17#include "absl/types/optional.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010018#include "api/scoped_refptr.h"
Elad Alon45befc52019-07-02 11:20:09 +020019#include "api/test/mock_fec_controller_override.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080020#include "api/video/builtin_video_bitrate_allocator_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010021#include "api/video/video_bitrate_allocation.h"
22#include "api/video/video_bitrate_allocator.h"
23#include "api/video/video_bitrate_allocator_factory.h"
Sergey Silkin86684962018-03-28 19:32:37 +020024#include "api/video_codecs/video_encoder.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020025#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010026#include "api/video_codecs/vp8_temporal_layers_factory.h"
Sergey Silkin86684962018-03-28 19:32:37 +020027#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080028#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080029#include "rtc_base/ref_counted_object.h"
Elad Alon45befc52019-07-02 11:20:09 +020030#include "test/gmock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/gtest.h"
sprang429600d2017-01-26 06:12:26 -080032
33namespace webrtc {
34
35namespace {
sprang429600d2017-01-26 06:12:26 -080036static const int kDefaultWidth = 1280;
37static const int kDefaultHeight = 720;
38static const int kDefaultFrameRate = 30;
39static const uint32_t kDefaultMinBitrateBps = 60000;
40static const uint32_t kDefaultTargetBitrateBps = 2000000;
41static const uint32_t kDefaultMaxBitrateBps = 2000000;
42static const uint32_t kDefaultMinTransmitBitrateBps = 400000;
43static const int kDefaultMaxQp = 48;
Erik Språng5e898d62018-07-06 16:32:20 +020044static const uint32_t kScreenshareTl0BitrateBps = 200000;
sprang429600d2017-01-26 06:12:26 -080045static const uint32_t kScreenshareCodecTargetBitrateBps = 200000;
46static const uint32_t kScreenshareDefaultFramerate = 5;
47// Bitrates for the temporal layers of the higher screenshare simulcast stream.
48static const uint32_t kHighScreenshareTl0Bps = 800000;
49static const uint32_t kHighScreenshareTl1Bps = 1200000;
50} // namespace
51
sprang429600d2017-01-26 06:12:26 -080052// TODO(sprang): Extend coverage to handle the rest of the codec initializer.
53class VideoCodecInitializerTest : public ::testing::Test {
54 public:
Niels Möllerf1338562018-04-26 09:51:47 +020055 VideoCodecInitializerTest() {}
sprang429600d2017-01-26 06:12:26 -080056 virtual ~VideoCodecInitializerTest() {}
57
58 protected:
59 void SetUpFor(VideoCodecType type,
60 int num_spatial_streams,
61 int num_temporal_streams,
62 bool screenshare) {
63 config_ = VideoEncoderConfig();
Niels Möller259a4972018-04-05 15:36:51 +020064 config_.codec_type = type;
65
sprang429600d2017-01-26 06:12:26 -080066 if (screenshare) {
67 config_.min_transmit_bitrate_bps = kDefaultMinTransmitBitrateBps;
68 config_.content_type = VideoEncoderConfig::ContentType::kScreen;
69 }
70
71 if (type == VideoCodecType::kVideoCodecVP8) {
72 config_.number_of_streams = num_spatial_streams;
73 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
74 vp8_settings.numberOfTemporalLayers = num_temporal_streams;
75 config_.encoder_specific_settings = new rtc::RefCountedObject<
76 webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
Sergey Silkin86684962018-03-28 19:32:37 +020077 } else if (type == VideoCodecType::kVideoCodecVP9) {
78 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
79 vp9_settings.numberOfSpatialLayers = num_spatial_streams;
80 vp9_settings.numberOfTemporalLayers = num_temporal_streams;
81 config_.encoder_specific_settings = new rtc::RefCountedObject<
82 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
83 } else if (type != VideoCodecType::kVideoCodecMultiplex) {
sprang429600d2017-01-26 06:12:26 -080084 ADD_FAILURE() << "Unexpected codec type: " << type;
85 }
86 }
87
88 bool InitializeCodec() {
89 codec_out_ = VideoCodec();
Elad Aloncde8ab22019-03-20 11:56:20 +010090 frame_buffer_controller_.reset();
Jiawei Ouc2ebe212018-11-08 10:02:56 -080091 if (!VideoCodecInitializer::SetupCodec(config_, streams_, &codec_out_)) {
sprang429600d2017-01-26 06:12:26 -080092 return false;
93 }
Jiawei Ouc2ebe212018-11-08 10:02:56 -080094 bitrate_allocator_ = CreateBuiltinVideoBitrateAllocatorFactory()
95 ->CreateVideoBitrateAllocator(codec_out_);
96 RTC_CHECK(bitrate_allocator_);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080097 if (codec_out_.codecType == VideoCodecType::kVideoCodecMultiplex)
Emircan Uysaler0a375472017-12-11 12:21:02 +053098 return true;
Erik Språng82fad3d2018-03-21 09:57:23 +010099
sprang429600d2017-01-26 06:12:26 -0800100 // Make sure temporal layers instances have been created.
101 if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
Elad Aloncde8ab22019-03-20 11:56:20 +0100102 Vp8TemporalLayersFactory factory;
Elad Alona2795842019-06-07 23:10:00 +0200103 const VideoEncoder::Settings settings(VideoEncoder::Capabilities(false),
104 1, 1000);
Elad Alon45befc52019-07-02 11:20:09 +0200105 frame_buffer_controller_ =
106 factory.Create(codec_out_, settings, &fec_controller_override_);
sprang429600d2017-01-26 06:12:26 -0800107 }
108 return true;
109 }
110
111 VideoStream DefaultStream() {
112 VideoStream stream;
113 stream.width = kDefaultWidth;
114 stream.height = kDefaultHeight;
115 stream.max_framerate = kDefaultFrameRate;
116 stream.min_bitrate_bps = kDefaultMinBitrateBps;
117 stream.target_bitrate_bps = kDefaultTargetBitrateBps;
118 stream.max_bitrate_bps = kDefaultMaxBitrateBps;
119 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100120 stream.num_temporal_layers = 1;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800121 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800122 return stream;
123 }
124
125 VideoStream DefaultScreenshareStream() {
126 VideoStream stream = DefaultStream();
127 stream.min_bitrate_bps = 30000;
128 stream.target_bitrate_bps = kScreenshareTl0BitrateBps;
129 stream.max_bitrate_bps = 1000000;
130 stream.max_framerate = kScreenshareDefaultFramerate;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100131 stream.num_temporal_layers = 2;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800132 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800133 return stream;
134 }
135
Elad Alon45befc52019-07-02 11:20:09 +0200136 MockFecControllerOverride fec_controller_override_;
137
sprang429600d2017-01-26 06:12:26 -0800138 // Input settings.
139 VideoEncoderConfig config_;
sprang429600d2017-01-26 06:12:26 -0800140 std::vector<VideoStream> streams_;
sprang429600d2017-01-26 06:12:26 -0800141
142 // Output.
143 VideoCodec codec_out_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800144 std::unique_ptr<VideoBitrateAllocator> bitrate_allocator_;
Elad Aloncde8ab22019-03-20 11:56:20 +0100145 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_;
sprang429600d2017-01-26 06:12:26 -0800146};
147
148TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
149 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
150 streams_.push_back(DefaultStream());
151 EXPECT_TRUE(InitializeCodec());
152
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800153 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
154 kDefaultTargetBitrateBps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800155 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
156 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
157 EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
158}
159
Seth Hampson46e31ba2018-01-18 10:39:54 -0800160TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
161 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
162 VideoStream inactive_stream = DefaultStream();
163 inactive_stream.active = false;
164 streams_.push_back(inactive_stream);
165 EXPECT_TRUE(InitializeCodec());
166
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800167 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
168 kDefaultTargetBitrateBps, kDefaultFrameRate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800169 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
170 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
171 EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
172}
173
sprang429600d2017-01-26 06:12:26 -0800174TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
175 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
176 streams_.push_back(DefaultScreenshareStream());
177 EXPECT_TRUE(InitializeCodec());
178
179 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
180 EXPECT_EQ(2u, codec_out_.VP8()->numberOfTemporalLayers);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800181 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
182 kScreenshareCodecTargetBitrateBps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800183 EXPECT_EQ(kScreenshareCodecTargetBitrateBps,
184 bitrate_allocation.get_sum_bps());
185 EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
186}
187
Seth Hampson46e31ba2018-01-18 10:39:54 -0800188TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800189 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
190 streams_.push_back(DefaultScreenshareStream());
191 VideoStream video_stream = DefaultStream();
192 video_stream.max_framerate = kScreenshareDefaultFramerate;
193 streams_.push_back(video_stream);
194 EXPECT_TRUE(InitializeCodec());
195
196 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
197 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
198 const uint32_t max_bitrate_bps =
199 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800200 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
201 max_bitrate_bps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800202 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
203 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
204 bitrate_allocation.GetSpatialLayerSum(0));
205 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
206 bitrate_allocation.GetSpatialLayerSum(1));
207}
208
Seth Hampson46e31ba2018-01-18 10:39:54 -0800209// Tests that when a video stream is inactive, then the bitrate allocation will
210// be 0 for that stream.
211TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
212 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
213 streams_.push_back(DefaultScreenshareStream());
214 VideoStream inactive_video_stream = DefaultStream();
215 inactive_video_stream.active = false;
216 inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
217 streams_.push_back(inactive_video_stream);
218 EXPECT_TRUE(InitializeCodec());
219
220 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
221 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
222 const uint32_t target_bitrate =
223 streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800224 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
225 target_bitrate, kScreenshareDefaultFramerate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800226 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
227 bitrate_allocation.get_sum_bps());
228 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
229 bitrate_allocation.GetSpatialLayerSum(0));
230 EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
231}
232
233TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800234 // Two simulcast streams, the lower one using legacy settings (two temporal
235 // streams, 5fps), the higher one using 3 temporal streams and 30fps.
236 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
237 streams_.push_back(DefaultScreenshareStream());
238 VideoStream video_stream = DefaultStream();
Sergey Silkina796a7e2018-03-01 15:11:29 +0100239 video_stream.num_temporal_layers = 3;
sprang429600d2017-01-26 06:12:26 -0800240 streams_.push_back(video_stream);
241 EXPECT_TRUE(InitializeCodec());
242
243 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
244 EXPECT_EQ(3u, codec_out_.VP8()->numberOfTemporalLayers);
245 const uint32_t max_bitrate_bps =
246 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Erik Språng566124a2018-04-23 12:32:22 +0200247 VideoBitrateAllocation bitrate_allocation =
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800248 bitrate_allocator_->GetAllocation(max_bitrate_bps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800249 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
250 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
251 bitrate_allocation.GetSpatialLayerSum(0));
252 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
253 bitrate_allocation.GetSpatialLayerSum(1));
254 EXPECT_EQ(kHighScreenshareTl0Bps, bitrate_allocation.GetBitrate(1, 0));
255 EXPECT_EQ(kHighScreenshareTl1Bps - kHighScreenshareTl0Bps,
256 bitrate_allocation.GetBitrate(1, 1));
257}
258
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800259TEST_F(VideoCodecInitializerTest, SingleStreamMultiplexCodec) {
260 SetUpFor(VideoCodecType::kVideoCodecMultiplex, 1, 1, true);
Emircan Uysaler0a375472017-12-11 12:21:02 +0530261 streams_.push_back(DefaultStream());
262 EXPECT_TRUE(InitializeCodec());
263}
264
Sergey Silkin86684962018-03-28 19:32:37 +0200265TEST_F(VideoCodecInitializerTest, Vp9SvcDefaultLayering) {
266 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
267 VideoStream stream = DefaultStream();
268 stream.num_temporal_layers = 3;
269 streams_.push_back(stream);
270
271 EXPECT_TRUE(InitializeCodec());
272 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 3u);
273 EXPECT_EQ(codec_out_.VP9()->numberOfTemporalLayers, 3u);
274}
275
276TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) {
277 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
278 VideoStream stream = DefaultStream();
279 stream.num_temporal_layers = 3;
280 // Set resolution which is only enough to produce 2 spatial layers.
281 stream.width = kMinVp9SpatialLayerWidth * 2;
282 stream.height = kMinVp9SpatialLayerHeight * 2;
283
284 streams_.push_back(stream);
285
286 EXPECT_TRUE(InitializeCodec());
287 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 2u);
288}
289
Sergey Silkinfafeac32018-04-13 16:36:39 +0200290TEST_F(VideoCodecInitializerTest,
291 Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrate) {
292 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, false);
293 VideoStream stream = DefaultStream();
294 stream.num_temporal_layers = 3;
295 streams_.push_back(stream);
296
297 EXPECT_TRUE(InitializeCodec());
298 EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate,
299 kDefaultMaxBitrateBps / 1000);
300}
301
Sergey Silkin33120922018-11-28 13:32:13 +0100302TEST_F(VideoCodecInitializerTest,
Ilya Nikolaevskiy9ef5e052019-03-05 10:08:35 +0100303 Vp9SingleSpatialLayerTargetBitrateIsEqualToCodecMaxBitrate) {
304 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 1, true);
305 VideoStream stream = DefaultStream();
306 stream.num_temporal_layers = 1;
307 streams_.push_back(stream);
308
309 EXPECT_TRUE(InitializeCodec());
310 EXPECT_EQ(codec_out_.spatialLayers[0].targetBitrate,
311 kDefaultMaxBitrateBps / 1000);
312}
313
314TEST_F(VideoCodecInitializerTest,
Sergey Silkin33120922018-11-28 13:32:13 +0100315 Vp9KeepBitrateLimitsIfNumberOfSpatialLayersIsReducedToOne) {
316 // Request 3 spatial layers for 320x180 input. Actual number of layers will be
317 // reduced to 1 due to low input resolution but SVC bitrate limits should be
318 // applied.
319 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
320 VideoStream stream = DefaultStream();
321 stream.width = 320;
322 stream.height = 180;
323 stream.num_temporal_layers = 3;
324 streams_.push_back(stream);
325
326 EXPECT_TRUE(InitializeCodec());
327 EXPECT_LT(codec_out_.spatialLayers[0].maxBitrate,
328 kDefaultMaxBitrateBps / 1000);
329}
330
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100331TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) {
332 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 1, false);
333 VideoStream stream = DefaultStream();
334 streams_.push_back(stream);
335
336 config_.simulcast_layers.resize(3);
337
338 // Activate all layers.
339 config_.simulcast_layers[0].active = true;
340 config_.simulcast_layers[1].active = true;
341 config_.simulcast_layers[2].active = true;
342 EXPECT_TRUE(InitializeCodec());
343 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
344 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
345 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
346
347 // Deactivate top layer.
348 config_.simulcast_layers[0].active = false;
349 EXPECT_TRUE(InitializeCodec());
350 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
351 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
352 EXPECT_FALSE(codec_out_.spatialLayers[2].active);
353
354 // Deactivate middle layer.
355 config_.simulcast_layers[0].active = true;
356 config_.simulcast_layers[1].active = false;
357 EXPECT_TRUE(InitializeCodec());
358 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
359 EXPECT_FALSE(codec_out_.spatialLayers[1].active);
360 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
361}
362
sprang429600d2017-01-26 06:12:26 -0800363} // namespace webrtc