blob: a90b7b7482114dcba1085db4633835d587b5b7f6 [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"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080018#include "api/video/builtin_video_bitrate_allocator_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010019#include "api/video/video_bitrate_allocation.h"
20#include "api/video/video_bitrate_allocator.h"
21#include "api/video/video_bitrate_allocator_factory.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020022#include "api/video_codecs/create_vp8_temporal_layers.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"
Sergey Silkin86684962018-03-28 19:32:37 +020025#include "common_types.h" // NOLINT(build/include)
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"
Yves Gerey3e707812018-11-28 16:47:49 +010029#include "rtc_base/scoped_ref_ptr.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "test/gtest.h"
sprang429600d2017-01-26 06:12:26 -080031
32namespace webrtc {
33
34namespace {
sprang429600d2017-01-26 06:12:26 -080035static const int kDefaultWidth = 1280;
36static const int kDefaultHeight = 720;
37static const int kDefaultFrameRate = 30;
38static const uint32_t kDefaultMinBitrateBps = 60000;
39static const uint32_t kDefaultTargetBitrateBps = 2000000;
40static const uint32_t kDefaultMaxBitrateBps = 2000000;
41static const uint32_t kDefaultMinTransmitBitrateBps = 400000;
42static const int kDefaultMaxQp = 48;
Erik Språng5e898d62018-07-06 16:32:20 +020043static const uint32_t kScreenshareTl0BitrateBps = 200000;
sprang429600d2017-01-26 06:12:26 -080044static const uint32_t kScreenshareCodecTargetBitrateBps = 200000;
45static const uint32_t kScreenshareDefaultFramerate = 5;
46// Bitrates for the temporal layers of the higher screenshare simulcast stream.
47static const uint32_t kHighScreenshareTl0Bps = 800000;
48static const uint32_t kHighScreenshareTl1Bps = 1200000;
49} // namespace
50
sprang429600d2017-01-26 06:12:26 -080051// TODO(sprang): Extend coverage to handle the rest of the codec initializer.
52class VideoCodecInitializerTest : public ::testing::Test {
53 public:
Niels Möllerf1338562018-04-26 09:51:47 +020054 VideoCodecInitializerTest() {}
sprang429600d2017-01-26 06:12:26 -080055 virtual ~VideoCodecInitializerTest() {}
56
57 protected:
58 void SetUpFor(VideoCodecType type,
59 int num_spatial_streams,
60 int num_temporal_streams,
61 bool screenshare) {
62 config_ = VideoEncoderConfig();
Niels Möller259a4972018-04-05 15:36:51 +020063 config_.codec_type = type;
64
sprang429600d2017-01-26 06:12:26 -080065 if (screenshare) {
66 config_.min_transmit_bitrate_bps = kDefaultMinTransmitBitrateBps;
67 config_.content_type = VideoEncoderConfig::ContentType::kScreen;
68 }
69
70 if (type == VideoCodecType::kVideoCodecVP8) {
71 config_.number_of_streams = num_spatial_streams;
72 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
73 vp8_settings.numberOfTemporalLayers = num_temporal_streams;
74 config_.encoder_specific_settings = new rtc::RefCountedObject<
75 webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
Sergey Silkin86684962018-03-28 19:32:37 +020076 } else if (type == VideoCodecType::kVideoCodecVP9) {
77 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
78 vp9_settings.numberOfSpatialLayers = num_spatial_streams;
79 vp9_settings.numberOfTemporalLayers = num_temporal_streams;
80 config_.encoder_specific_settings = new rtc::RefCountedObject<
81 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
82 } else if (type != VideoCodecType::kVideoCodecMultiplex) {
sprang429600d2017-01-26 06:12:26 -080083 ADD_FAILURE() << "Unexpected codec type: " << type;
84 }
85 }
86
87 bool InitializeCodec() {
88 codec_out_ = VideoCodec();
sprang429600d2017-01-26 06:12:26 -080089 temporal_layers_.clear();
Jiawei Ouc2ebe212018-11-08 10:02:56 -080090 if (!VideoCodecInitializer::SetupCodec(config_, streams_, &codec_out_)) {
sprang429600d2017-01-26 06:12:26 -080091 return false;
92 }
Jiawei Ouc2ebe212018-11-08 10:02:56 -080093 bitrate_allocator_ = CreateBuiltinVideoBitrateAllocatorFactory()
94 ->CreateVideoBitrateAllocator(codec_out_);
95 RTC_CHECK(bitrate_allocator_);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080096 if (codec_out_.codecType == VideoCodecType::kVideoCodecMultiplex)
Emircan Uysaler0a375472017-12-11 12:21:02 +053097 return true;
Erik Språng82fad3d2018-03-21 09:57:23 +010098
sprang429600d2017-01-26 06:12:26 -080099 // Make sure temporal layers instances have been created.
100 if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
sprang429600d2017-01-26 06:12:26 -0800101 for (int i = 0; i < codec_out_.numberOfSimulcastStreams; ++i) {
Erik Språng4529fbc2018-10-12 10:30:31 +0200102 temporal_layers_.emplace_back(
103 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
104 codec_out_.VP8()->numberOfTemporalLayers));
sprang429600d2017-01-26 06:12:26 -0800105 }
106 }
107 return true;
108 }
109
110 VideoStream DefaultStream() {
111 VideoStream stream;
112 stream.width = kDefaultWidth;
113 stream.height = kDefaultHeight;
114 stream.max_framerate = kDefaultFrameRate;
115 stream.min_bitrate_bps = kDefaultMinBitrateBps;
116 stream.target_bitrate_bps = kDefaultTargetBitrateBps;
117 stream.max_bitrate_bps = kDefaultMaxBitrateBps;
118 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100119 stream.num_temporal_layers = 1;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800120 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800121 return stream;
122 }
123
124 VideoStream DefaultScreenshareStream() {
125 VideoStream stream = DefaultStream();
126 stream.min_bitrate_bps = 30000;
127 stream.target_bitrate_bps = kScreenshareTl0BitrateBps;
128 stream.max_bitrate_bps = 1000000;
129 stream.max_framerate = kScreenshareDefaultFramerate;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100130 stream.num_temporal_layers = 2;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800131 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800132 return stream;
133 }
134
135 // Input settings.
136 VideoEncoderConfig config_;
sprang429600d2017-01-26 06:12:26 -0800137 std::vector<VideoStream> streams_;
sprang429600d2017-01-26 06:12:26 -0800138
139 // Output.
140 VideoCodec codec_out_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800141 std::unique_ptr<VideoBitrateAllocator> bitrate_allocator_;
Erik Språng4529fbc2018-10-12 10:30:31 +0200142 std::vector<std::unique_ptr<Vp8TemporalLayers>> temporal_layers_;
sprang429600d2017-01-26 06:12:26 -0800143};
144
145TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
146 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
147 streams_.push_back(DefaultStream());
148 EXPECT_TRUE(InitializeCodec());
149
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800150 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
151 kDefaultTargetBitrateBps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800152 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
153 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
154 EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
155}
156
Seth Hampson46e31ba2018-01-18 10:39:54 -0800157TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
158 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
159 VideoStream inactive_stream = DefaultStream();
160 inactive_stream.active = false;
161 streams_.push_back(inactive_stream);
162 EXPECT_TRUE(InitializeCodec());
163
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800164 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
165 kDefaultTargetBitrateBps, kDefaultFrameRate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800166 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
167 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
168 EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
169}
170
sprang429600d2017-01-26 06:12:26 -0800171TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
172 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
173 streams_.push_back(DefaultScreenshareStream());
174 EXPECT_TRUE(InitializeCodec());
175
176 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
177 EXPECT_EQ(2u, codec_out_.VP8()->numberOfTemporalLayers);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800178 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
179 kScreenshareCodecTargetBitrateBps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800180 EXPECT_EQ(kScreenshareCodecTargetBitrateBps,
181 bitrate_allocation.get_sum_bps());
182 EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
183}
184
Seth Hampson46e31ba2018-01-18 10:39:54 -0800185TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800186 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
187 streams_.push_back(DefaultScreenshareStream());
188 VideoStream video_stream = DefaultStream();
189 video_stream.max_framerate = kScreenshareDefaultFramerate;
190 streams_.push_back(video_stream);
191 EXPECT_TRUE(InitializeCodec());
192
193 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
194 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
195 const uint32_t max_bitrate_bps =
196 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800197 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
198 max_bitrate_bps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800199 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
200 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
201 bitrate_allocation.GetSpatialLayerSum(0));
202 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
203 bitrate_allocation.GetSpatialLayerSum(1));
204}
205
Seth Hampson46e31ba2018-01-18 10:39:54 -0800206// Tests that when a video stream is inactive, then the bitrate allocation will
207// be 0 for that stream.
208TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
209 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
210 streams_.push_back(DefaultScreenshareStream());
211 VideoStream inactive_video_stream = DefaultStream();
212 inactive_video_stream.active = false;
213 inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
214 streams_.push_back(inactive_video_stream);
215 EXPECT_TRUE(InitializeCodec());
216
217 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
218 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
219 const uint32_t target_bitrate =
220 streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800221 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
222 target_bitrate, kScreenshareDefaultFramerate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800223 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
224 bitrate_allocation.get_sum_bps());
225 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
226 bitrate_allocation.GetSpatialLayerSum(0));
227 EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
228}
229
230TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800231 // Two simulcast streams, the lower one using legacy settings (two temporal
232 // streams, 5fps), the higher one using 3 temporal streams and 30fps.
233 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
234 streams_.push_back(DefaultScreenshareStream());
235 VideoStream video_stream = DefaultStream();
Sergey Silkina796a7e2018-03-01 15:11:29 +0100236 video_stream.num_temporal_layers = 3;
sprang429600d2017-01-26 06:12:26 -0800237 streams_.push_back(video_stream);
238 EXPECT_TRUE(InitializeCodec());
239
240 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
241 EXPECT_EQ(3u, codec_out_.VP8()->numberOfTemporalLayers);
242 const uint32_t max_bitrate_bps =
243 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Erik Språng566124a2018-04-23 12:32:22 +0200244 VideoBitrateAllocation bitrate_allocation =
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800245 bitrate_allocator_->GetAllocation(max_bitrate_bps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800246 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
247 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
248 bitrate_allocation.GetSpatialLayerSum(0));
249 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
250 bitrate_allocation.GetSpatialLayerSum(1));
251 EXPECT_EQ(kHighScreenshareTl0Bps, bitrate_allocation.GetBitrate(1, 0));
252 EXPECT_EQ(kHighScreenshareTl1Bps - kHighScreenshareTl0Bps,
253 bitrate_allocation.GetBitrate(1, 1));
254}
255
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800256TEST_F(VideoCodecInitializerTest, SingleStreamMultiplexCodec) {
257 SetUpFor(VideoCodecType::kVideoCodecMultiplex, 1, 1, true);
Emircan Uysaler0a375472017-12-11 12:21:02 +0530258 streams_.push_back(DefaultStream());
259 EXPECT_TRUE(InitializeCodec());
260}
261
Sergey Silkin86684962018-03-28 19:32:37 +0200262TEST_F(VideoCodecInitializerTest, Vp9SvcDefaultLayering) {
263 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
264 VideoStream stream = DefaultStream();
265 stream.num_temporal_layers = 3;
266 streams_.push_back(stream);
267
268 EXPECT_TRUE(InitializeCodec());
269 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 3u);
270 EXPECT_EQ(codec_out_.VP9()->numberOfTemporalLayers, 3u);
271}
272
273TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) {
274 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
275 VideoStream stream = DefaultStream();
276 stream.num_temporal_layers = 3;
277 // Set resolution which is only enough to produce 2 spatial layers.
278 stream.width = kMinVp9SpatialLayerWidth * 2;
279 stream.height = kMinVp9SpatialLayerHeight * 2;
280
281 streams_.push_back(stream);
282
283 EXPECT_TRUE(InitializeCodec());
284 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 2u);
285}
286
Sergey Silkinfafeac32018-04-13 16:36:39 +0200287TEST_F(VideoCodecInitializerTest,
288 Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrate) {
289 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, false);
290 VideoStream stream = DefaultStream();
291 stream.num_temporal_layers = 3;
292 streams_.push_back(stream);
293
294 EXPECT_TRUE(InitializeCodec());
295 EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate,
296 kDefaultMaxBitrateBps / 1000);
297}
298
Sergey Silkin33120922018-11-28 13:32:13 +0100299TEST_F(VideoCodecInitializerTest,
300 Vp9KeepBitrateLimitsIfNumberOfSpatialLayersIsReducedToOne) {
301 // Request 3 spatial layers for 320x180 input. Actual number of layers will be
302 // reduced to 1 due to low input resolution but SVC bitrate limits should be
303 // applied.
304 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
305 VideoStream stream = DefaultStream();
306 stream.width = 320;
307 stream.height = 180;
308 stream.num_temporal_layers = 3;
309 streams_.push_back(stream);
310
311 EXPECT_TRUE(InitializeCodec());
312 EXPECT_LT(codec_out_.spatialLayers[0].maxBitrate,
313 kDefaultMaxBitrateBps / 1000);
314}
315
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100316TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) {
317 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 1, false);
318 VideoStream stream = DefaultStream();
319 streams_.push_back(stream);
320
321 config_.simulcast_layers.resize(3);
322
323 // Activate all layers.
324 config_.simulcast_layers[0].active = true;
325 config_.simulcast_layers[1].active = true;
326 config_.simulcast_layers[2].active = true;
327 EXPECT_TRUE(InitializeCodec());
328 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
329 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
330 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
331
332 // Deactivate top layer.
333 config_.simulcast_layers[0].active = false;
334 EXPECT_TRUE(InitializeCodec());
335 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
336 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
337 EXPECT_FALSE(codec_out_.spatialLayers[2].active);
338
339 // Deactivate middle layer.
340 config_.simulcast_layers[0].active = true;
341 config_.simulcast_layers[1].active = false;
342 EXPECT_TRUE(InitializeCodec());
343 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
344 EXPECT_FALSE(codec_out_.spatialLayers[1].active);
345 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
346}
347
sprang429600d2017-01-26 06:12:26 -0800348} // namespace webrtc