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