blob: 654aed7c6c263b85c92e47408bf6dd170f0c3134 [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>
Mirko Bonadei317a1f02019-09-17 15:06:1813#include <memory>
Sebastian Jansson98b07e912018-09-27 11:47:0114#include <utility>
15
Mirko Bonadei06d35592020-04-01 11:43:0816#include "absl/strings/match.h"
Artem Titov33f9d2b2019-12-05 14:59:0017#include "api/test/create_frame_generator.h"
18#include "api/test/frame_generator_interface.h"
Danil Chapovalov99b71df2018-10-26 13:57:4819#include "api/test/video/function_video_encoder_factory.h"
Jiawei Ouc2ebe212018-11-08 18:02:5620#include "api/video/builtin_video_bitrate_allocator_factory.h"
Steve Anton10542f22019-01-11 17:11:0021#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"
Niels Möller4a5a3da2022-06-17 09:26:0225#include "modules/video_coding/svc/scalability_mode_util.h"
Sebastian Jansson98b07e912018-09-27 11:47:0126#include "test/call_test.h"
27#include "test/fake_encoder.h"
Sebastian Jansson98b07e912018-09-27 11:47:0128#include "test/scenario/hardware_codecs.h"
Steve Anton10542f22019-01-11 17:11:0029#include "test/testsupport/file_utils.h"
Artem Titov8a9f3a82023-04-25 07:56:4930#include "test/video_test_constants.h"
Jonas Oreland1262eb52022-09-27 14:53:0431#include "video/config/encoder_stream_factory.h"
Sebastian Jansson98b07e912018-09-27 11:47:0132
33namespace webrtc {
34namespace test {
35namespace {
Elad Alond8d32482019-02-18 22:45:5736enum : int { // The first valid value is 1.
37 kTransportSequenceNumberExtensionId = 1,
Sebastian Janssone112bb82019-06-13 15:36:0138 kAbsSendTimeExtensionId,
Elad Alond8d32482019-02-18 22:45:5739 kVideoContentTypeExtensionId,
40 kVideoRotationRtpExtensionId,
41};
42
Sebastian Jansson98b07e912018-09-27 11:47:0143uint8_t CodecTypeToPayloadType(VideoCodecType codec_type) {
44 switch (codec_type) {
45 case VideoCodecType::kVideoCodecGeneric:
Artem Titov8a9f3a82023-04-25 07:56:4946 return VideoTestConstants::kFakeVideoSendPayloadType;
Sebastian Jansson98b07e912018-09-27 11:47:0147 case VideoCodecType::kVideoCodecVP8:
Artem Titov8a9f3a82023-04-25 07:56:4948 return VideoTestConstants::kPayloadTypeVP8;
Sebastian Jansson98b07e912018-09-27 11:47:0149 case VideoCodecType::kVideoCodecVP9:
Artem Titov8a9f3a82023-04-25 07:56:4950 return VideoTestConstants::kPayloadTypeVP9;
Sebastian Jansson98b07e912018-09-27 11:47:0151 case VideoCodecType::kVideoCodecH264:
Artem Titov8a9f3a82023-04-25 07:56:4952 return VideoTestConstants::kPayloadTypeH264;
qwu16ae82df72023-09-20 05:10:3153 case VideoCodecType::kVideoCodecH265:
54 return VideoTestConstants::kPayloadTypeH265;
Sebastian Jansson98b07e912018-09-27 11:47:0155 default:
Artem Titovd3251962021-11-15 15:57:0756 RTC_DCHECK_NOTREACHED();
Sebastian Jansson98b07e912018-09-27 11:47:0157 }
58 return {};
59}
60std::string CodecTypeToCodecName(VideoCodecType codec_type) {
61 switch (codec_type) {
62 case VideoCodecType::kVideoCodecGeneric:
63 return "";
64 case VideoCodecType::kVideoCodecVP8:
65 return cricket::kVp8CodecName;
66 case VideoCodecType::kVideoCodecVP9:
67 return cricket::kVp9CodecName;
68 case VideoCodecType::kVideoCodecH264:
69 return cricket::kH264CodecName;
qwu16ae82df72023-09-20 05:10:3170 case VideoCodecType::kVideoCodecH265:
71 return cricket::kH265CodecName;
Sebastian Jansson98b07e912018-09-27 11:47:0172 default:
Artem Titovd3251962021-11-15 15:57:0773 RTC_DCHECK_NOTREACHED();
Sebastian Jansson98b07e912018-09-27 11:47:0174 }
75 return {};
76}
Sebastian Janssonf0c366b2019-02-14 12:18:4277VideoEncoderConfig::ContentType ConvertContentType(
78 VideoStreamConfig::Encoder::ContentType content_type) {
79 switch (content_type) {
80 case VideoStreamConfig::Encoder::ContentType::kVideo:
81 return VideoEncoderConfig::ContentType::kRealtimeVideo;
Sebastian Janssonf0c366b2019-02-14 12:18:4282 case VideoStreamConfig::Encoder::ContentType::kScreen:
83 return VideoEncoderConfig::ContentType::kScreen;
84 }
85}
Niels Möller4a5a3da2022-06-17 09:26:0286
Sebastian Janssonf2727fb2019-02-18 15:54:5587std::string TransformFilePath(std::string path) {
88 static const std::string resource_prefix = "res://";
Mirko Bonadei5686e342020-12-16 06:29:0289 int ext_pos = path.rfind('.');
Sebastian Janssonf2727fb2019-02-18 15:54:5590 if (ext_pos < 0) {
91 return test::ResourcePath(path, "yuv");
Mirko Bonadei06d35592020-04-01 11:43:0892 } else if (absl::StartsWith(path, resource_prefix)) {
Sebastian Janssonf2727fb2019-02-18 15:54:5593 std::string name = path.substr(resource_prefix.length(), ext_pos);
94 std::string ext = path.substr(ext_pos, path.size());
95 return test::ResourcePath(name, ext);
96 }
97 return path;
98}
99
Sebastian Jansson3e66a492020-01-14 11:30:13100VideoSendStream::Config CreateVideoSendStreamConfig(
101 VideoStreamConfig config,
102 std::vector<uint32_t> ssrcs,
103 std::vector<uint32_t> rtx_ssrcs,
104 Transport* send_transport) {
Sebastian Jansson98b07e912018-09-27 11:47:01105 VideoSendStream::Config send_config(send_transport);
106 send_config.rtp.payload_name = CodecTypeToPayloadString(config.encoder.codec);
107 send_config.rtp.payload_type = CodecTypeToPayloadType(config.encoder.codec);
Sebastian Janssonc57b0ee2019-06-26 14:22:39108 send_config.rtp.nack.rtp_history_ms =
109 config.stream.nack_history_time.ms<int>();
Sebastian Jansson98b07e912018-09-27 11:47:01110
111 send_config.rtp.ssrcs = ssrcs;
112 send_config.rtp.extensions = GetVideoRtpExtensions(config);
113
Sebastian Jansson3e66a492020-01-14 11:30:13114 if (config.stream.use_rtx) {
Artem Titov8a9f3a82023-04-25 07:56:49115 send_config.rtp.rtx.payload_type = VideoTestConstants::kSendRtxPayloadType;
Sebastian Jansson3e66a492020-01-14 11:30:13116 send_config.rtp.rtx.ssrcs = rtx_ssrcs;
117 }
Sebastian Jansson98b07e912018-09-27 11:47:01118 if (config.stream.use_flexfec) {
Artem Titov8a9f3a82023-04-25 07:56:49119 send_config.rtp.flexfec.payload_type =
120 VideoTestConstants::kFlexfecPayloadType;
121 send_config.rtp.flexfec.ssrc = VideoTestConstants::kFlexfecSendSsrc;
Sebastian Jansson98b07e912018-09-27 11:47:01122 send_config.rtp.flexfec.protected_media_ssrcs = ssrcs;
123 }
124 if (config.stream.use_ulpfec) {
Artem Titov8a9f3a82023-04-25 07:56:49125 send_config.rtp.ulpfec.red_payload_type =
126 VideoTestConstants::kRedPayloadType;
127 send_config.rtp.ulpfec.ulpfec_payload_type =
128 VideoTestConstants::kUlpfecPayloadType;
129 send_config.rtp.ulpfec.red_rtx_payload_type =
130 VideoTestConstants::kRtxRedPayloadType;
Sebastian Jansson98b07e912018-09-27 11:47:01131 }
132 return send_config;
133}
134rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
Sebastian Jansson06c51452019-02-18 15:55:15135CreateVp9SpecificSettings(VideoStreamConfig video_config) {
136 constexpr auto kScreen = VideoStreamConfig::Encoder::ContentType::kScreen;
137 VideoStreamConfig::Encoder conf = video_config.encoder;
138 VideoCodecVP9 vp9 = VideoEncoder::GetDefaultVp9Settings();
Niels Möller4a5a3da2022-06-17 09:26:02139 // TODO(bugs.webrtc.org/11607): Support separate scalability mode per
140 // simulcast stream.
141 ScalabilityMode scalability_mode = conf.simulcast_streams[0];
Sebastian Jansson06c51452019-02-18 15:55:15142 vp9.keyFrameInterval = conf.key_frame_interval.value_or(0);
Niels Möller4a5a3da2022-06-17 09:26:02143 vp9.numberOfTemporalLayers =
144 ScalabilityModeToNumTemporalLayers(scalability_mode);
145 vp9.numberOfSpatialLayers =
146 ScalabilityModeToNumSpatialLayers(scalability_mode);
147 vp9.interLayerPred = ScalabilityModeToInterLayerPredMode(scalability_mode);
Sebastian Janssonf2727fb2019-02-18 15:54:55148
Sebastian Jansson06c51452019-02-18 15:55:15149 if (conf.content_type == kScreen &&
Niels Möller4a5a3da2022-06-17 09:26:02150 (video_config.source.framerate > 5 || vp9.numberOfSpatialLayers >= 3)) {
Sebastian Jansson06c51452019-02-18 15:55:15151 vp9.flexibleMode = true;
152 }
153
Niels Möller4a5a3da2022-06-17 09:26:02154 if (conf.content_type == kScreen || vp9.numberOfTemporalLayers > 1 ||
155 vp9.numberOfSpatialLayers > 1) {
Sebastian Jansson06c51452019-02-18 15:55:15156 vp9.automaticResizeOn = false;
157 vp9.denoisingOn = false;
158 } else {
159 vp9.automaticResizeOn = conf.single.automatic_scaling;
160 vp9.denoisingOn = conf.single.denoising;
Sebastian Janssonf2727fb2019-02-18 15:54:55161 }
Tommi87f70902021-04-27 12:43:08162 return rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>(
163 vp9);
Sebastian Janssonf0c366b2019-02-14 12:18:42164}
165
166rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
167CreateVp8SpecificSettings(VideoStreamConfig config) {
168 VideoCodecVP8 vp8_settings = VideoEncoder::GetDefaultVp8Settings();
Sebastian Janssonf0c366b2019-02-14 12:18:42169 vp8_settings.keyFrameInterval = config.encoder.key_frame_interval.value_or(0);
Niels Möller4a5a3da2022-06-17 09:26:02170 // TODO(bugs.webrtc.org/11607): Support separate scalability mode per
171 // simulcast stream.
172 ScalabilityMode scalability_mode = config.encoder.simulcast_streams[0];
173 vp8_settings.numberOfTemporalLayers =
174 ScalabilityModeToNumTemporalLayers(scalability_mode);
175 if (vp8_settings.numberOfTemporalLayers > 1 ||
176 config.encoder.simulcast_streams.size() > 1) {
Sebastian Jansson5fbebd52019-02-20 10:16:19177 vp8_settings.automaticResizeOn = false;
178 vp8_settings.denoisingOn = false;
179 } else {
180 vp8_settings.automaticResizeOn = config.encoder.single.automatic_scaling;
181 vp8_settings.denoisingOn = config.encoder.single.denoising;
182 }
Tommi87f70902021-04-27 12:43:08183 return rtc::make_ref_counted<VideoEncoderConfig::Vp8EncoderSpecificSettings>(
184 vp8_settings);
Sebastian Janssonf0c366b2019-02-14 12:18:42185}
186
187rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
188CreateH264SpecificSettings(VideoStreamConfig config) {
Niels Möller4a5a3da2022-06-17 09:26:02189 RTC_DCHECK_EQ(config.encoder.simulcast_streams.size(), 1);
190 RTC_DCHECK(config.encoder.simulcast_streams[0] == ScalabilityMode::kL1T1);
Niels Möllercf2c8912022-05-18 08:45:46191 // TODO(bugs.webrtc.org/6883): Set a key frame interval as a setting that
192 // isn't codec specific.
193 RTC_CHECK_EQ(0, config.encoder.key_frame_interval.value_or(0));
194 return nullptr;
Sebastian Janssonf0c366b2019-02-14 12:18:42195}
196
197rtc::scoped_refptr<VideoEncoderConfig::EncoderSpecificSettings>
Sebastian Jansson98b07e912018-09-27 11:47:01198CreateEncoderSpecificSettings(VideoStreamConfig config) {
199 using Codec = VideoStreamConfig::Encoder::Codec;
200 switch (config.encoder.codec) {
Sebastian Janssonf0c366b2019-02-14 12:18:42201 case Codec::kVideoCodecH264:
202 return CreateH264SpecificSettings(config);
203 case Codec::kVideoCodecVP8:
204 return CreateVp8SpecificSettings(config);
205 case Codec::kVideoCodecVP9:
206 return CreateVp9SpecificSettings(config);
207 case Codec::kVideoCodecGeneric:
Danil Chapovalovdc368292019-11-26 13:48:20208 case Codec::kVideoCodecAV1:
qwu16ae82df72023-09-20 05:10:31209 case Codec::kVideoCodecH265:
Sebastian Janssonf0c366b2019-02-14 12:18:42210 return nullptr;
211 case Codec::kVideoCodecMultiplex:
Artem Titovd3251962021-11-15 15:57:07212 RTC_DCHECK_NOTREACHED();
Sebastian Jansson98b07e912018-09-27 11:47:01213 return nullptr;
214 }
215}
216
217VideoEncoderConfig CreateVideoEncoderConfig(VideoStreamConfig config) {
Jonas Oreland80c87d72022-09-29 13:01:09218 webrtc::VideoEncoder::EncoderInfo encoder_info;
Sebastian Jansson98b07e912018-09-27 11:47:01219 VideoEncoderConfig encoder_config;
220 encoder_config.codec_type = config.encoder.codec;
Sebastian Janssonf0c366b2019-02-14 12:18:42221 encoder_config.content_type = ConvertContentType(config.encoder.content_type);
Sebastian Jansson98b07e912018-09-27 11:47:01222 encoder_config.video_format =
223 SdpVideoFormat(CodecTypeToPayloadString(config.encoder.codec), {});
Sebastian Janssonf0c366b2019-02-14 12:18:42224
Niels Möller4a5a3da2022-06-17 09:26:02225 encoder_config.number_of_streams = config.encoder.simulcast_streams.size();
Sebastian Janssone8226682019-04-30 12:29:09226 encoder_config.simulcast_layers =
Niels Möller4a5a3da2022-06-17 09:26:02227 std::vector<VideoStream>(encoder_config.number_of_streams);
Sebastian Jansson985ee682018-11-12 15:33:29228 encoder_config.min_transmit_bitrate_bps = config.stream.pad_to_rate.bps();
Sebastian Jansson98b07e912018-09-27 11:47:01229
230 std::string cricket_codec = CodecTypeToCodecName(config.encoder.codec);
231 if (!cricket_codec.empty()) {
Sebastian Jansson5fbebd52019-02-20 10:16:19232 bool screenshare = config.encoder.content_type ==
233 VideoStreamConfig::Encoder::ContentType::kScreen;
Sebastian Jansson98b07e912018-09-27 11:47:01234 encoder_config.video_stream_factory =
Tommi87f70902021-04-27 12:43:08235 rtc::make_ref_counted<cricket::EncoderStreamFactory>(
Sergey Silkinb6ef1a72023-10-23 15:11:21236 cricket_codec, cricket::kDefaultVideoMaxQpVpx, screenshare,
237 screenshare, encoder_info);
Sebastian Jansson98b07e912018-09-27 11:47:01238 } else {
239 encoder_config.video_stream_factory =
Tommi87f70902021-04-27 12:43:08240 rtc::make_ref_counted<DefaultVideoStreamFactory>();
Sebastian Jansson98b07e912018-09-27 11:47:01241 }
Sebastian Janssonf0c366b2019-02-14 12:18:42242
243 // TODO(srte): Base this on encoder capabilities.
244 encoder_config.max_bitrate_bps =
Danil Chapovalovcad3e0e2020-02-17 17:46:07245 config.encoder.max_data_rate.value_or(DataRate::KilobitsPerSec(10000))
246 .bps();
Sebastian Janssonf0c366b2019-02-14 12:18:42247
Niels Möller807328f2022-05-12 14:16:39248 encoder_config.frame_drop_enabled = config.encoder.frame_dropping;
Sebastian Jansson98b07e912018-09-27 11:47:01249 encoder_config.encoder_specific_settings =
250 CreateEncoderSpecificSettings(config);
Niels Möller4a5a3da2022-06-17 09:26:02251
252 for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
253 auto& layer = encoder_config.simulcast_layers[i];
254 if (config.encoder.max_framerate) {
Sebastian Jansson0c32e332018-11-12 15:47:43255 layer.max_framerate = *config.encoder.max_framerate;
Erik Språng279f3702020-10-13 19:55:07256 layer.min_bitrate_bps = config.encoder.min_data_rate->bps_or(-1);
Sebastian Jansson0c32e332018-11-12 15:47:43257 }
Niels Möller4a5a3da2022-06-17 09:26:02258 layer.scalability_mode = config.encoder.simulcast_streams[i];
Sebastian Jansson0c32e332018-11-12 15:47:43259 }
260
Sebastian Jansson98b07e912018-09-27 11:47:01261 return encoder_config;
262}
Sebastian Janssonf0c366b2019-02-14 12:18:42263
Artem Titov33f9d2b2019-12-05 14:59:00264std::unique_ptr<FrameGeneratorInterface> CreateImageSlideGenerator(
Sebastian Janssonf2727fb2019-02-18 15:54:55265 Clock* clock,
266 VideoStreamConfig::Source::Slides slides,
267 int framerate) {
268 std::vector<std::string> paths = slides.images.paths;
269 for (std::string& path : paths)
270 path = TransformFilePath(path);
271 if (slides.images.crop.width || slides.images.crop.height) {
272 TimeDelta pause_duration =
273 slides.change_interval - slides.images.crop.scroll_duration;
Sebastian Jansson5a000162019-04-12 09:21:32274 RTC_CHECK_GE(pause_duration, TimeDelta::Zero());
Sebastian Janssonf2727fb2019-02-18 15:54:55275 int crop_width = slides.images.crop.width.value_or(slides.images.width);
276 int crop_height = slides.images.crop.height.value_or(slides.images.height);
277 RTC_CHECK_LE(crop_width, slides.images.width);
278 RTC_CHECK_LE(crop_height, slides.images.height);
Artem Titov33f9d2b2019-12-05 14:59:00279 return CreateScrollingInputFromYuvFilesFrameGenerator(
Sebastian Janssonf2727fb2019-02-18 15:54:55280 clock, paths, slides.images.width, slides.images.height, crop_width,
281 crop_height, slides.images.crop.scroll_duration.ms(),
282 pause_duration.ms());
283 } else {
Artem Titov33f9d2b2019-12-05 14:59:00284 return CreateFromYuvFileFrameGenerator(
Sebastian Janssonf2727fb2019-02-18 15:54:55285 paths, slides.images.width, slides.images.height,
286 slides.change_interval.seconds<double>() * framerate);
287 }
288}
289
Artem Titov33f9d2b2019-12-05 14:59:00290std::unique_ptr<FrameGeneratorInterface> CreateFrameGenerator(
Sebastian Janssonf0c366b2019-02-14 12:18:42291 Clock* clock,
292 VideoStreamConfig::Source source) {
293 using Capture = VideoStreamConfig::Source::Capture;
294 switch (source.capture) {
295 case Capture::kGenerator:
Artem Titov33f9d2b2019-12-05 14:59:00296 return CreateSquareFrameGenerator(
Sebastian Janssonf0c366b2019-02-14 12:18:42297 source.generator.width, source.generator.height,
298 source.generator.pixel_format, /*num_squares*/ absl::nullopt);
299 case Capture::kVideoFile:
300 RTC_CHECK(source.video_file.width && source.video_file.height);
Artem Titov33f9d2b2019-12-05 14:59:00301 return CreateFromYuvFileFrameGenerator(
Sebastian Janssond37307c2019-02-22 16:07:49302 {TransformFilePath(source.video_file.name)}, source.video_file.width,
Sebastian Janssonf0c366b2019-02-14 12:18:42303 source.video_file.height, /*frame_repeat_count*/ 1);
Sebastian Janssonf2727fb2019-02-18 15:54:55304 case Capture::kGenerateSlides:
Artem Titov33f9d2b2019-12-05 14:59:00305 return CreateSlideFrameGenerator(
Sebastian Janssonf2727fb2019-02-18 15:54:55306 source.slides.generator.width, source.slides.generator.height,
307 source.slides.change_interval.seconds<double>() * source.framerate);
308 case Capture::kImageSlides:
309 return CreateImageSlideGenerator(clock, source.slides, source.framerate);
Sebastian Janssonf0c366b2019-02-14 12:18:42310 }
311}
312
Tommif6f45432022-05-20 13:21:20313VideoReceiveStreamInterface::Config CreateVideoReceiveStreamConfig(
Sebastian Jansson5fbebd52019-02-20 10:16:19314 VideoStreamConfig config,
315 Transport* feedback_transport,
Philip Eliasson2b068ce2020-08-03 15:55:10316 VideoDecoderFactory* decoder_factory,
Tommif6f45432022-05-20 13:21:20317 VideoReceiveStreamInterface::Decoder decoder,
Sebastian Jansson5fbebd52019-02-20 10:16:19318 rtc::VideoSinkInterface<VideoFrame>* renderer,
319 uint32_t local_ssrc,
320 uint32_t ssrc,
321 uint32_t rtx_ssrc) {
Tommif6f45432022-05-20 13:21:20322 VideoReceiveStreamInterface::Config recv(feedback_transport);
Sebastian Jansson5fbebd52019-02-20 10:16:19323 recv.rtp.local_ssrc = local_ssrc;
Sebastian Jansson24cf2602019-06-07 13:24:57324
Sebastian Jansson5fbebd52019-02-20 10:16:19325 RTC_DCHECK(!config.stream.use_rtx ||
326 config.stream.nack_history_time > TimeDelta::Zero());
327 recv.rtp.nack.rtp_history_ms = config.stream.nack_history_time.ms();
328 recv.rtp.protected_by_flexfec = config.stream.use_flexfec;
329 recv.rtp.remote_ssrc = ssrc;
Philip Eliasson2b068ce2020-08-03 15:55:10330 recv.decoder_factory = decoder_factory;
Sebastian Jansson5fbebd52019-02-20 10:16:19331 recv.decoders.push_back(decoder);
332 recv.renderer = renderer;
333 if (config.stream.use_rtx) {
334 recv.rtp.rtx_ssrc = rtx_ssrc;
Artem Titov8a9f3a82023-04-25 07:56:49335 recv.rtp
336 .rtx_associated_payload_types[VideoTestConstants::kSendRtxPayloadType] =
Sebastian Jansson5fbebd52019-02-20 10:16:19337 CodecTypeToPayloadType(config.encoder.codec);
338 }
339 if (config.stream.use_ulpfec) {
Artem Titov8a9f3a82023-04-25 07:56:49340 recv.rtp.red_payload_type = VideoTestConstants::kRedPayloadType;
341 recv.rtp.ulpfec_payload_type = VideoTestConstants::kUlpfecPayloadType;
342 recv.rtp
343 .rtx_associated_payload_types[VideoTestConstants::kRtxRedPayloadType] =
344 VideoTestConstants::kRedPayloadType;
Sebastian Jansson5fbebd52019-02-20 10:16:19345 }
Sebastian Janssoncc5be542019-04-01 11:34:55346 recv.sync_group = config.render.sync_group;
Sebastian Jansson5fbebd52019-02-20 10:16:19347 return recv;
348}
Sebastian Jansson98b07e912018-09-27 11:47:01349} // namespace
350
Per Kb3046c22023-01-12 16:00:22351std::vector<RtpExtension> GetVideoRtpExtensions(
352 const VideoStreamConfig config) {
353 std::vector<RtpExtension> res = {
354 RtpExtension(RtpExtension::kVideoContentTypeUri,
355 kVideoContentTypeExtensionId),
356 RtpExtension(RtpExtension::kVideoRotationUri,
357 kVideoRotationRtpExtensionId)};
358 if (config.stream.packet_feedback) {
359 res.push_back(RtpExtension(RtpExtension::kTransportSequenceNumberUri,
360 kTransportSequenceNumberExtensionId));
361 }
362 if (config.stream.abs_send_time) {
363 res.push_back(
364 RtpExtension(RtpExtension::kAbsSendTimeUri, kAbsSendTimeExtensionId));
365 }
366 return res;
367}
368
Sebastian Jansson98b07e912018-09-27 11:47:01369SendVideoStream::SendVideoStream(CallClient* sender,
370 VideoStreamConfig config,
Sebastian Jansson9a4f38e2018-12-19 12:14:41371 Transport* send_transport,
Sebastian Janssoncf2df2f2019-04-02 09:51:28372 VideoFrameMatcher* matcher)
Sebastian Jansson98b07e912018-09-27 11:47:01373 : sender_(sender), config_(config) {
Mirko Bonadei317a1f02019-09-17 15:06:18374 video_capturer_ = std::make_unique<FrameGeneratorCapturer>(
Danil Chapovalov59d0b8d2023-11-29 18:05:54375 &sender_->env_.clock(),
376 CreateFrameGenerator(&sender_->env_.clock(), config.source),
377 config.source.framerate, sender_->env_.task_queue_factory());
Sebastian Janssonf0c366b2019-02-14 12:18:42378 video_capturer_->Init();
Sebastian Jansson98b07e912018-09-27 11:47:01379
380 using Encoder = VideoStreamConfig::Encoder;
381 using Codec = VideoStreamConfig::Encoder::Codec;
382 switch (config.encoder.implementation) {
383 case Encoder::Implementation::kFake:
Jonas Olssona4d87372019-07-05 17:08:33384 encoder_factory_ =
Mirko Bonadei317a1f02019-09-17 15:06:18385 std::make_unique<FunctionVideoEncoderFactory>([this]() {
Markus Handella5a4be12020-07-08 14:09:21386 MutexLock lock(&mutex_);
Jonas Olssona4d87372019-07-05 17:08:33387 std::unique_ptr<FakeEncoder> encoder;
388 if (config_.encoder.codec == Codec::kVideoCodecVP8) {
Danil Chapovalov59d0b8d2023-11-29 18:05:54389 encoder = std::make_unique<test::FakeVp8Encoder>(
390 &sender_->env_.clock());
Jonas Olssona4d87372019-07-05 17:08:33391 } else if (config_.encoder.codec == Codec::kVideoCodecGeneric) {
Danil Chapovalov59d0b8d2023-11-29 18:05:54392 encoder =
393 std::make_unique<test::FakeEncoder>(&sender_->env_.clock());
Jonas Olssona4d87372019-07-05 17:08:33394 } else {
Artem Titovd3251962021-11-15 15:57:07395 RTC_DCHECK_NOTREACHED();
Jonas Olssona4d87372019-07-05 17:08:33396 }
397 fake_encoders_.push_back(encoder.get());
398 if (config_.encoder.fake.max_rate.IsFinite())
399 encoder->SetMaxBitrate(config_.encoder.fake.max_rate.kbps());
400 return encoder;
401 });
Sebastian Jansson98b07e912018-09-27 11:47:01402 break;
403 case VideoStreamConfig::Encoder::Implementation::kSoftware:
404 encoder_factory_.reset(new InternalEncoderFactory());
405 break;
406 case VideoStreamConfig::Encoder::Implementation::kHardware:
407 encoder_factory_ = CreateHardwareEncoderFactory();
408 break;
409 }
410 RTC_CHECK(encoder_factory_);
411
Jiawei Ouc2ebe212018-11-08 18:02:56412 bitrate_allocator_factory_ = CreateBuiltinVideoBitrateAllocatorFactory();
413 RTC_CHECK(bitrate_allocator_factory_);
414
Sebastian Janssonf0c366b2019-02-14 12:18:42415 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config);
416 for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
417 ssrcs_.push_back(sender->GetNextVideoSsrc());
418 rtx_ssrcs_.push_back(sender->GetNextRtxSsrc());
419 }
Sebastian Jansson98b07e912018-09-27 11:47:01420 VideoSendStream::Config send_config =
Sebastian Jansson3e66a492020-01-14 11:30:13421 CreateVideoSendStreamConfig(config, ssrcs_, rtx_ssrcs_, send_transport);
Sebastian Jansson98b07e912018-09-27 11:47:01422 send_config.encoder_settings.encoder_factory = encoder_factory_.get();
Jiawei Ouc2ebe212018-11-08 18:02:56423 send_config.encoder_settings.bitrate_allocator_factory =
424 bitrate_allocator_factory_.get();
Erik Språng279f3702020-10-13 19:55:07425 send_config.suspend_below_min_bitrate =
426 config.encoder.suspend_below_min_bitrate;
Jiawei Ouc2ebe212018-11-08 18:02:56427
Artem Titovf92cc6d2023-06-29 12:56:59428 video_capturer_->Start();
Sebastian Jansson105a10a2019-04-01 07:18:14429 sender_->SendTask([&] {
Sebastian Janssoncc5be542019-04-01 11:34:55430 if (config.stream.fec_controller_factory) {
431 send_stream_ = sender_->call_->CreateVideoSendStream(
432 std::move(send_config), std::move(encoder_config),
Danil Chapovalov55a61892024-01-03 17:39:27433 config.stream.fec_controller_factory->CreateFecController(
434 sender_->env_));
Sebastian Janssoncc5be542019-04-01 11:34:55435 } else {
436 send_stream_ = sender_->call_->CreateVideoSendStream(
437 std::move(send_config), std::move(encoder_config));
438 }
Sebastian Jansson98b07e912018-09-27 11:47:01439
Sebastian Janssoncf2df2f2019-04-02 09:51:28440 if (matcher->Active()) {
Mirko Bonadei317a1f02019-09-17 15:06:18441 frame_tap_ = std::make_unique<ForwardingCapturedFrameTap>(
Danil Chapovalov59d0b8d2023-11-29 18:05:54442 &sender_->env_.clock(), matcher, video_capturer_.get());
Sebastian Jansson105a10a2019-04-01 07:18:14443 send_stream_->SetSource(frame_tap_.get(),
444 config.encoder.degradation_preference);
445 } else {
446 send_stream_->SetSource(video_capturer_.get(),
447 config.encoder.degradation_preference);
448 }
449 });
Sebastian Jansson98b07e912018-09-27 11:47:01450}
451
452SendVideoStream::~SendVideoStream() {
Sebastian Jansson105a10a2019-04-01 07:18:14453 sender_->SendTask(
454 [this] { sender_->call_->DestroyVideoSendStream(send_stream_); });
Sebastian Jansson98b07e912018-09-27 11:47:01455}
456
457void SendVideoStream::Start() {
Sebastian Jansson105a10a2019-04-01 07:18:14458 sender_->SendTask([this] {
459 send_stream_->Start();
460 sender_->call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
461 });
Sebastian Jansson98b07e912018-09-27 11:47:01462}
463
Christoffer Rodbro5f6abcf2019-02-08 10:00:10464void SendVideoStream::Stop() {
Sebastian Jansson105a10a2019-04-01 07:18:14465 sender_->SendTask([this] { send_stream_->Stop(); });
Christoffer Rodbro5f6abcf2019-02-08 10:00:10466}
467
Sebastian Jansson0c32e332018-11-12 15:47:43468void SendVideoStream::UpdateConfig(
469 std::function<void(VideoStreamConfig*)> modifier) {
Sebastian Jansson105a10a2019-04-01 07:18:14470 sender_->SendTask([&] {
Markus Handella5a4be12020-07-08 14:09:21471 MutexLock lock(&mutex_);
Sebastian Jansson105a10a2019-04-01 07:18:14472 VideoStreamConfig prior_config = config_;
473 modifier(&config_);
474 if (prior_config.encoder.fake.max_rate != config_.encoder.fake.max_rate) {
475 for (auto* encoder : fake_encoders_) {
476 encoder->SetMaxBitrate(config_.encoder.fake.max_rate.kbps());
477 }
Sebastian Jansson0c32e332018-11-12 15:47:43478 }
Sebastian Jansson105a10a2019-04-01 07:18:14479 // TODO(srte): Add more conditions that should cause reconfiguration.
Erik Språng3e3e1662020-10-06 19:51:21480 if (prior_config.encoder.max_framerate != config_.encoder.max_framerate ||
481 prior_config.encoder.max_data_rate != config_.encoder.max_data_rate) {
Sebastian Jansson105a10a2019-04-01 07:18:14482 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config_);
483 send_stream_->ReconfigureVideoEncoder(std::move(encoder_config));
484 }
485 if (prior_config.source.framerate != config_.source.framerate) {
486 SetCaptureFramerate(config_.source.framerate);
487 }
488 });
Sebastian Jansson0c32e332018-11-12 15:47:43489}
490
Sebastian Janssone8226682019-04-30 12:29:09491void SendVideoStream::UpdateActiveLayers(std::vector<bool> active_layers) {
492 sender_->task_queue_.PostTask([=] {
Markus Handella5a4be12020-07-08 14:09:21493 MutexLock lock(&mutex_);
Sebastian Janssone8226682019-04-30 12:29:09494 if (config_.encoder.codec ==
495 VideoStreamConfig::Encoder::Codec::kVideoCodecVP8) {
Per Kjellander59ade012022-12-02 08:09:37496 send_stream_->StartPerRtpStream(active_layers);
Sebastian Janssone8226682019-04-30 12:29:09497 }
Erik Språng3e3e1662020-10-06 19:51:21498 VideoEncoderConfig encoder_config = CreateVideoEncoderConfig(config_);
499 RTC_CHECK_EQ(encoder_config.simulcast_layers.size(), active_layers.size());
500 for (size_t i = 0; i < encoder_config.simulcast_layers.size(); ++i)
501 encoder_config.simulcast_layers[i].active = active_layers[i];
502 send_stream_->ReconfigureVideoEncoder(std::move(encoder_config));
Sebastian Janssone8226682019-04-30 12:29:09503 });
504}
505
Sebastian Jansson3d4d94a2020-01-14 13:25:41506bool SendVideoStream::UsingSsrc(uint32_t ssrc) const {
507 for (uint32_t owned : ssrcs_) {
508 if (owned == ssrc)
509 return true;
510 }
511 return false;
512}
513
514bool SendVideoStream::UsingRtxSsrc(uint32_t ssrc) const {
515 for (uint32_t owned : rtx_ssrcs_) {
516 if (owned == ssrc)
517 return true;
518 }
519 return false;
520}
521
Sebastian Jansson98b07e912018-09-27 11:47:01522void SendVideoStream::SetCaptureFramerate(int framerate) {
Sebastian Jansson105a10a2019-04-01 07:18:14523 sender_->SendTask([&] { video_capturer_->ChangeFramerate(framerate); });
Sebastian Jansson98b07e912018-09-27 11:47:01524}
525
526VideoSendStream::Stats SendVideoStream::GetStats() const {
527 return send_stream_->GetStats();
528}
529
530ColumnPrinter SendVideoStream::StatsPrinter() {
531 return ColumnPrinter::Lambda(
532 "video_target_rate video_sent_rate width height",
533 [this](rtc::SimpleStringBuilder& sb) {
534 VideoSendStream::Stats video_stats = send_stream_->GetStats();
535 int width = 0;
536 int height = 0;
Mirko Bonadei739baf02019-01-27 16:29:42537 for (const auto& stream_stat : video_stats.substreams) {
Sebastian Jansson98b07e912018-09-27 11:47:01538 width = std::max(width, stream_stat.second.width);
539 height = std::max(height, stream_stat.second.height);
540 }
541 sb.AppendFormat("%.0lf %.0lf %i %i",
542 video_stats.target_media_bitrate_bps / 8.0,
543 video_stats.media_bitrate_bps / 8.0, width, height);
544 },
545 64);
546}
547
548ReceiveVideoStream::ReceiveVideoStream(CallClient* receiver,
549 VideoStreamConfig config,
550 SendVideoStream* send_stream,
551 size_t chosen_stream,
Sebastian Jansson9a4f38e2018-12-19 12:14:41552 Transport* feedback_transport,
Sebastian Janssoncf2df2f2019-04-02 09:51:28553 VideoFrameMatcher* matcher)
Sebastian Jansson0c32e332018-11-12 15:47:43554 : receiver_(receiver), config_(config) {
Sebastian Jansson0c32e332018-11-12 15:47:43555 if (config.encoder.codec ==
Sebastian Jansson3d4d94a2020-01-14 13:25:41556 VideoStreamConfig::Encoder::Codec::kVideoCodecGeneric ||
557 config.encoder.implementation == VideoStreamConfig::Encoder::kFake) {
Mirko Bonadei317a1f02019-09-17 15:06:18558 decoder_factory_ = std::make_unique<FunctionVideoDecoderFactory>(
559 []() { return std::make_unique<FakeDecoder>(); });
Sebastian Jansson0c32e332018-11-12 15:47:43560 } else {
Mirko Bonadei317a1f02019-09-17 15:06:18561 decoder_factory_ = std::make_unique<InternalDecoderFactory>();
Sebastian Jansson0c32e332018-11-12 15:47:43562 }
Sebastian Jansson98b07e912018-09-27 11:47:01563
Tommif6f45432022-05-20 13:21:20564 VideoReceiveStreamInterface::Decoder decoder =
Sebastian Jansson5fbebd52019-02-20 10:16:19565 CreateMatchingDecoder(CodecTypeToPayloadType(config.encoder.codec),
566 CodecTypeToPayloadString(config.encoder.codec));
Niels Möller4a5a3da2022-06-17 09:26:02567 size_t num_streams = config.encoder.simulcast_streams.size();
Sebastian Jansson5fbebd52019-02-20 10:16:19568 for (size_t i = 0; i < num_streams; ++i) {
569 rtc::VideoSinkInterface<VideoFrame>* renderer = &fake_renderer_;
Sebastian Janssoncf2df2f2019-04-02 09:51:28570 if (matcher->Active()) {
Danil Chapovalov59d0b8d2023-11-29 18:05:54571 render_taps_.emplace_back(std::make_unique<DecodedFrameTap>(
572 &receiver_->env_.clock(), matcher, i));
Sebastian Janssoncf2df2f2019-04-02 09:51:28573 renderer = render_taps_.back().get();
Sebastian Jansson5fbebd52019-02-20 10:16:19574 }
575 auto recv_config = CreateVideoReceiveStreamConfig(
Philip Eliasson2b068ce2020-08-03 15:55:10576 config, feedback_transport, decoder_factory_.get(), decoder, renderer,
Sebastian Jansson5fbebd52019-02-20 10:16:19577 receiver_->GetNextVideoLocalSsrc(), send_stream->ssrcs_[i],
578 send_stream->rtx_ssrcs_[i]);
579 if (config.stream.use_flexfec) {
580 RTC_DCHECK(num_streams == 1);
581 FlexfecReceiveStream::Config flexfec(feedback_transport);
Artem Titov8a9f3a82023-04-25 07:56:49582 flexfec.payload_type = VideoTestConstants::kFlexfecPayloadType;
583 flexfec.rtp.remote_ssrc = VideoTestConstants::kFlexfecSendSsrc;
Sebastian Jansson5fbebd52019-02-20 10:16:19584 flexfec.protected_media_ssrcs = send_stream->rtx_ssrcs_;
Tommi1c1f5402021-06-14 08:54:20585 flexfec.rtp.local_ssrc = recv_config.rtp.local_ssrc;
586 receiver_->ssrc_media_types_[flexfec.rtp.remote_ssrc] = MediaType::VIDEO;
Sebastian Jansson342f98b2019-06-18 14:08:23587
588 receiver_->SendTask([this, &flexfec] {
589 flecfec_stream_ = receiver_->call_->CreateFlexfecReceiveStream(flexfec);
590 });
Sebastian Jansson5fbebd52019-02-20 10:16:19591 }
592 receiver_->ssrc_media_types_[recv_config.rtp.remote_ssrc] =
593 MediaType::VIDEO;
594 if (config.stream.use_rtx)
595 receiver_->ssrc_media_types_[recv_config.rtp.rtx_ssrc] = MediaType::VIDEO;
Sebastian Jansson105a10a2019-04-01 07:18:14596 receiver_->SendTask([this, &recv_config] {
597 receive_streams_.push_back(
598 receiver_->call_->CreateVideoReceiveStream(std::move(recv_config)));
599 });
Sebastian Jansson98b07e912018-09-27 11:47:01600 }
Sebastian Jansson98b07e912018-09-27 11:47:01601}
602
603ReceiveVideoStream::~ReceiveVideoStream() {
Sebastian Jansson105a10a2019-04-01 07:18:14604 receiver_->SendTask([this] {
605 for (auto* recv_stream : receive_streams_)
606 receiver_->call_->DestroyVideoReceiveStream(recv_stream);
607 if (flecfec_stream_)
608 receiver_->call_->DestroyFlexfecReceiveStream(flecfec_stream_);
609 });
Sebastian Jansson98b07e912018-09-27 11:47:01610}
611
Sebastian Jansson49a78432018-11-20 15:15:29612void ReceiveVideoStream::Start() {
Sebastian Jansson105a10a2019-04-01 07:18:14613 receiver_->SendTask([this] {
614 for (auto* recv_stream : receive_streams_)
615 recv_stream->Start();
616 receiver_->call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
617 });
Sebastian Jansson49a78432018-11-20 15:15:29618}
619
Sebastian Janssonbdfadd62019-02-08 12:34:57620void ReceiveVideoStream::Stop() {
Sebastian Jansson105a10a2019-04-01 07:18:14621 receiver_->SendTask([this] {
622 for (auto* recv_stream : receive_streams_)
623 recv_stream->Stop();
624 });
Sebastian Janssonbdfadd62019-02-08 12:34:57625}
626
Tommif6f45432022-05-20 13:21:20627VideoReceiveStreamInterface::Stats ReceiveVideoStream::GetStats() const {
Sebastian Janssonf4481c82019-04-09 10:48:34628 if (receive_streams_.empty())
Tommif6f45432022-05-20 13:21:20629 return VideoReceiveStreamInterface::Stats();
Sebastian Janssonf4481c82019-04-09 10:48:34630 // TODO(srte): Handle multiple receive streams.
Sebastian Jansson8ad34272020-02-27 11:54:16631 return receive_streams_.back()->GetStats();
Sebastian Janssonf4481c82019-04-09 10:48:34632}
633
Sebastian Jansson98b07e912018-09-27 11:47:01634VideoStreamPair::~VideoStreamPair() = default;
635
Sebastian Janssoncf2df2f2019-04-02 09:51:28636VideoStreamPair::VideoStreamPair(CallClient* sender,
637 CallClient* receiver,
638 VideoStreamConfig config)
Sebastian Jansson98b07e912018-09-27 11:47:01639 : config_(config),
Sebastian Janssoncf2df2f2019-04-02 09:51:28640 matcher_(config.hooks.frame_pair_handlers),
641 send_stream_(sender, config, sender->transport_.get(), &matcher_),
Sebastian Jansson98b07e912018-09-27 11:47:01642 receive_stream_(receiver,
643 config,
644 &send_stream_,
645 /*chosen_stream=*/0,
Sebastian Jansson105a10a2019-04-01 07:18:14646 receiver->transport_.get(),
Sebastian Janssoncf2df2f2019-04-02 09:51:28647 &matcher_) {}
Sebastian Jansson98b07e912018-09-27 11:47:01648
649} // namespace test
650} // namespace webrtc