blob: ca1da2cc8c1131200acf17aeb40785732ccc2970 [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>
Jonas Olssona4d87372019-07-05 19:08:33 +020015
Yves Gerey3e707812018-11-28 16:47:49 +010016#include <memory>
17
18#include "absl/types/optional.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010019#include "api/scoped_refptr.h"
Elad Alon45befc52019-07-02 11:20:09 +020020#include "api/test/mock_fec_controller_override.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080021#include "api/video/builtin_video_bitrate_allocator_factory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010022#include "api/video/video_bitrate_allocation.h"
23#include "api/video/video_bitrate_allocator.h"
24#include "api/video/video_bitrate_allocator_factory.h"
Sergey Silkin86684962018-03-28 19:32:37 +020025#include "api/video_codecs/video_encoder.h"
Erik Språng4529fbc2018-10-12 10:30:31 +020026#include "api/video_codecs/vp8_temporal_layers.h"
Elad Aloncde8ab22019-03-20 11:56:20 +010027#include "api/video_codecs/vp8_temporal_layers_factory.h"
Sergey Silkin86684962018-03-28 19:32:37 +020028#include "modules/video_coding/codecs/vp9/include/vp9_globals.h"
Jiawei Ouc2ebe212018-11-08 10:02:56 -080029#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "rtc_base/ref_counted_object.h"
Elad Alon45befc52019-07-02 11:20:09 +020031#include "test/gmock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "test/gtest.h"
sprang429600d2017-01-26 06:12:26 -080033
34namespace webrtc {
35
36namespace {
sprang429600d2017-01-26 06:12:26 -080037static const int kDefaultWidth = 1280;
38static const int kDefaultHeight = 720;
39static const int kDefaultFrameRate = 30;
40static const uint32_t kDefaultMinBitrateBps = 60000;
41static const uint32_t kDefaultTargetBitrateBps = 2000000;
42static const uint32_t kDefaultMaxBitrateBps = 2000000;
43static const uint32_t kDefaultMinTransmitBitrateBps = 400000;
44static const int kDefaultMaxQp = 48;
Erik Språng5e898d62018-07-06 16:32:20 +020045static const uint32_t kScreenshareTl0BitrateBps = 200000;
sprang429600d2017-01-26 06:12:26 -080046static const uint32_t kScreenshareCodecTargetBitrateBps = 200000;
47static const uint32_t kScreenshareDefaultFramerate = 5;
48// Bitrates for the temporal layers of the higher screenshare simulcast stream.
49static const uint32_t kHighScreenshareTl0Bps = 800000;
50static const uint32_t kHighScreenshareTl1Bps = 1200000;
51} // namespace
52
sprang429600d2017-01-26 06:12:26 -080053// TODO(sprang): Extend coverage to handle the rest of the codec initializer.
54class VideoCodecInitializerTest : public ::testing::Test {
55 public:
Niels Möllerf1338562018-04-26 09:51:47 +020056 VideoCodecInitializerTest() {}
sprang429600d2017-01-26 06:12:26 -080057 virtual ~VideoCodecInitializerTest() {}
58
59 protected:
60 void SetUpFor(VideoCodecType type,
61 int num_spatial_streams,
62 int num_temporal_streams,
63 bool screenshare) {
64 config_ = VideoEncoderConfig();
Niels Möller259a4972018-04-05 15:36:51 +020065 config_.codec_type = type;
66
sprang429600d2017-01-26 06:12:26 -080067 if (screenshare) {
68 config_.min_transmit_bitrate_bps = kDefaultMinTransmitBitrateBps;
69 config_.content_type = VideoEncoderConfig::ContentType::kScreen;
70 }
71
72 if (type == VideoCodecType::kVideoCodecVP8) {
73 config_.number_of_streams = num_spatial_streams;
74 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
75 vp8_settings.numberOfTemporalLayers = num_temporal_streams;
76 config_.encoder_specific_settings = new rtc::RefCountedObject<
77 webrtc::VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
Sergey Silkin86684962018-03-28 19:32:37 +020078 } else if (type == VideoCodecType::kVideoCodecVP9) {
79 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
80 vp9_settings.numberOfSpatialLayers = num_spatial_streams;
81 vp9_settings.numberOfTemporalLayers = num_temporal_streams;
82 config_.encoder_specific_settings = new rtc::RefCountedObject<
83 webrtc::VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
84 } else if (type != VideoCodecType::kVideoCodecMultiplex) {
sprang429600d2017-01-26 06:12:26 -080085 ADD_FAILURE() << "Unexpected codec type: " << type;
86 }
87 }
88
89 bool InitializeCodec() {
90 codec_out_ = VideoCodec();
Elad Aloncde8ab22019-03-20 11:56:20 +010091 frame_buffer_controller_.reset();
Jiawei Ouc2ebe212018-11-08 10:02:56 -080092 if (!VideoCodecInitializer::SetupCodec(config_, streams_, &codec_out_)) {
sprang429600d2017-01-26 06:12:26 -080093 return false;
94 }
Jiawei Ouc2ebe212018-11-08 10:02:56 -080095 bitrate_allocator_ = CreateBuiltinVideoBitrateAllocatorFactory()
96 ->CreateVideoBitrateAllocator(codec_out_);
97 RTC_CHECK(bitrate_allocator_);
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -080098 if (codec_out_.codecType == VideoCodecType::kVideoCodecMultiplex)
Emircan Uysaler0a375472017-12-11 12:21:02 +053099 return true;
Erik Språng82fad3d2018-03-21 09:57:23 +0100100
sprang429600d2017-01-26 06:12:26 -0800101 // Make sure temporal layers instances have been created.
102 if (codec_out_.codecType == VideoCodecType::kVideoCodecVP8) {
Elad Aloncde8ab22019-03-20 11:56:20 +0100103 Vp8TemporalLayersFactory factory;
Elad Alona2795842019-06-07 23:10:00 +0200104 const VideoEncoder::Settings settings(VideoEncoder::Capabilities(false),
105 1, 1000);
Elad Alon45befc52019-07-02 11:20:09 +0200106 frame_buffer_controller_ =
107 factory.Create(codec_out_, settings, &fec_controller_override_);
sprang429600d2017-01-26 06:12:26 -0800108 }
109 return true;
110 }
111
112 VideoStream DefaultStream() {
113 VideoStream stream;
114 stream.width = kDefaultWidth;
115 stream.height = kDefaultHeight;
116 stream.max_framerate = kDefaultFrameRate;
117 stream.min_bitrate_bps = kDefaultMinBitrateBps;
118 stream.target_bitrate_bps = kDefaultTargetBitrateBps;
119 stream.max_bitrate_bps = kDefaultMaxBitrateBps;
120 stream.max_qp = kDefaultMaxQp;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100121 stream.num_temporal_layers = 1;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800122 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800123 return stream;
124 }
125
126 VideoStream DefaultScreenshareStream() {
127 VideoStream stream = DefaultStream();
128 stream.min_bitrate_bps = 30000;
129 stream.target_bitrate_bps = kScreenshareTl0BitrateBps;
130 stream.max_bitrate_bps = 1000000;
131 stream.max_framerate = kScreenshareDefaultFramerate;
Sergey Silkina796a7e2018-03-01 15:11:29 +0100132 stream.num_temporal_layers = 2;
Seth Hampson46e31ba2018-01-18 10:39:54 -0800133 stream.active = true;
sprang429600d2017-01-26 06:12:26 -0800134 return stream;
135 }
136
Elad Alon45befc52019-07-02 11:20:09 +0200137 MockFecControllerOverride fec_controller_override_;
138
sprang429600d2017-01-26 06:12:26 -0800139 // Input settings.
140 VideoEncoderConfig config_;
sprang429600d2017-01-26 06:12:26 -0800141 std::vector<VideoStream> streams_;
sprang429600d2017-01-26 06:12:26 -0800142
143 // Output.
144 VideoCodec codec_out_;
Jiawei Ouc2ebe212018-11-08 10:02:56 -0800145 std::unique_ptr<VideoBitrateAllocator> bitrate_allocator_;
Elad Aloncde8ab22019-03-20 11:56:20 +0100146 std::unique_ptr<Vp8FrameBufferController> frame_buffer_controller_;
sprang429600d2017-01-26 06:12:26 -0800147};
148
149TEST_F(VideoCodecInitializerTest, SingleStreamVp8Screenshare) {
150 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
151 streams_.push_back(DefaultStream());
152 EXPECT_TRUE(InitializeCodec());
153
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200154 VideoBitrateAllocation bitrate_allocation =
155 bitrate_allocator_->Allocate(VideoBitrateAllocationParameters(
156 kDefaultTargetBitrateBps, kDefaultFrameRate));
sprang429600d2017-01-26 06:12:26 -0800157 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
158 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
159 EXPECT_EQ(kDefaultTargetBitrateBps, bitrate_allocation.get_sum_bps());
160}
161
Seth Hampson46e31ba2018-01-18 10:39:54 -0800162TEST_F(VideoCodecInitializerTest, SingleStreamVp8ScreenshareInactive) {
163 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 1, true);
164 VideoStream inactive_stream = DefaultStream();
165 inactive_stream.active = false;
166 streams_.push_back(inactive_stream);
167 EXPECT_TRUE(InitializeCodec());
168
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200169 VideoBitrateAllocation bitrate_allocation =
170 bitrate_allocator_->Allocate(VideoBitrateAllocationParameters(
171 kDefaultTargetBitrateBps, kDefaultFrameRate));
Seth Hampson46e31ba2018-01-18 10:39:54 -0800172 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
173 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
174 EXPECT_EQ(0U, bitrate_allocation.get_sum_bps());
175}
176
sprang429600d2017-01-26 06:12:26 -0800177TEST_F(VideoCodecInitializerTest, TemporalLayeredVp8Screenshare) {
178 SetUpFor(VideoCodecType::kVideoCodecVP8, 1, 2, true);
179 streams_.push_back(DefaultScreenshareStream());
180 EXPECT_TRUE(InitializeCodec());
181
182 EXPECT_EQ(1u, codec_out_.numberOfSimulcastStreams);
183 EXPECT_EQ(2u, codec_out_.VP8()->numberOfTemporalLayers);
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200184 VideoBitrateAllocation bitrate_allocation =
185 bitrate_allocator_->Allocate(VideoBitrateAllocationParameters(
186 kScreenshareCodecTargetBitrateBps, kScreenshareDefaultFramerate));
sprang429600d2017-01-26 06:12:26 -0800187 EXPECT_EQ(kScreenshareCodecTargetBitrateBps,
188 bitrate_allocation.get_sum_bps());
189 EXPECT_EQ(kScreenshareTl0BitrateBps, bitrate_allocation.GetBitrate(0, 0));
190}
191
Seth Hampson46e31ba2018-01-18 10:39:54 -0800192TEST_F(VideoCodecInitializerTest, SimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800193 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
194 streams_.push_back(DefaultScreenshareStream());
195 VideoStream video_stream = DefaultStream();
196 video_stream.max_framerate = kScreenshareDefaultFramerate;
197 streams_.push_back(video_stream);
198 EXPECT_TRUE(InitializeCodec());
199
200 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
201 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
202 const uint32_t max_bitrate_bps =
203 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200204 VideoBitrateAllocation bitrate_allocation =
205 bitrate_allocator_->Allocate(VideoBitrateAllocationParameters(
206 max_bitrate_bps, kScreenshareDefaultFramerate));
sprang429600d2017-01-26 06:12:26 -0800207 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
208 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
209 bitrate_allocation.GetSpatialLayerSum(0));
210 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
211 bitrate_allocation.GetSpatialLayerSum(1));
212}
213
Seth Hampson46e31ba2018-01-18 10:39:54 -0800214// Tests that when a video stream is inactive, then the bitrate allocation will
215// be 0 for that stream.
216TEST_F(VideoCodecInitializerTest, SimulcastVp8ScreenshareInactive) {
217 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 1, true);
218 streams_.push_back(DefaultScreenshareStream());
219 VideoStream inactive_video_stream = DefaultStream();
220 inactive_video_stream.active = false;
221 inactive_video_stream.max_framerate = kScreenshareDefaultFramerate;
222 streams_.push_back(inactive_video_stream);
223 EXPECT_TRUE(InitializeCodec());
224
225 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
226 EXPECT_EQ(1u, codec_out_.VP8()->numberOfTemporalLayers);
227 const uint32_t target_bitrate =
228 streams_[0].target_bitrate_bps + streams_[1].target_bitrate_bps;
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200229 VideoBitrateAllocation bitrate_allocation =
230 bitrate_allocator_->Allocate(VideoBitrateAllocationParameters(
231 target_bitrate, kScreenshareDefaultFramerate));
Seth Hampson46e31ba2018-01-18 10:39:54 -0800232 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
233 bitrate_allocation.get_sum_bps());
234 EXPECT_EQ(static_cast<uint32_t>(streams_[0].max_bitrate_bps),
235 bitrate_allocation.GetSpatialLayerSum(0));
236 EXPECT_EQ(0U, bitrate_allocation.GetSpatialLayerSum(1));
237}
238
239TEST_F(VideoCodecInitializerTest, HighFpsSimulcastVp8Screenshare) {
sprang429600d2017-01-26 06:12:26 -0800240 // Two simulcast streams, the lower one using legacy settings (two temporal
241 // streams, 5fps), the higher one using 3 temporal streams and 30fps.
242 SetUpFor(VideoCodecType::kVideoCodecVP8, 2, 3, true);
243 streams_.push_back(DefaultScreenshareStream());
244 VideoStream video_stream = DefaultStream();
Sergey Silkina796a7e2018-03-01 15:11:29 +0100245 video_stream.num_temporal_layers = 3;
sprang429600d2017-01-26 06:12:26 -0800246 streams_.push_back(video_stream);
247 EXPECT_TRUE(InitializeCodec());
248
249 EXPECT_EQ(2u, codec_out_.numberOfSimulcastStreams);
250 EXPECT_EQ(3u, codec_out_.VP8()->numberOfTemporalLayers);
251 const uint32_t max_bitrate_bps =
252 streams_[0].target_bitrate_bps + streams_[1].max_bitrate_bps;
Florent Castelli8bbdb5b2019-08-02 15:16:28 +0200253 VideoBitrateAllocation bitrate_allocation = bitrate_allocator_->Allocate(
254 VideoBitrateAllocationParameters(max_bitrate_bps, kDefaultFrameRate));
sprang429600d2017-01-26 06:12:26 -0800255 EXPECT_EQ(max_bitrate_bps, bitrate_allocation.get_sum_bps());
256 EXPECT_EQ(static_cast<uint32_t>(streams_[0].target_bitrate_bps),
257 bitrate_allocation.GetSpatialLayerSum(0));
258 EXPECT_EQ(static_cast<uint32_t>(streams_[1].max_bitrate_bps),
259 bitrate_allocation.GetSpatialLayerSum(1));
260 EXPECT_EQ(kHighScreenshareTl0Bps, bitrate_allocation.GetBitrate(1, 0));
261 EXPECT_EQ(kHighScreenshareTl1Bps - kHighScreenshareTl0Bps,
262 bitrate_allocation.GetBitrate(1, 1));
263}
264
Emircan Uysalerd7ae3c32018-01-25 13:01:09 -0800265TEST_F(VideoCodecInitializerTest, SingleStreamMultiplexCodec) {
266 SetUpFor(VideoCodecType::kVideoCodecMultiplex, 1, 1, true);
Emircan Uysaler0a375472017-12-11 12:21:02 +0530267 streams_.push_back(DefaultStream());
268 EXPECT_TRUE(InitializeCodec());
269}
270
Sergey Silkin86684962018-03-28 19:32:37 +0200271TEST_F(VideoCodecInitializerTest, Vp9SvcDefaultLayering) {
272 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
273 VideoStream stream = DefaultStream();
274 stream.num_temporal_layers = 3;
275 streams_.push_back(stream);
276
277 EXPECT_TRUE(InitializeCodec());
278 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 3u);
279 EXPECT_EQ(codec_out_.VP9()->numberOfTemporalLayers, 3u);
280}
281
282TEST_F(VideoCodecInitializerTest, Vp9SvcAdjustedLayering) {
283 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
284 VideoStream stream = DefaultStream();
285 stream.num_temporal_layers = 3;
286 // Set resolution which is only enough to produce 2 spatial layers.
287 stream.width = kMinVp9SpatialLayerWidth * 2;
288 stream.height = kMinVp9SpatialLayerHeight * 2;
289
290 streams_.push_back(stream);
291
292 EXPECT_TRUE(InitializeCodec());
293 EXPECT_EQ(codec_out_.VP9()->numberOfSpatialLayers, 2u);
294}
295
Sergey Silkinfafeac32018-04-13 16:36:39 +0200296TEST_F(VideoCodecInitializerTest,
297 Vp9SingleSpatialLayerMaxBitrateIsEqualToCodecMaxBitrate) {
298 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 3, false);
299 VideoStream stream = DefaultStream();
300 stream.num_temporal_layers = 3;
301 streams_.push_back(stream);
302
303 EXPECT_TRUE(InitializeCodec());
304 EXPECT_EQ(codec_out_.spatialLayers[0].maxBitrate,
305 kDefaultMaxBitrateBps / 1000);
306}
307
Sergey Silkin33120922018-11-28 13:32:13 +0100308TEST_F(VideoCodecInitializerTest,
Ilya Nikolaevskiy9ef5e052019-03-05 10:08:35 +0100309 Vp9SingleSpatialLayerTargetBitrateIsEqualToCodecMaxBitrate) {
310 SetUpFor(VideoCodecType::kVideoCodecVP9, 1, 1, true);
311 VideoStream stream = DefaultStream();
312 stream.num_temporal_layers = 1;
313 streams_.push_back(stream);
314
315 EXPECT_TRUE(InitializeCodec());
316 EXPECT_EQ(codec_out_.spatialLayers[0].targetBitrate,
317 kDefaultMaxBitrateBps / 1000);
318}
319
320TEST_F(VideoCodecInitializerTest,
Sergey Silkin33120922018-11-28 13:32:13 +0100321 Vp9KeepBitrateLimitsIfNumberOfSpatialLayersIsReducedToOne) {
322 // Request 3 spatial layers for 320x180 input. Actual number of layers will be
323 // reduced to 1 due to low input resolution but SVC bitrate limits should be
324 // applied.
325 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 3, false);
326 VideoStream stream = DefaultStream();
327 stream.width = 320;
328 stream.height = 180;
329 stream.num_temporal_layers = 3;
330 streams_.push_back(stream);
331
332 EXPECT_TRUE(InitializeCodec());
333 EXPECT_LT(codec_out_.spatialLayers[0].maxBitrate,
334 kDefaultMaxBitrateBps / 1000);
335}
336
Sergey Silkin8b9b5f92018-12-10 09:28:53 +0100337TEST_F(VideoCodecInitializerTest, Vp9DeactivateLayers) {
338 SetUpFor(VideoCodecType::kVideoCodecVP9, 3, 1, false);
339 VideoStream stream = DefaultStream();
340 streams_.push_back(stream);
341
342 config_.simulcast_layers.resize(3);
343
344 // Activate all layers.
345 config_.simulcast_layers[0].active = true;
346 config_.simulcast_layers[1].active = true;
347 config_.simulcast_layers[2].active = true;
348 EXPECT_TRUE(InitializeCodec());
349 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
350 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
351 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
352
353 // Deactivate top layer.
354 config_.simulcast_layers[0].active = false;
355 EXPECT_TRUE(InitializeCodec());
356 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
357 EXPECT_TRUE(codec_out_.spatialLayers[1].active);
358 EXPECT_FALSE(codec_out_.spatialLayers[2].active);
359
360 // Deactivate middle layer.
361 config_.simulcast_layers[0].active = true;
362 config_.simulcast_layers[1].active = false;
363 EXPECT_TRUE(InitializeCodec());
364 EXPECT_TRUE(codec_out_.spatialLayers[0].active);
365 EXPECT_FALSE(codec_out_.spatialLayers[1].active);
366 EXPECT_TRUE(codec_out_.spatialLayers[2].active);
367}
368
sprang429600d2017-01-26 06:12:26 -0800369} // namespace webrtc