xref: /aosp_15_r20/external/webrtc/test/scenario/video_stream.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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