blob: a3c6d3c052ecb2262115caec8b12281435391936 [file] [log] [blame]
Sebastian Jansson98b07e912018-09-27 11:47:011/*
2 * Copyright 2018 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#include "test/scenario/video_stream.h"
11
12#include <algorithm>
13#include <utility>
14
Sebastian Jansson9a4f38e2018-12-19 12:14:4115#include "absl/memory/memory.h"
Danil Chapovalov99b71df2018-10-26 13:57:4816#include "api/test/video/function_video_encoder_factory.h"
Jiawei Ouc2ebe212018-11-08 18:02:5617#include "api/video/builtin_video_bitrate_allocator_factory.h"
Steve Anton10542f22019-01-11 17:11:0018#include "media/base/media_constants.h"
19#include "media/engine/internal_decoder_factory.h"
20#include "media/engine/internal_encoder_factory.h"
21#include "media/engine/webrtc_video_engine.h"
Sebastian Jansson98b07e912018-09-27 11:47:0122#include "test/call_test.h"
23#include "test/fake_encoder.h"
Sebastian Jansson98b07e912018-09-27 11:47:0124#include "test/scenario/hardware_codecs.h"
Steve Anton10542f22019-01-11 17:11:0025#include "test/testsupport/file_utils.h"
Sebastian Jansson98b07e912018-09-27 11:47:0126
27namespace webrtc {
28namespace test {
29namespace {
30constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
31const int kVideoRotationRtpExtensionId = 4;
32uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) {
33 switch (codec_type) {
34 case VideoCodecType::kVideoCodecGeneric:
35 return CallTest::kFakeVideoSendPayloadType;
36 case VideoCodecType::kVideoCodecVP8:
37 return CallTest::kPayloadTypeVP8;
38 case VideoCodecType::kVideoCodecVP9:
39 return CallTest::kPayloadTypeVP9;
40 case VideoCodecType::kVideoCodecH264:
41 return CallTest::kPayloadTypeH264;
42 default:
43 RTC_NOTREACHED();
44 }
45 return {};
46}
47std::string CodecTypeToCodecName(VideoCodecType codec_type) {
48 switch (codec_type) {
49 case VideoCodecType::kVideoCodecGeneric:
50 return "";
51 case VideoCodecType::kVideoCodecVP8:
52 return cricket::kVp8CodecName;
53 case VideoCodecType::kVideoCodecVP9:
54 return cricket::kVp9CodecName;
55 case VideoCodecType::kVideoCodecH264:
56 return cricket::kH264CodecName;
57 default:
58 RTC_NOTREACHED();
59 }
60 return {};
61}
62std::vector<RtpExtension> GetVideoRtpExtensions(
63 const VideoStreamConfig config) {
64 return {RtpExtension(RtpExtension::kTransportSequenceNumberUri,
65 kTransportSequenceNumberExtensionId),
66 RtpExtension(RtpExtension::kVideoContentTypeUri,
67 kVideoContentTypeExtensionId),
68 RtpExtension(RtpExtension::kVideoRotationUri,
69 kVideoRotationRtpExtensionId)};
70}
71
72VideoSendStream::Config CreateVideoSendStreamConfig(VideoStreamConfig config,
73 std::vector<uint32_t> ssrcs,
74 Transport* send_transport) {
75 VideoSendStream::Config send_config(send_transport);
76 send_config.rtp.payload_name = CodecTypeToPayloadString(config.encoder.codec);
77 send_config.rtp.payload_type = CodecTypeToPayloadType(config.encoder.codec);
78
79 send_config.rtp.ssrcs = ssrcs;
80 send_config.rtp.extensions = GetVideoRtpExtensions(config);
81
82 if (config.stream.use_flexfec) {
83 send_config.rtp.flexfec.payload_type = CallTest::kFlexfecPayloadType;
84 send_config.rtp.flexfec.ssrc = CallTest::kFlexfecSendSsrc;
85 send_config.rtp.flexfec.protected_media_ssrcs = ssrcs;
86 }
87 if (config.stream.use_ulpfec) {
88 send_config.rtp.ulpfec.red_payload_type = CallTest::kRedPayloadType;
89 send_config.rtp.ulpfec.ulpfec_payload_type = CallTest::kUlpfecPayloadType;
90 send_config.rtp.ulpfec.red_rtx_payload_type = CallTest::kRtxRedPayloadType;
91 }
92 return send_config;
93}
94rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
95CreateEncoderSpecificSettings(VideoStreamConfig config) {
96 using Codec = VideoStreamConfig::Encoder::Codec;
97 switch (config.encoder.codec) {
98 case Codec::kVideoCodecH264: {
99 VideoCodecH264 h264_settings = VideoEncoder::GetDefaultH264Settings();
100 h264_settings.frameDroppingOn = true;
101 h264_settings.keyFrameInterval =
102 config.encoder.key_frame_interval.value_or(0);
103 return new rtc::RefCountedObject<
104 VideoEncoderConfig::H264EncoderSpecificSettings>(h264_settings);
105 }
106 case Codec::kVideoCodecVP8: {
107 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
108 vp8_settings.frameDroppingOn = true;
109 vp8_settings.keyFrameInterval =
110 config.encoder.key_frame_interval.value_or(0);
111 vp8_settings.automaticResizeOn = true;
112 vp8_settings.denoisingOn = config.encoder.denoising;
113 return new rtc::RefCountedObject<
114 VideoEncoderConfig::Vp8EncoderSpecificSettings>(vp8_settings);
115 }
116 case Codec::kVideoCodecVP9: {
117 VideoCodecVP9 vp9_settings = VideoEncoder::GetDefaultVp9Settings();
118 vp9_settings.frameDroppingOn = true;
119 vp9_settings.keyFrameInterval =
120 config.encoder.key_frame_interval.value_or(0);
121 vp9_settings.automaticResizeOn = true;
122 vp9_settings.denoisingOn = config.encoder.denoising;
123 vp9_settings.interLayerPred = InterLayerPredMode::kOnKeyPic;
124 return new rtc::RefCountedObject<
125 VideoEncoderConfig::Vp9EncoderSpecificSettings>(vp9_settings);
126 }
127 default:
128 return nullptr;
129 }
130}
131
132VideoEncoderConfig CreateVideoEncoderConfig(VideoStreamConfig config) {
133 size_t num_streams = config.encoder.num_simulcast_streams;
134 VideoEncoderConfig encoder_config;
135 encoder_config.codec_type = config.encoder.codec;
Sebastian Jansson985ee682018-11-12 15:33:29136 switch (config.source.content_type) {
137 case VideoStreamConfig::Source::ContentType::kVideo:
138 encoder_config.content_type =
139 VideoEncoderConfig::ContentType::kRealtimeVideo;
140 break;
141 case VideoStreamConfig::Source::ContentType::kScreen:
142 encoder_config.content_type = VideoEncoderConfig::ContentType::kScreen;
143 break;
144 }
Sebastian Jansson98b07e912018-09-27 11:47:01145 encoder_config.video_format =
146 SdpVideoFormat(CodecTypeToPayloadString(config.encoder.codec), {});
147 encoder_config.number_of_streams = num_streams;
148 encoder_config.simulcast_layers = std::vector<VideoStream>(num_streams);
Sebastian Jansson985ee682018-11-12 15:33:29149 encoder_config.min_transmit_bitrate_bps = config.stream.pad_to_rate.bps();
Sebastian Jansson98b07e912018-09-27 11:47:01150
151 std::string cricket_codec = CodecTypeToCodecName(config.encoder.codec);
152 if (!cricket_codec.empty()) {
153 encoder_config.video_stream_factory =
154 new rtc::RefCountedObject<cricket::EncoderStreamFactory>(
155 cricket_codec, kDefaultMaxQp, false, false);
156 } else {
157 encoder_config.video_stream_factory =
158 new rtc::RefCountedObject<DefaultVideoStreamFactory>();
159 }
160 if (config.encoder.max_data_rate) {
161 encoder_config.max_bitrate_bps = config.encoder.max_data_rate->bps();
162 } else {
163 encoder_config.max_bitrate_bps = 10000000; // 10 mbit
164 }
165 encoder_config.encoder_specific_settings =
166 CreateEncoderSpecificSettings(config);
Sebastian Jansson0c32e332018-11-12 15:47:43167 if (config.encoder.max_framerate) {
168 for (auto& layer : encoder_config.simulcast_layers) {
169 layer.max_framerate = *config.encoder.max_framerate;
170 }
171 }
172
Sebastian Jansson98b07e912018-09-27 11:47:01173 return encoder_config;
174}
175} // namespace
176
177SendVideoStream::SendVideoStream(CallClient* sender,
178 VideoStreamConfig config,
Sebastian Jansson9a4f38e2018-12-19 12:14:41179 Transport* send_transport,
180 VideoQualityAnalyzer* analyzer)
Sebastian Jansson98b07e912018-09-27 11:47:01181 : sender_(sender), config_(config) {
182 for (size_t i = 0; i < config.encoder.num_simulcast_streams; ++i) {
183 ssrcs_.push_back(sender->GetNextVideoSsrc());
184 rtx_ssrcs_.push_back(sender->GetNextRtxSsrc());
185 }
186
187 using Capture = VideoStreamConfig::Source::Capture;
188 switch (config.source.capture) {
189 case Capture::kGenerator:
190 frame_generator_ = test::FrameGeneratorCapturer::Create(
191 config.source.width, config.source.height,
192 config.source.generator.pixel_format, absl::nullopt,
193 config.source.framerate, sender_->clock_);
194 video_capturer_.reset(frame_generator_);
195 break;
196 case Capture::kVideoFile:
197 frame_generator_ = test::FrameGeneratorCapturer::CreateFromYuvFile(
198 test::ResourcePath(config.source.video_file.name, "yuv"),
199 config.source.width, config.source.height, config.source.framerate,
200 sender_->clock_);
201 RTC_CHECK(frame_generator_)
202 << "Could not create capturer for " << config.source.video_file.name
203 << ".yuv. Is this resource file present?";
204 video_capturer_.reset(frame_generator_);
205 break;
206 }
207
208 using Encoder = VideoStreamConfig::Encoder;
209 using Codec = VideoStreamConfig::Encoder::Codec;
210 switch (config.encoder.implementation) {
211 case Encoder::Implementation::kFake:
212 if (config.encoder.codec == Codec::kVideoCodecGeneric) {
213 encoder_factory_ =
Sebastian Jansson0c32e332018-11-12 15:47:43214 absl::make_unique<FunctionVideoEncoderFactory>([this]() {
215 rtc::CritScope cs(&crit_);
Sebastian Jansson98b07e912018-09-27 11:47:01216 auto encoder =
217 absl::make_unique<test::FakeEncoder>(sender_->clock_);
Sebastian Jansson0c32e332018-11-12 15:47:43218 fake_encoders_.push_back(encoder.get());
219 if (config_.encoder.fake.max_rate.IsFinite())
220 encoder->SetMaxBitrate(config_.encoder.fake.max_rate.kbps());
Sebastian Jansson98b07e912018-09-27 11:47:01221 return encoder;
222 });
223 } else {
224 RTC_NOTREACHED();
225 }
226 break;
227 case VideoStreamConfig::Encoder::Implementation::kSoftware:
228 encoder_factory_.reset(new InternalEncoderFactory());
229 break;
230 case VideoStreamConfig::Encoder::Implementation::kHardware:
231 encoder_factory_ = CreateHardwareEncoderFactory();
232 break;
233 }
234 RTC_CHECK(encoder_factory_);
235
Jiawei Ouc2ebe212018-11-08 18:02:56236 bitrate_allocator_factory_ = CreateBuiltinVideoBitrateAllocatorFactory();
237 RTC_CHECK(bitrate_allocator_factory_);
238
Sebastian Jansson98b07e912018-09-27 11:47:01239 VideoSendStream::Config send_config =
240 CreateVideoSendStreamConfig(config, ssrcs_, send_transport);
241 send_config.encoder_settings.encoder_factory = encoder_factory_.get();
Jiawei Ouc2ebe212018-11-08 18:02:56242 send_config.encoder_settings.bitrate_allocator_factory =
243 bitrate_allocator_factory_.get();
244
Sebastian Jansson98b07e912018-09-27 11:47:01245 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config);
246
247 send_stream_ = sender_->call_->CreateVideoSendStream(
248 std::move(send_config), std::move(encoder_config));
Sebastian Jansson9a4f38e2018-12-19 12:14:41249 std::vector<std::function<void(const VideoFrameQualityInfo&)> >
250 frame_info_handlers;
251 if (config.analyzer.frame_quality_handler)
252 frame_info_handlers.push_back(config.analyzer.frame_quality_handler);
Sebastian Jansson98b07e912018-09-27 11:47:01253
Sebastian Jansson9a4f38e2018-12-19 12:14:41254 if (analyzer->Active()) {
255 frame_tap_.reset(new ForwardingCapturedFrameTap(sender_->clock_, analyzer,
256 video_capturer_.get()));
257 send_stream_->SetSource(frame_tap_.get(),
258 config.encoder.degradation_preference);
259 } else {
260 send_stream_->SetSource(video_capturer_.get(),
261 config.encoder.degradation_preference);
262 }
Sebastian Jansson98b07e912018-09-27 11:47:01263}
264
265SendVideoStream::~SendVideoStream() {
266 sender_->call_->DestroyVideoSendStream(send_stream_);
267}
268
269void SendVideoStream::Start() {
270 send_stream_->Start();
Sebastian Jansson49a78432018-11-20 15:15:29271 sender_->call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
Sebastian Jansson98b07e912018-09-27 11:47:01272}
273
Christoffer Rodbro5f6abcf2019-02-08 10:00:10274void SendVideoStream::Stop() {
275 send_stream_->Stop();
276}
277
Sebastian Jansson0c32e332018-11-12 15:47:43278void SendVideoStream::UpdateConfig(
279 std::function<void(VideoStreamConfig*)> modifier) {
280 rtc::CritScope cs(&crit_);
281 VideoStreamConfig prior_config = config_;
282 modifier(&config_);
283 if (prior_config.encoder.fake.max_rate != config_.encoder.fake.max_rate) {
284 for (auto* encoder : fake_encoders_) {
285 encoder->SetMaxBitrate(config_.encoder.fake.max_rate.kbps());
286 }
287 }
288 // TODO(srte): Add more conditions that should cause reconfiguration.
289 if (prior_config.encoder.max_framerate != config_.encoder.max_framerate) {
290 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config_);
291 send_stream_->ReconfigureVideoEncoder(std::move(encoder_config));
292 }
293 if (prior_config.source.framerate != config_.source.framerate) {
294 SetCaptureFramerate(config_.source.framerate);
295 }
296}
297
Sebastian Jansson98b07e912018-09-27 11:47:01298void SendVideoStream::SetCaptureFramerate(int framerate) {
299 RTC_CHECK(frame_generator_)
300 << "Framerate change only implemented for generators";
301 frame_generator_->ChangeFramerate(framerate);
Sebastian Jansson98b07e912018-09-27 11:47:01302}
303
304VideoSendStream::Stats SendVideoStream::GetStats() const {
305 return send_stream_->GetStats();
306}
307
308ColumnPrinter SendVideoStream::StatsPrinter() {
309 return ColumnPrinter::Lambda(
310 "video_target_rate video_sent_rate width height",
311 [this](rtc::SimpleStringBuilder& sb) {
312 VideoSendStream::Stats video_stats = send_stream_->GetStats();
313 int width = 0;
314 int height = 0;
Mirko Bonadei739baf02019-01-27 16:29:42315 for (const auto& stream_stat : video_stats.substreams) {
Sebastian Jansson98b07e912018-09-27 11:47:01316 width = std::max(width, stream_stat.second.width);
317 height = std::max(height, stream_stat.second.height);
318 }
319 sb.AppendFormat("%.0lf %.0lf %i %i",
320 video_stats.target_media_bitrate_bps / 8.0,
321 video_stats.media_bitrate_bps / 8.0, width, height);
322 },
323 64);
324}
325
326ReceiveVideoStream::ReceiveVideoStream(CallClient* receiver,
327 VideoStreamConfig config,
328 SendVideoStream* send_stream,
329 size_t chosen_stream,
Sebastian Jansson9a4f38e2018-12-19 12:14:41330 Transport* feedback_transport,
331 VideoQualityAnalyzer* analyzer)
Sebastian Jansson0c32e332018-11-12 15:47:43332 : receiver_(receiver), config_(config) {
Sebastian Jansson9a4f38e2018-12-19 12:14:41333 if (analyzer->Active()) {
334 renderer_ = absl::make_unique<DecodedFrameTap>(analyzer);
335 } else {
336 renderer_ = absl::make_unique<FakeVideoRenderer>();
337 }
Sebastian Jansson98b07e912018-09-27 11:47:01338 VideoReceiveStream::Config recv_config(feedback_transport);
339 recv_config.rtp.remb = !config.stream.packet_feedback;
340 recv_config.rtp.transport_cc = config.stream.packet_feedback;
341 recv_config.rtp.local_ssrc = CallTest::kReceiverLocalVideoSsrc;
342 recv_config.rtp.extensions = GetVideoRtpExtensions(config);
Sebastian Janssonfd201712018-11-12 15:44:16343 receiver_->AddExtensions(recv_config.rtp.extensions);
Sebastian Jansson98b07e912018-09-27 11:47:01344 RTC_DCHECK(!config.stream.use_rtx ||
345 config.stream.nack_history_time > TimeDelta::Zero());
346 recv_config.rtp.nack.rtp_history_ms = config.stream.nack_history_time.ms();
347 recv_config.rtp.protected_by_flexfec = config.stream.use_flexfec;
348 recv_config.renderer = renderer_.get();
349 if (config.stream.use_rtx) {
350 recv_config.rtp.rtx_ssrc = send_stream->rtx_ssrcs_[chosen_stream];
Sebastian Jansson800e1212018-10-22 09:49:03351 receiver->ssrc_media_types_[recv_config.rtp.rtx_ssrc] = MediaType::VIDEO;
Sebastian Jansson98b07e912018-09-27 11:47:01352 recv_config.rtp
353 .rtx_associated_payload_types[CallTest::kSendRtxPayloadType] =
354 CodecTypeToPayloadType(config.encoder.codec);
355 }
356 recv_config.rtp.remote_ssrc = send_stream->ssrcs_[chosen_stream];
Sebastian Jansson800e1212018-10-22 09:49:03357 receiver->ssrc_media_types_[recv_config.rtp.remote_ssrc] = MediaType::VIDEO;
358
Sebastian Jansson98b07e912018-09-27 11:47:01359 VideoReceiveStream::Decoder decoder =
360 CreateMatchingDecoder(CodecTypeToPayloadType(config.encoder.codec),
361 CodecTypeToPayloadString(config.encoder.codec));
Sebastian Jansson0c32e332018-11-12 15:47:43362 if (config.encoder.codec ==
363 VideoStreamConfig::Encoder::Codec::kVideoCodecGeneric) {
364 decoder_factory_ = absl::make_unique<FunctionVideoDecoderFactory>(
365 []() { return absl::make_unique<FakeDecoder>(); });
366 } else {
367 decoder_factory_ = absl::make_unique<InternalDecoderFactory>();
368 }
Niels Möllercbcbc222018-09-28 07:07:24369 decoder.decoder_factory = decoder_factory_.get();
Sebastian Jansson98b07e912018-09-27 11:47:01370 recv_config.decoders.push_back(decoder);
371
372 if (config.stream.use_flexfec) {
373 RTC_CHECK_EQ(config.encoder.num_simulcast_streams, 1);
374 FlexfecReceiveStream::Config flexfec_config(feedback_transport);
375 flexfec_config.payload_type = CallTest::kFlexfecPayloadType;
376 flexfec_config.remote_ssrc = CallTest::kFlexfecSendSsrc;
Sebastian Jansson800e1212018-10-22 09:49:03377 receiver->ssrc_media_types_[flexfec_config.remote_ssrc] = MediaType::VIDEO;
Sebastian Jansson98b07e912018-09-27 11:47:01378 flexfec_config.protected_media_ssrcs = send_stream->rtx_ssrcs_;
379 flexfec_config.local_ssrc = recv_config.rtp.local_ssrc;
380 flecfec_stream_ =
381 receiver_->call_->CreateFlexfecReceiveStream(flexfec_config);
382 }
383 if (config.stream.use_ulpfec) {
384 recv_config.rtp.red_payload_type = CallTest::kRedPayloadType;
385 recv_config.rtp.ulpfec_payload_type = CallTest::kUlpfecPayloadType;
386 recv_config.rtp.rtx_associated_payload_types[CallTest::kRtxRedPayloadType] =
387 CallTest::kRedPayloadType;
388 }
389 receive_stream_ =
390 receiver_->call_->CreateVideoReceiveStream(std::move(recv_config));
391}
392
393ReceiveVideoStream::~ReceiveVideoStream() {
394 receiver_->call_->DestroyVideoReceiveStream(receive_stream_);
395 if (flecfec_stream_)
396 receiver_->call_->DestroyFlexfecReceiveStream(flecfec_stream_);
397}
398
Sebastian Jansson49a78432018-11-20 15:15:29399void ReceiveVideoStream::Start() {
400 receive_stream_->Start();
401 receiver_->call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
402}
403
Sebastian Jansson98b07e912018-09-27 11:47:01404VideoStreamPair::~VideoStreamPair() = default;
405
Sebastian Jansson52de8b02019-01-16 16:25:44406VideoStreamPair::VideoStreamPair(
407 CallClient* sender,
408 CallClient* receiver,
409 VideoStreamConfig config,
410 std::unique_ptr<RtcEventLogOutput> quality_writer)
Sebastian Jansson98b07e912018-09-27 11:47:01411 : config_(config),
Sebastian Jansson52de8b02019-01-16 16:25:44412 analyzer_(std::move(quality_writer),
413 config.analyzer.frame_quality_handler),
Sebastian Jansson9a4f38e2018-12-19 12:14:41414 send_stream_(sender, config, &sender->transport_, &analyzer_),
Sebastian Jansson98b07e912018-09-27 11:47:01415 receive_stream_(receiver,
416 config,
417 &send_stream_,
418 /*chosen_stream=*/0,
Sebastian Jansson9a4f38e2018-12-19 12:14:41419 &receiver->transport_,
420 &analyzer_) {}
Sebastian Jansson98b07e912018-09-27 11:47:01421
422} // namespace test
423} // namespace webrtc