1 /*
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 <memory>
14 #include <utility>
15
16 #include "absl/strings/match.h"
17 #include "api/test/create_frame_generator.h"
18 #include "api/test/frame_generator_interface.h"
19 #include "api/test/video/function_video_encoder_factory.h"
20 #include "api/video/builtin_video_bitrate_allocator_factory.h"
21 #include "media/base/media_constants.h"
22 #include "media/engine/internal_decoder_factory.h"
23 #include "media/engine/internal_encoder_factory.h"
24 #include "media/engine/webrtc_video_engine.h"
25 #include "modules/video_coding/svc/scalability_mode_util.h"
26 #include "test/call_test.h"
27 #include "test/fake_encoder.h"
28 #include "test/scenario/hardware_codecs.h"
29 #include "test/testsupport/file_utils.h"
30 #include "video/config/encoder_stream_factory.h"
31
32 namespace webrtc {
33 namespace test {
34 namespace {
35 enum : int { // The first valid value is 1.
36 kTransportSequenceNumberExtensionId = 1,
37 kAbsSendTimeExtensionId,
38 kVideoContentTypeExtensionId,
39 kVideoRotationRtpExtensionId,
40 };
41
42 constexpr int kDefaultMaxQp = cricket::WebRtcVideoChannel::kDefaultQpMax;
CodecTypeToPayloadType(VideoCodecType codec_type)43 uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) {
44 switch (codec_type) {
45 case VideoCodecType::kVideoCodecGeneric:
46 return CallTest::kFakeVideoSendPayloadType;
47 case VideoCodecType::kVideoCodecVP8:
48 return CallTest::kPayloadTypeVP8;
49 case VideoCodecType::kVideoCodecVP9:
50 return CallTest::kPayloadTypeVP9;
51 case VideoCodecType::kVideoCodecH264:
52 return CallTest::kPayloadTypeH264;
53 default:
54 RTC_DCHECK_NOTREACHED();
55 }
56 return {};
57 }
CodecTypeToCodecName(VideoCodecType codec_type)58 std::string CodecTypeToCodecName(VideoCodecType codec_type) {
59 switch (codec_type) {
60 case VideoCodecType::kVideoCodecGeneric:
61 return "";
62 case VideoCodecType::kVideoCodecVP8:
63 return cricket::kVp8CodecName;
64 case VideoCodecType::kVideoCodecVP9:
65 return cricket::kVp9CodecName;
66 case VideoCodecType::kVideoCodecH264:
67 return cricket::kH264CodecName;
68 default:
69 RTC_DCHECK_NOTREACHED();
70 }
71 return {};
72 }
ConvertContentType(VideoStreamConfig::Encoder::ContentType content_type)73 VideoEncoderConfig::ContentType ConvertContentType(
74 VideoStreamConfig::Encoder::ContentType content_type) {
75 switch (content_type) {
76 case VideoStreamConfig::Encoder::ContentType::kVideo:
77 return VideoEncoderConfig::ContentType::kRealtimeVideo;
78 case VideoStreamConfig::Encoder::ContentType::kScreen:
79 return VideoEncoderConfig::ContentType::kScreen;
80 }
81 }
82
GetVideoRtpExtensions(const VideoStreamConfig config)83 std::vector<RtpExtension> GetVideoRtpExtensions(
84 const VideoStreamConfig config) {
85 std::vector<RtpExtension> res = {
86 RtpExtension(RtpExtension::kVideoContentTypeUri,
87 kVideoContentTypeExtensionId),
88 RtpExtension(RtpExtension::kVideoRotationUri,
89 kVideoRotationRtpExtensionId)};
90 if (config.stream.packet_feedback) {
91 res.push_back(RtpExtension(RtpExtension::kTransportSequenceNumberUri,
92 kTransportSequenceNumberExtensionId));
93 }
94 if (config.stream.abs_send_time) {
95 res.push_back(
96 RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId));
97 }
98 return res;
99 }
100
TransformFilePath(std::string path)101 std::string TransformFilePath(std::string path) {
102 static const std::string resource_prefix = "res://";
103 int ext_pos = path.rfind('.');
104 if (ext_pos < 0) {
105 return test::ResourcePath(path, "yuv");
106 } else if (absl::StartsWith(path, resource_prefix)) {
107 std::string name = path.substr(resource_prefix.length(), ext_pos);
108 std::string ext = path.substr(ext_pos, path.size());
109 return test::ResourcePath(name, ext);
110 }
111 return path;
112 }
113
CreateVideoSendStreamConfig(VideoStreamConfig config,std::vector<uint32_t> ssrcs,std::vector<uint32_t> rtx_ssrcs,Transport * send_transport)114 VideoSendStream::Config CreateVideoSendStreamConfig(
115 VideoStreamConfig config,
116 std::vector<uint32_t> ssrcs,
117 std::vector<uint32_t> rtx_ssrcs,
118 Transport* send_transport) {
119 VideoSendStream::Config send_config(send_transport);
120 send_config.rtp.payload_name = CodecTypeToPayloadString(config.encoder.codec);
121 send_config.rtp.payload_type = CodecTypeToPayloadType(config.encoder.codec);
122 send_config.rtp.nack.rtp_history_ms =
123 config.stream.nack_history_time.ms<int>();
124
125 send_config.rtp.ssrcs = ssrcs;
126 send_config.rtp.extensions = GetVideoRtpExtensions(config);
127
128 if (config.stream.use_rtx) {
129 send_config.rtp.rtx.payload_type = CallTest::kSendRtxPayloadType;
130 send_config.rtp.rtx.ssrcs = rtx_ssrcs;
131 }
132 if (config.stream.use_flexfec) {
133 send_config.rtp.flexfec.payload_type = CallTest::kFlexfecPayloadType;
134 send_config.rtp.flexfec.ssrc = CallTest::kFlexfecSendSsrc;
135 send_config.rtp.flexfec.protected_media_ssrcs = ssrcs;
136 }
137 if (config.stream.use_ulpfec) {
138 send_config.rtp.ulpfec.red_payload_type = CallTest::kRedPayloadType;
139 send_config.rtp.ulpfec.ulpfec_payload_type = CallTest::kUlpfecPayloadType;
140 send_config.rtp.ulpfec.red_rtx_payload_type = CallTest::kRtxRedPayloadType;
141 }
142 return send_config;
143 }
144 rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
CreateVp9SpecificSettings(VideoStreamConfig video_config)145 CreateVp9SpecificSettings(VideoStreamConfig video_config) {
146 constexpr auto kScreen = VideoStreamConfig::Encoder::ContentType::kScreen;
147 VideoStreamConfig::Encoder conf = video_config.encoder;
148 VideoCodecVP9 vp9 = VideoEncoder::GetDefaultVp9Settings();
149 // TODO(bugs.webrtc.org/11607): Support separate scalability mode per
150 // simulcast stream.
151 ScalabilityMode scalability_mode = conf.simulcast_streams[0];
152 vp9.keyFrameInterval = conf.key_frame_interval.value_or(0);
153 vp9.numberOfTemporalLayers =
154 ScalabilityModeToNumTemporalLayers(scalability_mode);
155 vp9.numberOfSpatialLayers =
156 ScalabilityModeToNumSpatialLayers(scalability_mode);
157 vp9.interLayerPred = ScalabilityModeToInterLayerPredMode(scalability_mode);
158
159 if (conf.content_type == kScreen &&
160 (video_config.source.framerate > 5 || vp9.numberOfSpatialLayers >= 3)) {
161 vp9.flexibleMode = true;
162 }
163
164 if (conf.content_type == kScreen || vp9.numberOfTemporalLayers > 1 ||
165 vp9.numberOfSpatialLayers > 1) {
166 vp9.automaticResizeOn = false;
167 vp9.denoisingOn = false;
168 } else {
169 vp9.automaticResizeOn = conf.single.automatic_scaling;
170 vp9.denoisingOn = conf.single.denoising;
171 }
172 return rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>(
173 vp9);
174 }
175
176 rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
CreateVp8SpecificSettings(VideoStreamConfig config)177 CreateVp8SpecificSettings(VideoStreamConfig config) {
178 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
179 vp8_settings.keyFrameInterval = config.encoder.key_frame_interval.value_or(0);
180 // TODO(bugs.webrtc.org/11607): Support separate scalability mode per
181 // simulcast stream.
182 ScalabilityMode scalability_mode = config.encoder.simulcast_streams[0];
183 vp8_settings.numberOfTemporalLayers =
184 ScalabilityModeToNumTemporalLayers(scalability_mode);
185 if (vp8_settings.numberOfTemporalLayers > 1 ||
186 config.encoder.simulcast_streams.size() > 1) {
187 vp8_settings.automaticResizeOn = false;
188 vp8_settings.denoisingOn = false;
189 } else {
190 vp8_settings.automaticResizeOn = config.encoder.single.automatic_scaling;
191 vp8_settings.denoisingOn = config.encoder.single.denoising;
192 }
193 return rtc::make_ref_counted<VideoEncoderConfig::Vp8EncoderSpecificSettings>(
194 vp8_settings);
195 }
196
197 rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
CreateH264SpecificSettings(VideoStreamConfig config)198 CreateH264SpecificSettings(VideoStreamConfig config) {
199 RTC_DCHECK_EQ(config.encoder.simulcast_streams.size(), 1);
200 RTC_DCHECK(config.encoder.simulcast_streams[0] == ScalabilityMode::kL1T1);
201 // TODO(bugs.webrtc.org/6883): Set a key frame interval as a setting that
202 // isn't codec specific.
203 RTC_CHECK_EQ(0, config.encoder.key_frame_interval.value_or(0));
204 return nullptr;
205 }
206
207 rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
CreateEncoderSpecificSettings(VideoStreamConfig config)208 CreateEncoderSpecificSettings(VideoStreamConfig config) {
209 using Codec = VideoStreamConfig::Encoder::Codec;
210 switch (config.encoder.codec) {
211 case Codec::kVideoCodecH264:
212 return CreateH264SpecificSettings(config);
213 case Codec::kVideoCodecVP8:
214 return CreateVp8SpecificSettings(config);
215 case Codec::kVideoCodecVP9:
216 return CreateVp9SpecificSettings(config);
217 case Codec::kVideoCodecGeneric:
218 case Codec::kVideoCodecAV1:
219 return nullptr;
220 case Codec::kVideoCodecMultiplex:
221 RTC_DCHECK_NOTREACHED();
222 return nullptr;
223 }
224 }
225
CreateVideoEncoderConfig(VideoStreamConfig config)226 VideoEncoderConfig CreateVideoEncoderConfig(VideoStreamConfig config) {
227 webrtc::VideoEncoder::EncoderInfo encoder_info;
228 VideoEncoderConfig encoder_config;
229 encoder_config.codec_type = config.encoder.codec;
230 encoder_config.content_type = ConvertContentType(config.encoder.content_type);
231 encoder_config.video_format =
232 SdpVideoFormat(CodecTypeToPayloadString(config.encoder.codec), {});
233
234 encoder_config.number_of_streams = config.encoder.simulcast_streams.size();
235 encoder_config.simulcast_layers =
236 std::vector<VideoStream>(encoder_config.number_of_streams);
237 encoder_config.min_transmit_bitrate_bps = config.stream.pad_to_rate.bps();
238
239 std::string cricket_codec = CodecTypeToCodecName(config.encoder.codec);
240 if (!cricket_codec.empty()) {
241 bool screenshare = config.encoder.content_type ==
242 VideoStreamConfig::Encoder::ContentType::kScreen;
243 encoder_config.video_stream_factory =
244 rtc::make_ref_counted<cricket::EncoderStreamFactory>(
245 cricket_codec, kDefaultMaxQp, screenshare, screenshare,
246 encoder_info);
247 } else {
248 encoder_config.video_stream_factory =
249 rtc::make_ref_counted<DefaultVideoStreamFactory>();
250 }
251
252 // TODO(srte): Base this on encoder capabilities.
253 encoder_config.max_bitrate_bps =
254 config.encoder.max_data_rate.value_or(DataRate::KilobitsPerSec(10000))
255 .bps();
256
257 encoder_config.frame_drop_enabled = config.encoder.frame_dropping;
258 encoder_config.encoder_specific_settings =
259 CreateEncoderSpecificSettings(config);
260
261 for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
262 auto& layer = encoder_config.simulcast_layers[i];
263 if (config.encoder.max_framerate) {
264 layer.max_framerate = *config.encoder.max_framerate;
265 layer.min_bitrate_bps = config.encoder.min_data_rate->bps_or(-1);
266 }
267 layer.scalability_mode = config.encoder.simulcast_streams[i];
268 }
269
270 return encoder_config;
271 }
272
CreateImageSlideGenerator(Clock * clock,VideoStreamConfig::Source::Slides slides,int framerate)273 std::unique_ptr<FrameGeneratorInterface> CreateImageSlideGenerator(
274 Clock* clock,
275 VideoStreamConfig::Source::Slides slides,
276 int framerate) {
277 std::vector<std::string> paths = slides.images.paths;
278 for (std::string& path : paths)
279 path = TransformFilePath(path);
280 if (slides.images.crop.width || slides.images.crop.height) {
281 TimeDelta pause_duration =
282 slides.change_interval - slides.images.crop.scroll_duration;
283 RTC_CHECK_GE(pause_duration, TimeDelta::Zero());
284 int crop_width = slides.images.crop.width.value_or(slides.images.width);
285 int crop_height = slides.images.crop.height.value_or(slides.images.height);
286 RTC_CHECK_LE(crop_width, slides.images.width);
287 RTC_CHECK_LE(crop_height, slides.images.height);
288 return CreateScrollingInputFromYuvFilesFrameGenerator(
289 clock, paths, slides.images.width, slides.images.height, crop_width,
290 crop_height, slides.images.crop.scroll_duration.ms(),
291 pause_duration.ms());
292 } else {
293 return CreateFromYuvFileFrameGenerator(
294 paths, slides.images.width, slides.images.height,
295 slides.change_interval.seconds<double>() * framerate);
296 }
297 }
298
CreateFrameGenerator(Clock * clock,VideoStreamConfig::Source source)299 std::unique_ptr<FrameGeneratorInterface> CreateFrameGenerator(
300 Clock* clock,
301 VideoStreamConfig::Source source) {
302 using Capture = VideoStreamConfig::Source::Capture;
303 switch (source.capture) {
304 case Capture::kGenerator:
305 return CreateSquareFrameGenerator(
306 source.generator.width, source.generator.height,
307 source.generator.pixel_format, /*num_squares*/ absl::nullopt);
308 case Capture::kVideoFile:
309 RTC_CHECK(source.video_file.width && source.video_file.height);
310 return CreateFromYuvFileFrameGenerator(
311 {TransformFilePath(source.video_file.name)}, source.video_file.width,
312 source.video_file.height, /*frame_repeat_count*/ 1);
313 case Capture::kGenerateSlides:
314 return CreateSlideFrameGenerator(
315 source.slides.generator.width, source.slides.generator.height,
316 source.slides.change_interval.seconds<double>() * source.framerate);
317 case Capture::kImageSlides:
318 return CreateImageSlideGenerator(clock, source.slides, source.framerate);
319 }
320 }
321
CreateVideoReceiveStreamConfig(VideoStreamConfig config,Transport * feedback_transport,VideoDecoderFactory * decoder_factory,VideoReceiveStreamInterface::Decoder decoder,rtc::VideoSinkInterface<VideoFrame> * renderer,uint32_t local_ssrc,uint32_t ssrc,uint32_t rtx_ssrc)322 VideoReceiveStreamInterface::Config CreateVideoReceiveStreamConfig(
323 VideoStreamConfig config,
324 Transport* feedback_transport,
325 VideoDecoderFactory* decoder_factory,
326 VideoReceiveStreamInterface::Decoder decoder,
327 rtc::VideoSinkInterface<VideoFrame>* renderer,
328 uint32_t local_ssrc,
329 uint32_t ssrc,
330 uint32_t rtx_ssrc) {
331 VideoReceiveStreamInterface::Config recv(feedback_transport);
332 recv.rtp.transport_cc = config.stream.packet_feedback;
333 recv.rtp.local_ssrc = local_ssrc;
334 recv.rtp.extensions = GetVideoRtpExtensions(config);
335
336 RTC_DCHECK(!config.stream.use_rtx ||
337 config.stream.nack_history_time > TimeDelta::Zero());
338 recv.rtp.nack.rtp_history_ms = config.stream.nack_history_time.ms();
339 recv.rtp.protected_by_flexfec = config.stream.use_flexfec;
340 recv.rtp.remote_ssrc = ssrc;
341 recv.decoder_factory = decoder_factory;
342 recv.decoders.push_back(decoder);
343 recv.renderer = renderer;
344 if (config.stream.use_rtx) {
345 recv.rtp.rtx_ssrc = rtx_ssrc;
346 recv.rtp.rtx_associated_payload_types[CallTest::kSendRtxPayloadType] =
347 CodecTypeToPayloadType(config.encoder.codec);
348 }
349 if (config.stream.use_ulpfec) {
350 recv.rtp.red_payload_type = CallTest::kRedPayloadType;
351 recv.rtp.ulpfec_payload_type = CallTest::kUlpfecPayloadType;
352 recv.rtp.rtx_associated_payload_types[CallTest::kRtxRedPayloadType] =
353 CallTest::kRedPayloadType;
354 }
355 recv.sync_group = config.render.sync_group;
356 return recv;
357 }
358 } // namespace
359
SendVideoStream(CallClient * sender,VideoStreamConfig config,Transport * send_transport,VideoFrameMatcher * matcher)360 SendVideoStream::SendVideoStream(CallClient* sender,
361 VideoStreamConfig config,
362 Transport* send_transport,
363 VideoFrameMatcher* matcher)
364 : sender_(sender), config_(config) {
365 video_capturer_ = std::make_unique<FrameGeneratorCapturer>(
366 sender_->clock_, CreateFrameGenerator(sender_->clock_, config.source),
367 config.source.framerate,
368 *sender->time_controller_->GetTaskQueueFactory());
369 video_capturer_->Init();
370
371 using Encoder = VideoStreamConfig::Encoder;
372 using Codec = VideoStreamConfig::Encoder::Codec;
373 switch (config.encoder.implementation) {
374 case Encoder::Implementation::kFake:
375 encoder_factory_ =
376 std::make_unique<FunctionVideoEncoderFactory>([this]() {
377 MutexLock lock(&mutex_);
378 std::unique_ptr<FakeEncoder> encoder;
379 if (config_.encoder.codec == Codec::kVideoCodecVP8) {
380 encoder = std::make_unique<test::FakeVp8Encoder>(sender_->clock_);
381 } else if (config_.encoder.codec == Codec::kVideoCodecGeneric) {
382 encoder = std::make_unique<test::FakeEncoder>(sender_->clock_);
383 } else {
384 RTC_DCHECK_NOTREACHED();
385 }
386 fake_encoders_.push_back(encoder.get());
387 if (config_.encoder.fake.max_rate.IsFinite())
388 encoder->SetMaxBitrate(config_.encoder.fake.max_rate.kbps());
389 return encoder;
390 });
391 break;
392 case VideoStreamConfig::Encoder::Implementation::kSoftware:
393 encoder_factory_.reset(new InternalEncoderFactory());
394 break;
395 case VideoStreamConfig::Encoder::Implementation::kHardware:
396 encoder_factory_ = CreateHardwareEncoderFactory();
397 break;
398 }
399 RTC_CHECK(encoder_factory_);
400
401 bitrate_allocator_factory_ = CreateBuiltinVideoBitrateAllocatorFactory();
402 RTC_CHECK(bitrate_allocator_factory_);
403
404 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config);
405 for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
406 ssrcs_.push_back(sender->GetNextVideoSsrc());
407 rtx_ssrcs_.push_back(sender->GetNextRtxSsrc());
408 }
409 VideoSendStream::Config send_config =
410 CreateVideoSendStreamConfig(config, ssrcs_, rtx_ssrcs_, send_transport);
411 send_config.encoder_settings.encoder_factory = encoder_factory_.get();
412 send_config.encoder_settings.bitrate_allocator_factory =
413 bitrate_allocator_factory_.get();
414 send_config.suspend_below_min_bitrate =
415 config.encoder.suspend_below_min_bitrate;
416
417 sender_->SendTask([&] {
418 if (config.stream.fec_controller_factory) {
419 send_stream_ = sender_->call_->CreateVideoSendStream(
420 std::move(send_config), std::move(encoder_config),
421 config.stream.fec_controller_factory->CreateFecController());
422 } else {
423 send_stream_ = sender_->call_->CreateVideoSendStream(
424 std::move(send_config), std::move(encoder_config));
425 }
426
427 if (matcher->Active()) {
428 frame_tap_ = std::make_unique<ForwardingCapturedFrameTap>(
429 sender_->clock_, matcher, video_capturer_.get());
430 send_stream_->SetSource(frame_tap_.get(),
431 config.encoder.degradation_preference);
432 } else {
433 send_stream_->SetSource(video_capturer_.get(),
434 config.encoder.degradation_preference);
435 }
436 });
437 }
438
~SendVideoStream()439 SendVideoStream::~SendVideoStream() {
440 sender_->SendTask(
441 [this] { sender_->call_->DestroyVideoSendStream(send_stream_); });
442 }
443
Start()444 void SendVideoStream::Start() {
445 sender_->SendTask([this] {
446 send_stream_->Start();
447 sender_->call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
448 });
449 }
450
Stop()451 void SendVideoStream::Stop() {
452 sender_->SendTask([this] { send_stream_->Stop(); });
453 }
454
UpdateConfig(std::function<void (VideoStreamConfig *)> modifier)455 void SendVideoStream::UpdateConfig(
456 std::function<void(VideoStreamConfig*)> modifier) {
457 sender_->SendTask([&] {
458 MutexLock lock(&mutex_);
459 VideoStreamConfig prior_config = config_;
460 modifier(&config_);
461 if (prior_config.encoder.fake.max_rate != config_.encoder.fake.max_rate) {
462 for (auto* encoder : fake_encoders_) {
463 encoder->SetMaxBitrate(config_.encoder.fake.max_rate.kbps());
464 }
465 }
466 // TODO(srte): Add more conditions that should cause reconfiguration.
467 if (prior_config.encoder.max_framerate != config_.encoder.max_framerate ||
468 prior_config.encoder.max_data_rate != config_.encoder.max_data_rate) {
469 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config_);
470 send_stream_->ReconfigureVideoEncoder(std::move(encoder_config));
471 }
472 if (prior_config.source.framerate != config_.source.framerate) {
473 SetCaptureFramerate(config_.source.framerate);
474 }
475 });
476 }
477
UpdateActiveLayers(std::vector<bool> active_layers)478 void SendVideoStream::UpdateActiveLayers(std::vector<bool> active_layers) {
479 sender_->task_queue_.PostTask([=] {
480 MutexLock lock(&mutex_);
481 if (config_.encoder.codec ==
482 VideoStreamConfig::Encoder::Codec::kVideoCodecVP8) {
483 send_stream_->StartPerRtpStream(active_layers);
484 }
485 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config_);
486 RTC_CHECK_EQ(encoder_config.simulcast_layers.size(), active_layers.size());
487 for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i)
488 encoder_config.simulcast_layers[i].active = active_layers[i];
489 send_stream_->ReconfigureVideoEncoder(std::move(encoder_config));
490 });
491 }
492
UsingSsrc(uint32_t ssrc) const493 bool SendVideoStream::UsingSsrc(uint32_t ssrc) const {
494 for (uint32_t owned : ssrcs_) {
495 if (owned == ssrc)
496 return true;
497 }
498 return false;
499 }
500
UsingRtxSsrc(uint32_t ssrc) const501 bool SendVideoStream::UsingRtxSsrc(uint32_t ssrc) const {
502 for (uint32_t owned : rtx_ssrcs_) {
503 if (owned == ssrc)
504 return true;
505 }
506 return false;
507 }
508
SetCaptureFramerate(int framerate)509 void SendVideoStream::SetCaptureFramerate(int framerate) {
510 sender_->SendTask([&] { video_capturer_->ChangeFramerate(framerate); });
511 }
512
GetStats() const513 VideoSendStream::Stats SendVideoStream::GetStats() const {
514 return send_stream_->GetStats();
515 }
516
StatsPrinter()517 ColumnPrinter SendVideoStream::StatsPrinter() {
518 return ColumnPrinter::Lambda(
519 "video_target_rate video_sent_rate width height",
520 [this](rtc::SimpleStringBuilder& sb) {
521 VideoSendStream::Stats video_stats = send_stream_->GetStats();
522 int width = 0;
523 int height = 0;
524 for (const auto& stream_stat : video_stats.substreams) {
525 width = std::max(width, stream_stat.second.width);
526 height = std::max(height, stream_stat.second.height);
527 }
528 sb.AppendFormat("%.0lf %.0lf %i %i",
529 video_stats.target_media_bitrate_bps / 8.0,
530 video_stats.media_bitrate_bps / 8.0, width, height);
531 },
532 64);
533 }
534
ReceiveVideoStream(CallClient * receiver,VideoStreamConfig config,SendVideoStream * send_stream,size_t chosen_stream,Transport * feedback_transport,VideoFrameMatcher * matcher)535 ReceiveVideoStream::ReceiveVideoStream(CallClient* receiver,
536 VideoStreamConfig config,
537 SendVideoStream* send_stream,
538 size_t chosen_stream,
539 Transport* feedback_transport,
540 VideoFrameMatcher* matcher)
541 : receiver_(receiver), config_(config) {
542 if (config.encoder.codec ==
543 VideoStreamConfig::Encoder::Codec::kVideoCodecGeneric ||
544 config.encoder.implementation == VideoStreamConfig::Encoder::kFake) {
545 decoder_factory_ = std::make_unique<FunctionVideoDecoderFactory>(
546 []() { return std::make_unique<FakeDecoder>(); });
547 } else {
548 decoder_factory_ = std::make_unique<InternalDecoderFactory>();
549 }
550
551 VideoReceiveStreamInterface::Decoder decoder =
552 CreateMatchingDecoder(CodecTypeToPayloadType(config.encoder.codec),
553 CodecTypeToPayloadString(config.encoder.codec));
554 size_t num_streams = config.encoder.simulcast_streams.size();
555 for (size_t i = 0; i < num_streams; ++i) {
556 rtc::VideoSinkInterface<VideoFrame>* renderer = &fake_renderer_;
557 if (matcher->Active()) {
558 render_taps_.emplace_back(
559 std::make_unique<DecodedFrameTap>(receiver_->clock_, matcher, i));
560 renderer = render_taps_.back().get();
561 }
562 auto recv_config = CreateVideoReceiveStreamConfig(
563 config, feedback_transport, decoder_factory_.get(), decoder, renderer,
564 receiver_->GetNextVideoLocalSsrc(), send_stream->ssrcs_[i],
565 send_stream->rtx_ssrcs_[i]);
566 if (config.stream.use_flexfec) {
567 RTC_DCHECK(num_streams == 1);
568 FlexfecReceiveStream::Config flexfec(feedback_transport);
569 flexfec.payload_type = CallTest::kFlexfecPayloadType;
570 flexfec.rtp.remote_ssrc = CallTest::kFlexfecSendSsrc;
571 flexfec.protected_media_ssrcs = send_stream->rtx_ssrcs_;
572 flexfec.rtp.local_ssrc = recv_config.rtp.local_ssrc;
573 receiver_->ssrc_media_types_[flexfec.rtp.remote_ssrc] = MediaType::VIDEO;
574
575 receiver_->SendTask([this, &flexfec] {
576 flecfec_stream_ = receiver_->call_->CreateFlexfecReceiveStream(flexfec);
577 });
578 }
579 receiver_->ssrc_media_types_[recv_config.rtp.remote_ssrc] =
580 MediaType::VIDEO;
581 if (config.stream.use_rtx)
582 receiver_->ssrc_media_types_[recv_config.rtp.rtx_ssrc] = MediaType::VIDEO;
583 receiver_->SendTask([this, &recv_config] {
584 receive_streams_.push_back(
585 receiver_->call_->CreateVideoReceiveStream(std::move(recv_config)));
586 });
587 }
588 }
589
~ReceiveVideoStream()590 ReceiveVideoStream::~ReceiveVideoStream() {
591 receiver_->SendTask([this] {
592 for (auto* recv_stream : receive_streams_)
593 receiver_->call_->DestroyVideoReceiveStream(recv_stream);
594 if (flecfec_stream_)
595 receiver_->call_->DestroyFlexfecReceiveStream(flecfec_stream_);
596 });
597 }
598
Start()599 void ReceiveVideoStream::Start() {
600 receiver_->SendTask([this] {
601 for (auto* recv_stream : receive_streams_)
602 recv_stream->Start();
603 receiver_->call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
604 });
605 }
606
Stop()607 void ReceiveVideoStream::Stop() {
608 receiver_->SendTask([this] {
609 for (auto* recv_stream : receive_streams_)
610 recv_stream->Stop();
611 });
612 }
613
GetStats() const614 VideoReceiveStreamInterface::Stats ReceiveVideoStream::GetStats() const {
615 if (receive_streams_.empty())
616 return VideoReceiveStreamInterface::Stats();
617 // TODO(srte): Handle multiple receive streams.
618 return receive_streams_.back()->GetStats();
619 }
620
621 VideoStreamPair::~VideoStreamPair() = default;
622
VideoStreamPair(CallClient * sender,CallClient * receiver,VideoStreamConfig config)623 VideoStreamPair::VideoStreamPair(CallClient* sender,
624 CallClient* receiver,
625 VideoStreamConfig config)
626 : config_(config),
627 matcher_(config.hooks.frame_pair_handlers),
628 send_stream_(sender, config, sender->transport_.get(), &matcher_),
629 receive_stream_(receiver,
630 config,
631 &send_stream_,
632 /*chosen_stream=*/0,
633 receiver->transport_.get(),
634 &matcher_) {}
635
636 } // namespace test
637 } // namespace webrtc
638