blob: 5cac795c06fbe536dbb81471d8610ab2d8751753 [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"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080019#include "api/video/builtin_video_bitrate_allocator_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "api/video/video_bitrate_allocation.h"
21#include "api/video/video_bitrate_allocator.h"
22#include "api/video/video_bitrate_allocator_factory.h"
Sergey Silkin86684962018-03-28 19:32:37 +020023#include "api/video_codecs/video_encoder.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020024#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010025#include "api/video_codecs/vp8_temporal_layers_factory.h"
Sergey Silkin86684962018-03-28 19:32:37 +020026#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080027#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080028#include "rtc_base/ref_counted_object.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "test/gtest.h"
sprang429600d2017-01-26 06:12:26 -080030
31namespace webrtc {
32
33namespace {
sprang429600d2017-01-26 06:12:26 -080034static const int kDefaultWidth = 1280;
35static const int kDefaultHeight = 720;
36static const int kDefaultFrameRate = 30;
37static const uint32_t kDefaultMinBitrateBps = 60000;
38static const uint32_t kDefaultTargetBitrateBps = 2000000;
39static const uint32_t kDefaultMaxBitrateBps = 2000000;
40static const uint32_t kDefaultMinTransmitBitrateBps = 400000;
41static const int kDefaultMaxQp = 48;
Erik Språng5e898d62018-07-06 16:32:20 +020042static const uint32_t kScreenshareTl0BitrateBps = 200000;
sprang429600d2017-01-26 06:12:26 -080043static const uint32_t kScreenshareCodecTargetBitrateBps = 200000;
44static const uint32_t kScreenshareDefaultFramerate = 5;
45// Bitrates for the temporal layers of the higher screenshare simulcast stream.
46static const uint32_t kHighScreenshareTl0Bps = 800000;
47static const uint32_t kHighScreenshareTl1Bps = 1200000;
48} // namespace
49
sprang429600d2017-01-26 06:12:26 -080050// TODO(sprang): Extend coverage to handle the rest of the codec initializer.
51class VideoCodecInitializerTest : public ::testing::Test {
52 public:
Niels Möllerf1338562018-04-26 09:51:47 +020053 VideoCodecInitializerTest() {}
sprang429600d2017-01-26 06:12:26 -080054 virtual ~VideoCodecInitializerTest() {}
55
56 protected:
57 void SetUpFor(VideoCodecType type,
58 int num_spatial_streams,
59 int num_temporal_streams,
60 bool screenshare) {
61 config_ = VideoEncoderConfig();
Niels Möller259a4972018-04-05 15:36:51 +020062 config_.codec_type = type;
63
sprang429600d2017-01-26 06:12:26 -080064 if (screenshare) {
65 config_.min_transmit_bitrate_bps = kDefaultMinTransmitBitrateBps;
66 config_.content_type = VideoEncoderConfig::ContentType::kScreen;
67 }
68
69 if (type == VideoCodecType::kVideoCodecVP8) {
70 config_.number_of_streams = num_spatial_streams;
71 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
72 vp8_settings.numberOfTemporalLayers = num_temporal_streams;
73 config_.encoder_specific_settings = new rtc::RefCountedObject<
74 webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
Sergey Silkin86684962018-03-28 19:32:37 +020075 } else if (type == VideoCodecType::kVideoCodecVP9) {
76 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
77 vp9_settings.numberOfSpatialLayers = num_spatial_streams;
78 vp9_settings.numberOfTemporalLayers = num_temporal_streams;
79 config_.encoder_specific_settings = new rtc::RefCountedObject<
80 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
81 } else if (type != VideoCodecType::kVideoCodecMultiplex) {
sprang429600d2017-01-26 06:12:26 -080082 ADD_FAILURE() << "Unexpected codec type: " << type;
83 }
84 }
85
86 bool InitializeCodec() {
87 codec_out_ = VideoCodec();
Elad Aloncde8ab22019-03-20 11:56:20 +010088 frame_buffer_controller_.reset();
Jiawei Ouc2ebe212018-11-08 10:02:56 -080089 if (!VideoCodecInitializer::SetupCodec(config_, streams_, &codec_out_)) {
sprang429600d2017-01-26 06:12:26 -080090 return false;
91 }
Jiawei Ouc2ebe212018-11-08 10:02:56 -080092 bitrate_allocator_ = CreateBuiltinVideoBitrateAllocatorFactory()
93 ->CreateVideoBitrateAllocator(codec_out_);
94 RTC_CHECK(bitrate_allocator_);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080095 if (codec_out_.codecType == VideoCodecType::kVideoCodecMultiplex)
Emircan Uysaler0a375472017-12-11 12:21:02 +053096 return true;
Erik Språng82fad3d2018-03-21 09:57:23 +010097
sprang429600d2017-01-26 06:12:26 -080098 // Make sure temporal layers instances have been created.
99 if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
Elad Aloncde8ab22019-03-20 11:56:20 +0100100 Vp8TemporalLayersFactory factory;
Elad Alona2795842019-06-07 23:10:00 +0200101 const VideoEncoder::Settings settings(VideoEncoder::Capabilities(false),
102 1, 1000);
103 frame_buffer_controller_ = factory.Create(codec_out_, settings);
sprang429600d2017-01-26 06:12:26 -0800104 }
105 return true;
106 }
107
108 VideoStream DefaultStream() {
109 VideoStream stream;
110 stream.width = kDefaultWidth;
111 stream.height = kDefaultHeight;
112 stream.max_framerate = kDefaultFrameRate;
113 stream.min_bitrate_bps = kDefaultMinBitrateBps;
114 stream.target_bitrate_bps = kDefaultTargetBitrateBps;
115 stream.max_bitrate_bps = kDefaultMaxBitrateBps;
116 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100117 stream.num_temporal_layers = 1;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800118 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800119 return stream;
120 }
121
122 VideoStream DefaultScreenshareStream() {
123 VideoStream stream = DefaultStream();
124 stream.min_bitrate_bps = 30000;
125 stream.target_bitrate_bps = kScreenshareTl0BitrateBps;
126 stream.max_bitrate_bps = 1000000;
127 stream.max_framerate = kScreenshareDefaultFramerate;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100128 stream.num_temporal_layers = 2;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800129 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800130 return stream;
131 }
132
133 // Input settings.
134 VideoEncoderConfig config_;
sprang429600d2017-01-26 06:12:26 -0800135 std::vector<VideoStream> streams_;
sprang429600d2017-01-26 06:12:26 -0800136
137 // Output.
138 VideoCodec codec_out_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800139 std::unique_ptr<VideoBitrateAllocator> bitrate_allocator_;
Elad Aloncde8ab22019-03-20 11:56:20 +0100140 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_;
sprang429600d2017-01-26 06:12:26 -0800141};
142
143TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
144 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
145 streams_.push_back(DefaultStream());
146 EXPECT_TRUE(InitializeCodec());
147
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800148 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
149 kDefaultTargetBitrateBps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800150 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
151 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
152 EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
153}
154
Seth Hampson46e31ba2018-01-18 10:39:54 -0800155TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
156 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
157 VideoStream inactive_stream = DefaultStream();
158 inactive_stream.active = false;
159 streams_.push_back(inactive_stream);
160 EXPECT_TRUE(InitializeCodec());
161
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800162 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
163 kDefaultTargetBitrateBps, kDefaultFrameRate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800164 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
165 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
166 EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
167}
168
sprang429600d2017-01-26 06:12:26 -0800169TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
170 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
171 streams_.push_back(DefaultScreenshareStream());
172 EXPECT_TRUE(InitializeCodec());
173
174 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
175 EXPECT_EQ(2u, codec_out_.VP8()->numberOfTemporalLayers);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800176 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
177 kScreenshareCodecTargetBitrateBps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800178 EXPECT_EQ(kScreenshareCodecTargetBitrateBps,
179 bitrate_allocation.get_sum_bps());
180 EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
181}
182
Seth Hampson46e31ba2018-01-18 10:39:54 -0800183TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800184 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
185 streams_.push_back(DefaultScreenshareStream());
186 VideoStream video_stream = DefaultStream();
187 video_stream.max_framerate = kScreenshareDefaultFramerate;
188 streams_.push_back(video_stream);
189 EXPECT_TRUE(InitializeCodec());
190
191 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
192 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
193 const uint32_t max_bitrate_bps =
194 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800195 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
196 max_bitrate_bps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800197 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
198 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
199 bitrate_allocation.GetSpatialLayerSum(0));
200 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
201 bitrate_allocation.GetSpatialLayerSum(1));
202}
203
Seth Hampson46e31ba2018-01-18 10:39:54 -0800204// Tests that when a video stream is inactive, then the bitrate allocation will
205// be 0 for that stream.
206TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
207 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
208 streams_.push_back(DefaultScreenshareStream());
209 VideoStream inactive_video_stream = DefaultStream();
210 inactive_video_stream.active = false;
211 inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
212 streams_.push_back(inactive_video_stream);
213 EXPECT_TRUE(InitializeCodec());
214
215 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
216 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
217 const uint32_t target_bitrate =
218 streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800219 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
220 target_bitrate, kScreenshareDefaultFramerate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800221 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
222 bitrate_allocation.get_sum_bps());
223 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
224 bitrate_allocation.GetSpatialLayerSum(0));
225 EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
226}
227
228TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800229 // Two simulcast streams, the lower one using legacy settings (two temporal
230 // streams, 5fps), the higher one using 3 temporal streams and 30fps.
231 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
232 streams_.push_back(DefaultScreenshareStream());
233 VideoStream video_stream = DefaultStream();
Sergey Silkina796a7e2018-03-01 15:11:29 +0100234 video_stream.num_temporal_layers = 3;
sprang429600d2017-01-26 06:12:26 -0800235 streams_.push_back(video_stream);
236 EXPECT_TRUE(InitializeCodec());
237
238 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
239 EXPECT_EQ(3u, codec_out_.VP8()->numberOfTemporalLayers);
240 const uint32_t max_bitrate_bps =
241 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Erik Språng566124a2018-04-23 12:32:22 +0200242 VideoBitrateAllocation bitrate_allocation =
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800243 bitrate_allocator_->GetAllocation(max_bitrate_bps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800244 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
245 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
246 bitrate_allocation.GetSpatialLayerSum(0));
247 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
248 bitrate_allocation.GetSpatialLayerSum(1));
249 EXPECT_EQ(kHighScreenshareTl0Bps, bitrate_allocation.GetBitrate(1, 0));
250 EXPECT_EQ(kHighScreenshareTl1Bps - kHighScreenshareTl0Bps,
251 bitrate_allocation.GetBitrate(1, 1));
252}
253
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800254TEST_F(VideoCodecInitializerTest, SingleStreamMultiplexCodec) {
255 SetUpFor(VideoCodecType::kVideoCodecMultiplex, 1, 1, true);
Emircan Uysaler0a375472017-12-11 12:21:02 +0530256 streams_.push_back(DefaultStream());
257 EXPECT_TRUE(InitializeCodec());
258}
259
Sergey Silkin86684962018-03-28 19:32:37 +0200260TEST_F(VideoCodecInitializerTest, Vp9SvcDefaultLayering) {
261 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
262 VideoStream stream = DefaultStream();
263 stream.num_temporal_layers = 3;
264 streams_.push_back(stream);
265
266 EXPECT_TRUE(InitializeCodec());
267 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 3u);
268 EXPECT_EQ(codec_out_.VP9()->numberOfTemporalLayers, 3u);
269}
270
271TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) {
272 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
273 VideoStream stream = DefaultStream();
274 stream.num_temporal_layers = 3;
275 // Set resolution which is only enough to produce 2 spatial layers.
276 stream.width = kMinVp9SpatialLayerWidth * 2;
277 stream.height = kMinVp9SpatialLayerHeight * 2;
278
279 streams_.push_back(stream);
280
281 EXPECT_TRUE(InitializeCodec());
282 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 2u);
283}
284
Sergey Silkinfafeac32018-04-13 16:36:39 +0200285TEST_F(VideoCodecInitializerTest,
286 Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrate) {
287 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, false);
288 VideoStream stream = DefaultStream();
289 stream.num_temporal_layers = 3;
290 streams_.push_back(stream);
291
292 EXPECT_TRUE(InitializeCodec());
293 EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate,
294 kDefaultMaxBitrateBps / 1000);
295}
296
Sergey Silkin33120922018-11-28 13:32:13 +0100297TEST_F(VideoCodecInitializerTest,
Ilya Nikolaevskiy9ef5e052019-03-05 10:08:35 +0100298 Vp9SingleSpatialLayerTargetBitrateIsEqualToCodecMaxBitrate) {
299 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 1, true);
300 VideoStream stream = DefaultStream();
301 stream.num_temporal_layers = 1;
302 streams_.push_back(stream);
303
304 EXPECT_TRUE(InitializeCodec());
305 EXPECT_EQ(codec_out_.spatialLayers[0].targetBitrate,
306 kDefaultMaxBitrateBps / 1000);
307}
308
309TEST_F(VideoCodecInitializerTest,
Sergey Silkin33120922018-11-28 13:32:13 +0100310 Vp9KeepBitrateLimitsIfNumberOfSpatialLayersIsReducedToOne) {
311 // Request 3 spatial layers for 320x180 input. Actual number of layers will be
312 // reduced to 1 due to low input resolution but SVC bitrate limits should be
313 // applied.
314 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
315 VideoStream stream = DefaultStream();
316 stream.width = 320;
317 stream.height = 180;
318 stream.num_temporal_layers = 3;
319 streams_.push_back(stream);
320
321 EXPECT_TRUE(InitializeCodec());
322 EXPECT_LT(codec_out_.spatialLayers[0].maxBitrate,
323 kDefaultMaxBitrateBps / 1000);
324}
325
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100326TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) {
327 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 1, false);
328 VideoStream stream = DefaultStream();
329 streams_.push_back(stream);
330
331 config_.simulcast_layers.resize(3);
332
333 // Activate all layers.
334 config_.simulcast_layers[0].active = true;
335 config_.simulcast_layers[1].active = true;
336 config_.simulcast_layers[2].active = true;
337 EXPECT_TRUE(InitializeCodec());
338 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
339 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
340 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
341
342 // Deactivate top layer.
343 config_.simulcast_layers[0].active = false;
344 EXPECT_TRUE(InitializeCodec());
345 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
346 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
347 EXPECT_FALSE(codec_out_.spatialLayers[2].active);
348
349 // Deactivate middle layer.
350 config_.simulcast_layers[0].active = true;
351 config_.simulcast_layers[1].active = false;
352 EXPECT_TRUE(InitializeCodec());
353 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
354 EXPECT_FALSE(codec_out_.spatialLayers[1].active);
355 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
356}
357
sprang429600d2017-01-26 06:12:26 -0800358} // namespace webrtc