blob: ceff1ebaf7427bf928fe7e6adbe03c530a187ce3 [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"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080012#include "api/video/builtin_video_bitrate_allocator_factory.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020013#include "api/video_codecs/create_vp8_temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020014#include "api/video_codecs/video_encoder.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020015#include "api/video_codecs/vp8_temporal_layers.h"
Sergey Silkin86684962018-03-28 19:32:37 +020016#include "common_types.h" // NOLINT(build/include)
Sergey Silkin86684962018-03-28 19:32:37 +020017#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080018#include "rtc_base/checks.h"
Niels Möller84255bb2017-10-06 13:43:23 +020019#include "rtc_base/refcountedobject.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "test/gtest.h"
sprang429600d2017-01-26 06:12:26 -080021
22namespace webrtc {
23
24namespace {
sprang429600d2017-01-26 06:12:26 -080025static const int kDefaultWidth = 1280;
26static const int kDefaultHeight = 720;
27static const int kDefaultFrameRate = 30;
28static const uint32_t kDefaultMinBitrateBps = 60000;
29static const uint32_t kDefaultTargetBitrateBps = 2000000;
30static const uint32_t kDefaultMaxBitrateBps = 2000000;
31static const uint32_t kDefaultMinTransmitBitrateBps = 400000;
32static const int kDefaultMaxQp = 48;
Erik Språng5e898d62018-07-06 16:32:20 +020033static const uint32_t kScreenshareTl0BitrateBps = 200000;
sprang429600d2017-01-26 06:12:26 -080034static const uint32_t kScreenshareCodecTargetBitrateBps = 200000;
35static const uint32_t kScreenshareDefaultFramerate = 5;
36// Bitrates for the temporal layers of the higher screenshare simulcast stream.
37static const uint32_t kHighScreenshareTl0Bps = 800000;
38static const uint32_t kHighScreenshareTl1Bps = 1200000;
39} // namespace
40
sprang429600d2017-01-26 06:12:26 -080041// TODO(sprang): Extend coverage to handle the rest of the codec initializer.
42class VideoCodecInitializerTest : public ::testing::Test {
43 public:
Niels Möllerf1338562018-04-26 09:51:47 +020044 VideoCodecInitializerTest() {}
sprang429600d2017-01-26 06:12:26 -080045 virtual ~VideoCodecInitializerTest() {}
46
47 protected:
48 void SetUpFor(VideoCodecType type,
49 int num_spatial_streams,
50 int num_temporal_streams,
51 bool screenshare) {
52 config_ = VideoEncoderConfig();
Niels Möller259a4972018-04-05 15:36:51 +020053 config_.codec_type = type;
54
sprang429600d2017-01-26 06:12:26 -080055 if (screenshare) {
56 config_.min_transmit_bitrate_bps = kDefaultMinTransmitBitrateBps;
57 config_.content_type = VideoEncoderConfig::ContentType::kScreen;
58 }
59
60 if (type == VideoCodecType::kVideoCodecVP8) {
61 config_.number_of_streams = num_spatial_streams;
62 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
63 vp8_settings.numberOfTemporalLayers = num_temporal_streams;
64 config_.encoder_specific_settings = new rtc::RefCountedObject<
65 webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
Sergey Silkin86684962018-03-28 19:32:37 +020066 } else if (type == VideoCodecType::kVideoCodecVP9) {
67 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
68 vp9_settings.numberOfSpatialLayers = num_spatial_streams;
69 vp9_settings.numberOfTemporalLayers = num_temporal_streams;
70 config_.encoder_specific_settings = new rtc::RefCountedObject<
71 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
72 } else if (type != VideoCodecType::kVideoCodecMultiplex) {
sprang429600d2017-01-26 06:12:26 -080073 ADD_FAILURE() << "Unexpected codec type: " << type;
74 }
75 }
76
77 bool InitializeCodec() {
78 codec_out_ = VideoCodec();
sprang429600d2017-01-26 06:12:26 -080079 temporal_layers_.clear();
Jiawei Ouc2ebe212018-11-08 10:02:56 -080080 if (!VideoCodecInitializer::SetupCodec(config_, streams_, &codec_out_)) {
sprang429600d2017-01-26 06:12:26 -080081 return false;
82 }
Jiawei Ouc2ebe212018-11-08 10:02:56 -080083 bitrate_allocator_ = CreateBuiltinVideoBitrateAllocatorFactory()
84 ->CreateVideoBitrateAllocator(codec_out_);
85 RTC_CHECK(bitrate_allocator_);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080086 if (codec_out_.codecType == VideoCodecType::kVideoCodecMultiplex)
Emircan Uysaler0a375472017-12-11 12:21:02 +053087 return true;
Erik Språng82fad3d2018-03-21 09:57:23 +010088
sprang429600d2017-01-26 06:12:26 -080089 // Make sure temporal layers instances have been created.
90 if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
sprang429600d2017-01-26 06:12:26 -080091 for (int i = 0; i < codec_out_.numberOfSimulcastStreams; ++i) {
Erik Språng4529fbc2018-10-12 10:30:31 +020092 temporal_layers_.emplace_back(
93 CreateVp8TemporalLayers(Vp8TemporalLayersType::kFixedPattern,
94 codec_out_.VP8()->numberOfTemporalLayers));
sprang429600d2017-01-26 06:12:26 -080095 }
96 }
97 return true;
98 }
99
100 VideoStream DefaultStream() {
101 VideoStream stream;
102 stream.width = kDefaultWidth;
103 stream.height = kDefaultHeight;
104 stream.max_framerate = kDefaultFrameRate;
105 stream.min_bitrate_bps = kDefaultMinBitrateBps;
106 stream.target_bitrate_bps = kDefaultTargetBitrateBps;
107 stream.max_bitrate_bps = kDefaultMaxBitrateBps;
108 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100109 stream.num_temporal_layers = 1;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800110 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800111 return stream;
112 }
113
114 VideoStream DefaultScreenshareStream() {
115 VideoStream stream = DefaultStream();
116 stream.min_bitrate_bps = 30000;
117 stream.target_bitrate_bps = kScreenshareTl0BitrateBps;
118 stream.max_bitrate_bps = 1000000;
119 stream.max_framerate = kScreenshareDefaultFramerate;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100120 stream.num_temporal_layers = 2;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800121 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800122 return stream;
123 }
124
125 // Input settings.
126 VideoEncoderConfig config_;
sprang429600d2017-01-26 06:12:26 -0800127 std::vector<VideoStream> streams_;
sprang429600d2017-01-26 06:12:26 -0800128
129 // Output.
130 VideoCodec codec_out_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800131 std::unique_ptr<VideoBitrateAllocator> bitrate_allocator_;
Erik Språng4529fbc2018-10-12 10:30:31 +0200132 std::vector<std::unique_ptr<Vp8TemporalLayers>> temporal_layers_;
sprang429600d2017-01-26 06:12:26 -0800133};
134
135TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
136 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
137 streams_.push_back(DefaultStream());
138 EXPECT_TRUE(InitializeCodec());
139
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800140 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
141 kDefaultTargetBitrateBps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800142 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
143 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
144 EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
145}
146
Seth Hampson46e31ba2018-01-18 10:39:54 -0800147TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
148 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
149 VideoStream inactive_stream = DefaultStream();
150 inactive_stream.active = false;
151 streams_.push_back(inactive_stream);
152 EXPECT_TRUE(InitializeCodec());
153
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800154 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
155 kDefaultTargetBitrateBps, kDefaultFrameRate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800156 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
157 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
158 EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
159}
160
sprang429600d2017-01-26 06:12:26 -0800161TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
162 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
163 streams_.push_back(DefaultScreenshareStream());
164 EXPECT_TRUE(InitializeCodec());
165
166 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
167 EXPECT_EQ(2u, codec_out_.VP8()->numberOfTemporalLayers);
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800168 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
169 kScreenshareCodecTargetBitrateBps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800170 EXPECT_EQ(kScreenshareCodecTargetBitrateBps,
171 bitrate_allocation.get_sum_bps());
172 EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
173}
174
Seth Hampson46e31ba2018-01-18 10:39:54 -0800175TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800176 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
177 streams_.push_back(DefaultScreenshareStream());
178 VideoStream video_stream = DefaultStream();
179 video_stream.max_framerate = kScreenshareDefaultFramerate;
180 streams_.push_back(video_stream);
181 EXPECT_TRUE(InitializeCodec());
182
183 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
184 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
185 const uint32_t max_bitrate_bps =
186 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800187 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
188 max_bitrate_bps, kScreenshareDefaultFramerate);
sprang429600d2017-01-26 06:12:26 -0800189 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
190 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
191 bitrate_allocation.GetSpatialLayerSum(0));
192 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
193 bitrate_allocation.GetSpatialLayerSum(1));
194}
195
Seth Hampson46e31ba2018-01-18 10:39:54 -0800196// Tests that when a video stream is inactive, then the bitrate allocation will
197// be 0 for that stream.
198TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
199 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
200 streams_.push_back(DefaultScreenshareStream());
201 VideoStream inactive_video_stream = DefaultStream();
202 inactive_video_stream.active = false;
203 inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
204 streams_.push_back(inactive_video_stream);
205 EXPECT_TRUE(InitializeCodec());
206
207 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
208 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
209 const uint32_t target_bitrate =
210 streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800211 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->GetAllocation(
212 target_bitrate, kScreenshareDefaultFramerate);
Seth Hampson46e31ba2018-01-18 10:39:54 -0800213 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
214 bitrate_allocation.get_sum_bps());
215 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
216 bitrate_allocation.GetSpatialLayerSum(0));
217 EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
218}
219
220TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800221 // Two simulcast streams, the lower one using legacy settings (two temporal
222 // streams, 5fps), the higher one using 3 temporal streams and 30fps.
223 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
224 streams_.push_back(DefaultScreenshareStream());
225 VideoStream video_stream = DefaultStream();
Sergey Silkina796a7e2018-03-01 15:11:29 +0100226 video_stream.num_temporal_layers = 3;
sprang429600d2017-01-26 06:12:26 -0800227 streams_.push_back(video_stream);
228 EXPECT_TRUE(InitializeCodec());
229
230 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
231 EXPECT_EQ(3u, codec_out_.VP8()->numberOfTemporalLayers);
232 const uint32_t max_bitrate_bps =
233 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Erik Språng566124a2018-04-23 12:32:22 +0200234 VideoBitrateAllocation bitrate_allocation =
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800235 bitrate_allocator_->GetAllocation(max_bitrate_bps, kDefaultFrameRate);
sprang429600d2017-01-26 06:12:26 -0800236 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
237 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
238 bitrate_allocation.GetSpatialLayerSum(0));
239 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
240 bitrate_allocation.GetSpatialLayerSum(1));
241 EXPECT_EQ(kHighScreenshareTl0Bps, bitrate_allocation.GetBitrate(1, 0));
242 EXPECT_EQ(kHighScreenshareTl1Bps - kHighScreenshareTl0Bps,
243 bitrate_allocation.GetBitrate(1, 1));
244}
245
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800246TEST_F(VideoCodecInitializerTest, SingleStreamMultiplexCodec) {
247 SetUpFor(VideoCodecType::kVideoCodecMultiplex, 1, 1, true);
Emircan Uysaler0a375472017-12-11 12:21:02 +0530248 streams_.push_back(DefaultStream());
249 EXPECT_TRUE(InitializeCodec());
250}
251
Sergey Silkin86684962018-03-28 19:32:37 +0200252TEST_F(VideoCodecInitializerTest, Vp9SvcDefaultLayering) {
253 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
254 VideoStream stream = DefaultStream();
255 stream.num_temporal_layers = 3;
256 streams_.push_back(stream);
257
258 EXPECT_TRUE(InitializeCodec());
259 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 3u);
260 EXPECT_EQ(codec_out_.VP9()->numberOfTemporalLayers, 3u);
261}
262
263TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) {
264 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
265 VideoStream stream = DefaultStream();
266 stream.num_temporal_layers = 3;
267 // Set resolution which is only enough to produce 2 spatial layers.
268 stream.width = kMinVp9SpatialLayerWidth * 2;
269 stream.height = kMinVp9SpatialLayerHeight * 2;
270
271 streams_.push_back(stream);
272
273 EXPECT_TRUE(InitializeCodec());
274 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 2u);
275}
276
Sergey Silkinfafeac32018-04-13 16:36:39 +0200277TEST_F(VideoCodecInitializerTest,
278 Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrate) {
279 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, false);
280 VideoStream stream = DefaultStream();
281 stream.num_temporal_layers = 3;
282 streams_.push_back(stream);
283
284 EXPECT_TRUE(InitializeCodec());
285 EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate,
286 kDefaultMaxBitrateBps / 1000);
287}
288
sprang429600d2017-01-26 06:12:26 -0800289} // namespace webrtc