blob: 2b3103d56b422db904107d02299e6b8ef1b24a52 [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"
Sergey Silkin86684962018-03-28 19:32:37 +020012#include "api/video_codecs/video_encoder.h"
13#include "common_types.h" // NOLINT(build/include)
14#include "common_video/include/video_bitrate_allocator.h"
15#include "modules/video_coding/codecs/vp8/temporal_layers.h"
16#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Niels Möller84255bb2017-10-06 13:43:23 +020017#include "rtc_base/refcountedobject.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "test/gtest.h"
sprang429600d2017-01-26 06:12:26 -080019
20namespace webrtc {
21
22namespace {
Niels Möller6c2c13a2018-03-29 13:06:51 +020023static const char* kVp8PayloadName = "VP8";
24static const int kVp8PayloadType = 100;
25static const char* kVp9PayloadName = "VP9";
26static const int kVp9PayloadType = 120;
sprang429600d2017-01-26 06:12:26 -080027static const int kDefaultWidth = 1280;
28static const int kDefaultHeight = 720;
29static const int kDefaultFrameRate = 30;
30static const uint32_t kDefaultMinBitrateBps = 60000;
31static const uint32_t kDefaultTargetBitrateBps = 2000000;
32static const uint32_t kDefaultMaxBitrateBps = 2000000;
33static const uint32_t kDefaultMinTransmitBitrateBps = 400000;
34static const int kDefaultMaxQp = 48;
35static const uint32_t kScreenshareTl0BitrateBps = 100000;
36static const uint32_t kScreenshareCodecTargetBitrateBps = 200000;
37static const uint32_t kScreenshareDefaultFramerate = 5;
38// Bitrates for the temporal layers of the higher screenshare simulcast stream.
39static const uint32_t kHighScreenshareTl0Bps = 800000;
40static const uint32_t kHighScreenshareTl1Bps = 1200000;
41} // namespace
42
sprang429600d2017-01-26 06:12:26 -080043// TODO(sprang): Extend coverage to handle the rest of the codec initializer.
44class VideoCodecInitializerTest : public ::testing::Test {
45 public:
46 VideoCodecInitializerTest() : nack_enabled_(false) {}
47 virtual ~VideoCodecInitializerTest() {}
48
49 protected:
50 void SetUpFor(VideoCodecType type,
51 int num_spatial_streams,
52 int num_temporal_streams,
53 bool screenshare) {
54 config_ = VideoEncoderConfig();
55 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);
Niels Möller6c2c13a2018-03-29 13:06:51 +020066 settings_.payload_name = kVp8PayloadName;
67 settings_.payload_type = kVp8PayloadType;
Sergey Silkin86684962018-03-28 19:32:37 +020068 } else if (type == VideoCodecType::kVideoCodecVP9) {
69 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
70 vp9_settings.numberOfSpatialLayers = num_spatial_streams;
71 vp9_settings.numberOfTemporalLayers = num_temporal_streams;
72 config_.encoder_specific_settings = new rtc::RefCountedObject<
73 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
Niels Möller6c2c13a2018-03-29 13:06:51 +020074 settings_.payload_name = kVp9PayloadName;
75 settings_.payload_type = kVp9PayloadType;
Sergey Silkin86684962018-03-28 19:32:37 +020076 } else if (type != VideoCodecType::kVideoCodecMultiplex) {
sprang429600d2017-01-26 06:12:26 -080077 ADD_FAILURE() << "Unexpected codec type: " << type;
78 }
79 }
80
81 bool InitializeCodec() {
82 codec_out_ = VideoCodec();
83 bitrate_allocator_out_.reset();
84 temporal_layers_.clear();
Niels Möller6c2c13a2018-03-29 13:06:51 +020085 if (!VideoCodecInitializer::SetupCodec(config_, settings_, streams_,
86 nack_enabled_, &codec_out_,
sprang429600d2017-01-26 06:12:26 -080087 &bitrate_allocator_out_)) {
88 return false;
89 }
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080090 if (codec_out_.codecType == VideoCodecType::kVideoCodecMultiplex)
Emircan Uysaler0a375472017-12-11 12:21:02 +053091 return true;
Erik Språng82fad3d2018-03-21 09:57:23 +010092
sprang429600d2017-01-26 06:12:26 -080093 // Make sure temporal layers instances have been created.
94 if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
sprang429600d2017-01-26 06:12:26 -080095 for (int i = 0; i < codec_out_.numberOfSimulcastStreams; ++i) {
Erik Språng82fad3d2018-03-21 09:57:23 +010096 temporal_layers_.emplace_back(
Niels Möller150dcb02018-03-27 14:16:55 +020097 TemporalLayers::CreateTemporalLayers(codec_out_, i));
sprang429600d2017-01-26 06:12:26 -080098 }
99 }
100 return true;
101 }
102
103 VideoStream DefaultStream() {
104 VideoStream stream;
105 stream.width = kDefaultWidth;
106 stream.height = kDefaultHeight;
107 stream.max_framerate = kDefaultFrameRate;
108 stream.min_bitrate_bps = kDefaultMinBitrateBps;
109 stream.target_bitrate_bps = kDefaultTargetBitrateBps;
110 stream.max_bitrate_bps = kDefaultMaxBitrateBps;
111 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100112 stream.num_temporal_layers = 1;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800113 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800114 return stream;
115 }
116
117 VideoStream DefaultScreenshareStream() {
118 VideoStream stream = DefaultStream();
119 stream.min_bitrate_bps = 30000;
120 stream.target_bitrate_bps = kScreenshareTl0BitrateBps;
121 stream.max_bitrate_bps = 1000000;
122 stream.max_framerate = kScreenshareDefaultFramerate;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100123 stream.num_temporal_layers = 2;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800124 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800125 return stream;
126 }
127
128 // Input settings.
129 VideoEncoderConfig config_;
Niels Möller6c2c13a2018-03-29 13:06:51 +0200130 VideoSendStream::Config::EncoderSettings settings_;
sprang429600d2017-01-26 06:12:26 -0800131 std::vector<VideoStream> streams_;
132 bool nack_enabled_;
133
134 // Output.
135 VideoCodec codec_out_;
136 std::unique_ptr<VideoBitrateAllocator> bitrate_allocator_out_;
137 std::vector<std::unique_ptr<TemporalLayers>> temporal_layers_;
138};
139
140TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
141 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
142 streams_.push_back(DefaultStream());
143 EXPECT_TRUE(InitializeCodec());
144
145 BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
146 kDefaultTargetBitrateBps, kDefaultFrameRate);
147 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
148 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
149 EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
150}
151
Seth Hampson46e31ba2018-01-18 10:39:54 -0800152TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
153 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
154 VideoStream inactive_stream = DefaultStream();
155 inactive_stream.active = false;
156 streams_.push_back(inactive_stream);
157 EXPECT_TRUE(InitializeCodec());
158
159 BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
160 kDefaultTargetBitrateBps, kDefaultFrameRate);
161 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
162 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
163 EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
164}
165
sprang429600d2017-01-26 06:12:26 -0800166TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
167 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
168 streams_.push_back(DefaultScreenshareStream());
169 EXPECT_TRUE(InitializeCodec());
170
171 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
172 EXPECT_EQ(2u, codec_out_.VP8()->numberOfTemporalLayers);
173 BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
174 kScreenshareCodecTargetBitrateBps, kScreenshareDefaultFramerate);
175 EXPECT_EQ(kScreenshareCodecTargetBitrateBps,
176 bitrate_allocation.get_sum_bps());
177 EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
178}
179
Seth Hampson46e31ba2018-01-18 10:39:54 -0800180TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800181 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
182 streams_.push_back(DefaultScreenshareStream());
183 VideoStream video_stream = DefaultStream();
184 video_stream.max_framerate = kScreenshareDefaultFramerate;
185 streams_.push_back(video_stream);
186 EXPECT_TRUE(InitializeCodec());
187
188 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
189 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
190 const uint32_t max_bitrate_bps =
191 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
192 BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
193 max_bitrate_bps, kScreenshareDefaultFramerate);
194 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
195 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
196 bitrate_allocation.GetSpatialLayerSum(0));
197 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
198 bitrate_allocation.GetSpatialLayerSum(1));
199}
200
Seth Hampson46e31ba2018-01-18 10:39:54 -0800201// Tests that when a video stream is inactive, then the bitrate allocation will
202// be 0 for that stream.
203TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
204 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
205 streams_.push_back(DefaultScreenshareStream());
206 VideoStream inactive_video_stream = DefaultStream();
207 inactive_video_stream.active = false;
208 inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
209 streams_.push_back(inactive_video_stream);
210 EXPECT_TRUE(InitializeCodec());
211
212 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
213 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
214 const uint32_t target_bitrate =
215 streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
216 BitrateAllocation bitrate_allocation = bitrate_allocator_out_->GetAllocation(
217 target_bitrate, kScreenshareDefaultFramerate);
218 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
219 bitrate_allocation.get_sum_bps());
220 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
221 bitrate_allocation.GetSpatialLayerSum(0));
222 EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
223}
224
225TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800226 // Two simulcast streams, the lower one using legacy settings (two temporal
227 // streams, 5fps), the higher one using 3 temporal streams and 30fps.
228 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
229 streams_.push_back(DefaultScreenshareStream());
230 VideoStream video_stream = DefaultStream();
Sergey Silkina796a7e2018-03-01 15:11:29 +0100231 video_stream.num_temporal_layers = 3;
sprang429600d2017-01-26 06:12:26 -0800232 streams_.push_back(video_stream);
233 EXPECT_TRUE(InitializeCodec());
234
235 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
236 EXPECT_EQ(3u, codec_out_.VP8()->numberOfTemporalLayers);
237 const uint32_t max_bitrate_bps =
238 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
239 BitrateAllocation bitrate_allocation =
240 bitrate_allocator_out_->GetAllocation(max_bitrate_bps, kDefaultFrameRate);
241 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
242 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
243 bitrate_allocation.GetSpatialLayerSum(0));
244 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
245 bitrate_allocation.GetSpatialLayerSum(1));
246 EXPECT_EQ(kHighScreenshareTl0Bps, bitrate_allocation.GetBitrate(1, 0));
247 EXPECT_EQ(kHighScreenshareTl1Bps - kHighScreenshareTl0Bps,
248 bitrate_allocation.GetBitrate(1, 1));
249}
250
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800251TEST_F(VideoCodecInitializerTest, SingleStreamMultiplexCodec) {
252 SetUpFor(VideoCodecType::kVideoCodecMultiplex, 1, 1, true);
Emircan Uysaler0a375472017-12-11 12:21:02 +0530253 streams_.push_back(DefaultStream());
254 EXPECT_TRUE(InitializeCodec());
255}
256
Sergey Silkin86684962018-03-28 19:32:37 +0200257TEST_F(VideoCodecInitializerTest, Vp9SvcDefaultLayering) {
258 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
259 VideoStream stream = DefaultStream();
260 stream.num_temporal_layers = 3;
261 streams_.push_back(stream);
262
263 EXPECT_TRUE(InitializeCodec());
264 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 3u);
265 EXPECT_EQ(codec_out_.VP9()->numberOfTemporalLayers, 3u);
266}
267
268TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) {
269 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
270 VideoStream stream = DefaultStream();
271 stream.num_temporal_layers = 3;
272 // Set resolution which is only enough to produce 2 spatial layers.
273 stream.width = kMinVp9SpatialLayerWidth * 2;
274 stream.height = kMinVp9SpatialLayerHeight * 2;
275
276 streams_.push_back(stream);
277
278 EXPECT_TRUE(InitializeCodec());
279 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 2u);
280}
281
sprang429600d2017-01-26 06:12:26 -0800282} // namespace webrtc