blob: 7df6809523261e32e35e92ee67ba6710f386699b [file] [log] [blame]
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001/*
2 * libjingle
3 * Copyright 2014 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifdef HAVE_WEBRTC_VIDEO
29#include "talk/media/webrtc/webrtcvideoengine2.h"
30
pbos@webrtc.org3c107582014-07-20 15:27:35 +000031#include <set>
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000032#include <string>
33
34#include "libyuv/convert_from.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000035#include "talk/media/base/videocapturer.h"
36#include "talk/media/base/videorenderer.h"
buildbot@webrtc.orgdf9bbbe2014-06-19 19:54:33 +000037#include "talk/media/webrtc/constants.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000038#include "talk/media/webrtc/webrtcvideocapturer.h"
39#include "talk/media/webrtc/webrtcvideoframe.h"
40#include "talk/media/webrtc/webrtcvoiceengine.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000041#include "webrtc/base/buffer.h"
42#include "webrtc/base/logging.h"
43#include "webrtc/base/stringutils.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000044#include "webrtc/call.h"
pbos@webrtc.org776e6f22014-10-29 15:28:39 +000045#include "webrtc/video_decoder.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000046#include "webrtc/video_encoder.h"
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +000047
48#define UNIMPLEMENTED \
49 LOG(LS_ERROR) << "Call to unimplemented function " << __FUNCTION__; \
50 ASSERT(false)
51
52namespace cricket {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +000053namespace {
54
55static bool CodecNameMatches(const std::string& name1,
56 const std::string& name2) {
57 return _stricmp(name1.c_str(), name2.c_str()) == 0;
58}
59
60// True if codec is supported by a software implementation that's always
61// available.
62static bool CodecIsInternallySupported(const std::string& codec_name) {
63 return CodecNameMatches(codec_name, kVp8CodecName);
64}
65
66static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
67 std::stringstream out;
68 out << '{';
69 for (size_t i = 0; i < codecs.size(); ++i) {
70 out << codecs[i].ToString();
71 if (i != codecs.size() - 1) {
72 out << ", ";
73 }
74 }
75 out << '}';
76 return out.str();
77}
78
79static bool ValidateCodecFormats(const std::vector<VideoCodec>& codecs) {
80 bool has_video = false;
81 for (size_t i = 0; i < codecs.size(); ++i) {
82 if (!codecs[i].ValidateCodecFormat()) {
83 return false;
84 }
85 if (codecs[i].GetCodecType() == VideoCodec::CODEC_VIDEO) {
86 has_video = true;
87 }
88 }
89 if (!has_video) {
90 LOG(LS_ERROR) << "Setting codecs without a video codec is invalid: "
91 << CodecVectorToString(codecs);
92 return false;
93 }
94 return true;
95}
96
97static std::string RtpExtensionsToString(
98 const std::vector<RtpHeaderExtension>& extensions) {
99 std::stringstream out;
100 out << '{';
101 for (size_t i = 0; i < extensions.size(); ++i) {
102 out << "{" << extensions[i].uri << ": " << extensions[i].id << "}";
103 if (i != extensions.size() - 1) {
104 out << ", ";
105 }
106 }
107 out << '}';
108 return out.str();
109}
110
111} // namespace
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000112
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000113// This constant is really an on/off, lower-level configurable NACK history
114// duration hasn't been implemented.
115static const int kNackHistoryMs = 1000;
116
buildbot@webrtc.org933d88a2014-09-18 20:23:05 +0000117static const int kDefaultQpMax = 56;
118
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000119static const int kDefaultRtcpReceiverReportSsrc = 1;
120
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000121// External video encoders are given payloads 120-127. This also means that we
122// only support up to 8 external payload types.
123static const int kExternalVideoPayloadTypeBase = 120;
124#ifndef NDEBUG
125static const size_t kMaxExternalVideoCodecs = 8;
126#endif
127
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000128struct VideoCodecPref {
129 int payload_type;
pbos@webrtc.org97fdeb82014-08-22 10:36:23 +0000130 int width;
131 int height;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000132 const char* name;
133 int rtx_payload_type;
pbos@webrtc.org97fdeb82014-08-22 10:36:23 +0000134} kDefaultVideoCodecPref = {100, 640, 400, kVp8CodecName, 96};
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000135
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000136const char kH264CodecName[] = "H264";
137
pbos@webrtc.org97fdeb82014-08-22 10:36:23 +0000138VideoCodecPref kRedPref = {116, -1, -1, kRedCodecName, -1};
139VideoCodecPref kUlpfecPref = {117, -1, -1, kUlpfecCodecName, -1};
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000140
141static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs,
142 const VideoCodec& requested_codec,
143 VideoCodec* matching_codec) {
144 for (size_t i = 0; i < codecs.size(); ++i) {
145 if (requested_codec.Matches(codecs[i])) {
146 *matching_codec = codecs[i];
147 return true;
148 }
149 }
150 return false;
151}
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000152
pbos@webrtc.orgf99c2f22014-06-13 12:27:38 +0000153static void AddDefaultFeedbackParams(VideoCodec* codec) {
154 const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
155 codec->AddFeedbackParam(kFir);
156 const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
157 codec->AddFeedbackParam(kNack);
158 const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli);
159 codec->AddFeedbackParam(kPli);
160 const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
161 codec->AddFeedbackParam(kRemb);
162}
163
164static bool IsNackEnabled(const VideoCodec& codec) {
165 return codec.HasFeedbackParam(
166 FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
167}
168
pbos@webrtc.org257e1302014-07-25 19:01:32 +0000169static bool IsRembEnabled(const VideoCodec& codec) {
170 return codec.HasFeedbackParam(
171 FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty));
172}
173
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000174static VideoCodec DefaultVideoCodec() {
175 VideoCodec default_codec(kDefaultVideoCodecPref.payload_type,
176 kDefaultVideoCodecPref.name,
pbos@webrtc.org97fdeb82014-08-22 10:36:23 +0000177 kDefaultVideoCodecPref.width,
178 kDefaultVideoCodecPref.height,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000179 kDefaultFramerate,
180 0);
pbos@webrtc.orgf99c2f22014-06-13 12:27:38 +0000181 AddDefaultFeedbackParams(&default_codec);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000182 return default_codec;
183}
184
185static VideoCodec DefaultRedCodec() {
186 return VideoCodec(kRedPref.payload_type, kRedPref.name, 0, 0, 0, 0);
187}
188
189static VideoCodec DefaultUlpfecCodec() {
190 return VideoCodec(kUlpfecPref.payload_type, kUlpfecPref.name, 0, 0, 0, 0);
191}
192
193static std::vector<VideoCodec> DefaultVideoCodecs() {
194 std::vector<VideoCodec> codecs;
195 codecs.push_back(DefaultVideoCodec());
196 codecs.push_back(DefaultRedCodec());
197 codecs.push_back(DefaultUlpfecCodec());
198 if (kDefaultVideoCodecPref.rtx_payload_type != -1) {
199 codecs.push_back(
200 VideoCodec::CreateRtxCodec(kDefaultVideoCodecPref.rtx_payload_type,
201 kDefaultVideoCodecPref.payload_type));
202 }
203 return codecs;
204}
205
pbos@webrtc.org3c107582014-07-20 15:27:35 +0000206static bool ValidateRtpHeaderExtensionIds(
207 const std::vector<RtpHeaderExtension>& extensions) {
208 std::set<int> extensions_used;
209 for (size_t i = 0; i < extensions.size(); ++i) {
210 if (extensions[i].id < 0 || extensions[i].id >= 15 ||
211 !extensions_used.insert(extensions[i].id).second) {
212 LOG(LS_ERROR) << "RTP extensions are with incorrect or duplicate ids.";
213 return false;
214 }
215 }
216 return true;
217}
218
219static std::vector<webrtc::RtpExtension> FilterRtpExtensions(
220 const std::vector<RtpHeaderExtension>& extensions) {
221 std::vector<webrtc::RtpExtension> webrtc_extensions;
222 for (size_t i = 0; i < extensions.size(); ++i) {
223 // Unsupported extensions will be ignored.
224 if (webrtc::RtpExtension::IsSupported(extensions[i].uri)) {
225 webrtc_extensions.push_back(webrtc::RtpExtension(
226 extensions[i].uri, extensions[i].id));
227 } else {
228 LOG(LS_WARNING) << "Unsupported RTP extension: " << extensions[i].uri;
229 }
230 }
231 return webrtc_extensions;
232}
233
pbos@webrtc.org0d523ee2014-06-05 09:10:55 +0000234WebRtcVideoEncoderFactory2::~WebRtcVideoEncoderFactory2() {
235}
236
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000237std::vector<webrtc::VideoStream> WebRtcVideoEncoderFactory2::CreateVideoStreams(
238 const VideoCodec& codec,
239 const VideoOptions& options,
240 size_t num_streams) {
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000241 if (num_streams != 1) {
242 LOG(LS_ERROR) << "Unsupported number of streams: " << num_streams;
243 return std::vector<webrtc::VideoStream>();
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000244 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000245
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000246 webrtc::VideoStream stream;
247 stream.width = codec.width;
248 stream.height = codec.height;
249 stream.max_framerate =
250 codec.framerate != 0 ? codec.framerate : kDefaultFramerate;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000251
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000252 int min_bitrate = kMinVideoBitrate;
253 codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
254 int max_bitrate = kMaxVideoBitrate;
255 codec.GetParam(kCodecParamMaxBitrate, &max_bitrate);
256 stream.min_bitrate_bps = min_bitrate * 1000;
257 stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate * 1000;
258
buildbot@webrtc.org933d88a2014-09-18 20:23:05 +0000259 int max_qp = kDefaultQpMax;
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000260 codec.GetParam(kCodecParamMaxQuantization, &max_qp);
261 stream.max_qp = max_qp;
262 std::vector<webrtc::VideoStream> streams;
263 streams.push_back(stream);
264 return streams;
265}
266
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000267void* WebRtcVideoEncoderFactory2::CreateVideoEncoderSettings(
268 const VideoCodec& codec,
269 const VideoOptions& options) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000270 if (CodecNameMatches(codec.name, kVp8CodecName)) {
pbos@webrtc.org6cd6ba82014-09-18 12:42:28 +0000271 webrtc::VideoCodecVP8* settings = new webrtc::VideoCodecVP8(
272 webrtc::VideoEncoder::GetDefaultVp8Settings());
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000273 options.video_noise_reduction.Get(&settings->denoisingOn);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000274 return settings;
275 }
276 return NULL;
277}
278
279void WebRtcVideoEncoderFactory2::DestroyVideoEncoderSettings(
280 const VideoCodec& codec,
281 void* encoder_settings) {
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000282 if (encoder_settings == NULL) {
283 return;
284 }
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000285 if (CodecNameMatches(codec.name, kVp8CodecName)) {
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000286 delete reinterpret_cast<webrtc::VideoCodecVP8*>(encoder_settings);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000287 }
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000288}
289
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000290DefaultUnsignalledSsrcHandler::DefaultUnsignalledSsrcHandler()
291 : default_recv_ssrc_(0), default_renderer_(NULL) {}
292
293UnsignalledSsrcHandler::Action DefaultUnsignalledSsrcHandler::OnUnsignalledSsrc(
294 VideoMediaChannel* channel,
295 uint32_t ssrc) {
296 if (default_recv_ssrc_ != 0) { // Already one default stream.
297 LOG(LS_WARNING) << "Unknown SSRC, but default receive stream already set.";
298 return kDropPacket;
299 }
300
301 StreamParams sp;
302 sp.ssrcs.push_back(ssrc);
303 LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << ".";
304 if (!channel->AddRecvStream(sp)) {
305 LOG(LS_WARNING) << "Could not create default receive stream.";
306 }
307
308 channel->SetRenderer(ssrc, default_renderer_);
309 default_recv_ssrc_ = ssrc;
310 return kDeliverPacket;
311}
312
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000313WebRtcCallFactory::~WebRtcCallFactory() {
314}
315webrtc::Call* WebRtcCallFactory::CreateCall(
316 const webrtc::Call::Config& config) {
317 return webrtc::Call::Create(config);
318}
319
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +0000320VideoRenderer* DefaultUnsignalledSsrcHandler::GetDefaultRenderer() const {
321 return default_renderer_;
322}
323
324void DefaultUnsignalledSsrcHandler::SetDefaultRenderer(
325 VideoMediaChannel* channel,
326 VideoRenderer* renderer) {
327 default_renderer_ = renderer;
328 if (default_recv_ssrc_ != 0) {
329 channel->SetRenderer(default_recv_ssrc_, default_renderer_);
330 }
331}
332
pbos@webrtc.org97fdeb82014-08-22 10:36:23 +0000333WebRtcVideoEngine2::WebRtcVideoEngine2()
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000334 : worker_thread_(NULL),
335 voice_engine_(NULL),
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000336 default_codec_format_(kDefaultVideoCodecPref.width,
337 kDefaultVideoCodecPref.height,
338 FPS_TO_INTERVAL(kDefaultFramerate),
339 FOURCC_ANY),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000340 initialized_(false),
341 cpu_monitor_(new rtc::CpuMonitor(NULL)),
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000342 call_factory_(&default_call_factory_),
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000343 external_decoder_factory_(NULL),
344 external_encoder_factory_(NULL) {
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000345 LOG(LS_INFO) << "WebRtcVideoEngine2::WebRtcVideoEngine2()";
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000346 video_codecs_ = GetSupportedCodecs();
pbos@webrtc.org587ef602014-06-16 17:32:02 +0000347 rtp_header_extensions_.push_back(
348 RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension,
349 kRtpTimestampOffsetHeaderExtensionDefaultId));
350 rtp_header_extensions_.push_back(
351 RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension,
352 kRtpAbsoluteSenderTimeHeaderExtensionDefaultId));
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000353}
354
355WebRtcVideoEngine2::~WebRtcVideoEngine2() {
356 LOG(LS_INFO) << "WebRtcVideoEngine2::~WebRtcVideoEngine2";
357
358 if (initialized_) {
359 Terminate();
360 }
361}
362
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000363void WebRtcVideoEngine2::SetCallFactory(WebRtcCallFactory* call_factory) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000364 assert(!initialized_);
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000365 call_factory_ = call_factory;
366}
367
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000368bool WebRtcVideoEngine2::Init(rtc::Thread* worker_thread) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000369 LOG(LS_INFO) << "WebRtcVideoEngine2::Init";
370 worker_thread_ = worker_thread;
371 ASSERT(worker_thread_ != NULL);
372
373 cpu_monitor_->set_thread(worker_thread_);
374 if (!cpu_monitor_->Start(kCpuMonitorPeriodMs)) {
375 LOG(LS_ERROR) << "Failed to start CPU monitor.";
376 cpu_monitor_.reset();
377 }
378
379 initialized_ = true;
380 return true;
381}
382
383void WebRtcVideoEngine2::Terminate() {
384 LOG(LS_INFO) << "WebRtcVideoEngine2::Terminate";
385
386 cpu_monitor_->Stop();
387
388 initialized_ = false;
389}
390
391int WebRtcVideoEngine2::GetCapabilities() { return VIDEO_RECV | VIDEO_SEND; }
392
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000393bool WebRtcVideoEngine2::SetDefaultEncoderConfig(
394 const VideoEncoderConfig& config) {
pbos@webrtc.org8fdeee62014-07-20 14:40:23 +0000395 const VideoCodec& codec = config.max_codec;
396 // TODO(pbos): Make use of external encoder factory.
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000397 if (!CodecIsInternallySupported(codec.name)) {
pbos@webrtc.org8fdeee62014-07-20 14:40:23 +0000398 LOG(LS_ERROR) << "SetDefaultEncoderConfig, codec not supported:"
399 << codec.ToString();
400 return false;
401 }
402
buildbot@webrtc.org992febb2014-09-05 16:39:08 +0000403 default_codec_format_ =
404 VideoFormat(codec.width,
405 codec.height,
406 VideoFormat::FpsToInterval(codec.framerate),
407 FOURCC_ANY);
pbos@webrtc.org8fdeee62014-07-20 14:40:23 +0000408 video_codecs_.clear();
409 video_codecs_.push_back(codec);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000410 return true;
411}
412
413VideoEncoderConfig WebRtcVideoEngine2::GetDefaultEncoderConfig() const {
414 return VideoEncoderConfig(DefaultVideoCodec());
415}
416
417WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel(
buildbot@webrtc.org1ecbe452014-10-14 20:29:28 +0000418 const VideoOptions& options,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000419 VoiceMediaChannel* voice_channel) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000420 assert(initialized_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000421 LOG(LS_INFO) << "CreateChannel: "
422 << (voice_channel != NULL ? "With" : "Without")
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000423 << " voice channel. Options: " << options.ToString();
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000424 WebRtcVideoChannel2* channel =
425 new WebRtcVideoChannel2(call_factory_,
426 voice_channel,
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000427 options,
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000428 external_encoder_factory_,
429 external_decoder_factory_,
430 GetVideoEncoderFactory());
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000431 if (!channel->Init()) {
432 delete channel;
433 return NULL;
434 }
pbos@webrtc.orge322a172014-06-13 11:47:28 +0000435 channel->SetRecvCodecs(video_codecs_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000436 return channel;
437}
438
439const std::vector<VideoCodec>& WebRtcVideoEngine2::codecs() const {
440 return video_codecs_;
441}
442
443const std::vector<RtpHeaderExtension>&
444WebRtcVideoEngine2::rtp_header_extensions() const {
445 return rtp_header_extensions_;
446}
447
448void WebRtcVideoEngine2::SetLogging(int min_sev, const char* filter) {
449 // TODO(pbos): Set up logging.
450 LOG(LS_VERBOSE) << "SetLogging: " << min_sev << '"' << filter << '"';
451 // if min_sev == -1, we keep the current log level.
452 if (min_sev < 0) {
453 assert(min_sev == -1);
454 return;
455 }
456}
457
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000458void WebRtcVideoEngine2::SetExternalDecoderFactory(
459 WebRtcVideoDecoderFactory* decoder_factory) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000460 assert(!initialized_);
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000461 external_decoder_factory_ = decoder_factory;
462}
463
464void WebRtcVideoEngine2::SetExternalEncoderFactory(
465 WebRtcVideoEncoderFactory* encoder_factory) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000466 assert(!initialized_);
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000467 external_encoder_factory_ = encoder_factory;
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000468
469 video_codecs_ = GetSupportedCodecs();
pbos@webrtc.org0a2087a2014-09-23 09:40:22 +0000470}
471
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000472bool WebRtcVideoEngine2::EnableTimedRender() {
473 // TODO(pbos): Figure out whether this can be removed.
474 return true;
475}
476
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000477// Checks to see whether we comprehend and could receive a particular codec
478bool WebRtcVideoEngine2::FindCodec(const VideoCodec& in) {
479 // TODO(pbos): Probe encoder factory to figure out that the codec is supported
480 // if supported by the encoder factory. Add a corresponding test that fails
481 // with this code (that doesn't ask the factory).
pbos@webrtc.org8fdeee62014-07-20 14:40:23 +0000482 for (size_t j = 0; j < video_codecs_.size(); ++j) {
483 VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0);
484 if (codec.Matches(in)) {
485 return true;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000486 }
487 }
488 return false;
489}
490
491// Tells whether the |requested| codec can be transmitted or not. If it can be
492// transmitted |out| is set with the best settings supported. Aspect ratio will
493// be set as close to |current|'s as possible. If not set |requested|'s
494// dimensions will be used for aspect ratio matching.
495bool WebRtcVideoEngine2::CanSendCodec(const VideoCodec& requested,
496 const VideoCodec& current,
497 VideoCodec* out) {
498 assert(out != NULL);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000499
500 if (requested.width != requested.height &&
501 (requested.height == 0 || requested.width == 0)) {
502 // 0xn and nx0 are invalid resolutions.
503 return false;
504 }
505
506 VideoCodec matching_codec;
507 if (!FindFirstMatchingCodec(video_codecs_, requested, &matching_codec)) {
508 // Codec not supported.
509 return false;
510 }
511
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000512 out->id = requested.id;
513 out->name = requested.name;
514 out->preference = requested.preference;
515 out->params = requested.params;
516 out->framerate =
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000517 rtc::_min(requested.framerate, matching_codec.framerate);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000518 out->params = requested.params;
519 out->feedback_params = requested.feedback_params;
pbos@webrtc.org8fdeee62014-07-20 14:40:23 +0000520 out->width = requested.width;
521 out->height = requested.height;
522 if (requested.width == 0 && requested.height == 0) {
523 return true;
524 }
525
526 while (out->width > matching_codec.width) {
527 out->width /= 2;
528 out->height /= 2;
529 }
530
531 return out->width > 0 && out->height > 0;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000532}
533
534bool WebRtcVideoEngine2::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) {
535 if (initialized_) {
536 LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init";
537 return false;
538 }
539 voice_engine_ = voice_engine;
540 return true;
541}
542
543// Ignore spammy trace messages, mostly from the stats API when we haven't
544// gotten RTCP info yet from the remote side.
545bool WebRtcVideoEngine2::ShouldIgnoreTrace(const std::string& trace) {
546 static const char* const kTracesToIgnore[] = {NULL};
547 for (const char* const* p = kTracesToIgnore; *p; ++p) {
548 if (trace.find(*p) == 0) {
549 return true;
550 }
551 }
552 return false;
553}
554
buildbot@webrtc.orgd41eaeb2014-06-12 07:13:26 +0000555WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() {
556 return &default_video_encoder_factory_;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000557}
558
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000559std::vector<VideoCodec> WebRtcVideoEngine2::GetSupportedCodecs() const {
560 std::vector<VideoCodec> supported_codecs = DefaultVideoCodecs();
561
562 if (external_encoder_factory_ == NULL) {
563 return supported_codecs;
564 }
565
566 assert(external_encoder_factory_->codecs().size() <= kMaxExternalVideoCodecs);
567 const std::vector<WebRtcVideoEncoderFactory::VideoCodec>& codecs =
568 external_encoder_factory_->codecs();
569 for (size_t i = 0; i < codecs.size(); ++i) {
570 // Don't add internally-supported codecs twice.
571 if (CodecIsInternallySupported(codecs[i].name)) {
572 continue;
573 }
574
575 VideoCodec codec(kExternalVideoPayloadTypeBase + static_cast<int>(i),
576 codecs[i].name,
577 codecs[i].max_width,
578 codecs[i].max_height,
579 codecs[i].max_fps,
580 0);
581
582 AddDefaultFeedbackParams(&codec);
583 supported_codecs.push_back(codec);
584 }
585 return supported_codecs;
586}
587
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000588// Thin map between VideoFrame and an existing webrtc::I420VideoFrame
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000589// to avoid having to copy the rendered VideoFrame prematurely.
590// This implementation is only safe to use in a const context and should never
591// be written to.
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000592class WebRtcVideoRenderFrame : public VideoFrame {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000593 public:
594 explicit WebRtcVideoRenderFrame(const webrtc::I420VideoFrame* frame)
595 : frame_(frame) {}
596
597 virtual bool InitToBlack(int w,
598 int h,
599 size_t pixel_width,
600 size_t pixel_height,
601 int64 elapsed_time,
602 int64 time_stamp) OVERRIDE {
603 UNIMPLEMENTED;
604 return false;
605 }
606
607 virtual bool Reset(uint32 fourcc,
608 int w,
609 int h,
610 int dw,
611 int dh,
612 uint8* sample,
613 size_t sample_size,
614 size_t pixel_width,
615 size_t pixel_height,
616 int64 elapsed_time,
617 int64 time_stamp,
618 int rotation) OVERRIDE {
619 UNIMPLEMENTED;
620 return false;
621 }
622
623 virtual size_t GetWidth() const OVERRIDE {
624 return static_cast<size_t>(frame_->width());
625 }
626 virtual size_t GetHeight() const OVERRIDE {
627 return static_cast<size_t>(frame_->height());
628 }
629
630 virtual const uint8* GetYPlane() const OVERRIDE {
631 return frame_->buffer(webrtc::kYPlane);
632 }
633 virtual const uint8* GetUPlane() const OVERRIDE {
634 return frame_->buffer(webrtc::kUPlane);
635 }
636 virtual const uint8* GetVPlane() const OVERRIDE {
637 return frame_->buffer(webrtc::kVPlane);
638 }
639
640 virtual uint8* GetYPlane() OVERRIDE {
641 UNIMPLEMENTED;
642 return NULL;
643 }
644 virtual uint8* GetUPlane() OVERRIDE {
645 UNIMPLEMENTED;
646 return NULL;
647 }
648 virtual uint8* GetVPlane() OVERRIDE {
649 UNIMPLEMENTED;
650 return NULL;
651 }
652
653 virtual int32 GetYPitch() const OVERRIDE {
654 return frame_->stride(webrtc::kYPlane);
655 }
656 virtual int32 GetUPitch() const OVERRIDE {
657 return frame_->stride(webrtc::kUPlane);
658 }
659 virtual int32 GetVPitch() const OVERRIDE {
660 return frame_->stride(webrtc::kVPlane);
661 }
662
663 virtual void* GetNativeHandle() const OVERRIDE { return NULL; }
664
665 virtual size_t GetPixelWidth() const OVERRIDE { return 1; }
666 virtual size_t GetPixelHeight() const OVERRIDE { return 1; }
667
668 virtual int64 GetElapsedTime() const OVERRIDE {
669 // Convert millisecond render time to ns timestamp.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000670 return frame_->render_time_ms() * rtc::kNumNanosecsPerMillisec;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000671 }
672 virtual int64 GetTimeStamp() const OVERRIDE {
673 // Convert 90K rtp timestamp to ns timestamp.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000674 return (frame_->timestamp() / 90) * rtc::kNumNanosecsPerMillisec;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000675 }
676 virtual void SetElapsedTime(int64 elapsed_time) OVERRIDE { UNIMPLEMENTED; }
677 virtual void SetTimeStamp(int64 time_stamp) OVERRIDE { UNIMPLEMENTED; }
678
679 virtual int GetRotation() const OVERRIDE {
680 UNIMPLEMENTED;
681 return ROTATION_0;
682 }
683
684 virtual VideoFrame* Copy() const OVERRIDE {
685 UNIMPLEMENTED;
686 return NULL;
687 }
688
689 virtual bool MakeExclusive() OVERRIDE {
690 UNIMPLEMENTED;
691 return false;
692 }
693
694 virtual size_t CopyToBuffer(uint8* buffer, size_t size) const {
695 UNIMPLEMENTED;
696 return 0;
697 }
698
699 // TODO(fbarchard): Refactor into base class and share with LMI
700 virtual size_t ConvertToRgbBuffer(uint32 to_fourcc,
701 uint8* buffer,
702 size_t size,
703 int stride_rgb) const OVERRIDE {
704 size_t width = GetWidth();
705 size_t height = GetHeight();
706 size_t needed = (stride_rgb >= 0 ? stride_rgb : -stride_rgb) * height;
707 if (size < needed) {
708 LOG(LS_WARNING) << "RGB buffer is not large enough";
709 return needed;
710 }
711
712 if (libyuv::ConvertFromI420(GetYPlane(),
713 GetYPitch(),
714 GetUPlane(),
715 GetUPitch(),
716 GetVPlane(),
717 GetVPitch(),
718 buffer,
719 stride_rgb,
720 static_cast<int>(width),
721 static_cast<int>(height),
722 to_fourcc)) {
723 LOG(LS_ERROR) << "RGB type not supported: " << to_fourcc;
724 return 0; // 0 indicates error
725 }
726 return needed;
727 }
728
729 protected:
730 virtual VideoFrame* CreateEmptyFrame(int w,
731 int h,
732 size_t pixel_width,
733 size_t pixel_height,
734 int64 elapsed_time,
735 int64 time_stamp) const OVERRIDE {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000736 WebRtcVideoFrame* frame = new WebRtcVideoFrame();
737 frame->InitToBlack(
738 w, h, pixel_width, pixel_height, elapsed_time, time_stamp);
739 return frame;
740 }
741
742 private:
743 const webrtc::I420VideoFrame* const frame_;
744};
745
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000746WebRtcVideoChannel2::WebRtcVideoChannel2(
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000747 WebRtcCallFactory* call_factory,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000748 VoiceMediaChannel* voice_channel,
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000749 const VideoOptions& options,
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000750 WebRtcVideoEncoderFactory* external_encoder_factory,
751 WebRtcVideoDecoderFactory* external_decoder_factory,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000752 WebRtcVideoEncoderFactory2* encoder_factory)
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000753 : unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_),
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000754 external_encoder_factory_(external_encoder_factory),
755 external_decoder_factory_(external_decoder_factory),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +0000756 encoder_factory_(encoder_factory) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000757 // TODO(pbos): Connect the video and audio with |voice_channel|.
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000758 SetDefaultOptions();
759 options_.SetAll(options);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000760 webrtc::Call::Config config(this);
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000761 config.overuse_callback = this;
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000762
763 // Set start bitrate for the call. A default is provided by SetDefaultOptions.
764 int start_bitrate_kbps;
765 options_.video_start_bitrate.Get(&start_bitrate_kbps);
766 config.stream_start_bitrate_bps = start_bitrate_kbps * 1000;
767
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000768 call_.reset(call_factory->CreateCall(config));
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000769
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000770 rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc;
771 sending_ = false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000772 default_send_ssrc_ = 0;
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +0000773}
774
775void WebRtcVideoChannel2::SetDefaultOptions() {
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000776 options_.cpu_overuse_detection.Set(false);
pbos@webrtc.org5ff71ab2014-07-23 07:28:56 +0000777 options_.suspend_below_min_bitrate.Set(false);
pbos@webrtc.org42684be2014-10-03 11:25:45 +0000778 options_.use_payload_padding.Set(false);
779 options_.video_noise_reduction.Set(true);
pbos@webrtc.orgfa553ef2014-10-20 11:07:07 +0000780 options_.video_start_bitrate.Set(
781 webrtc::Call::Config::kDefaultStartBitrateBps / 1000);
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +0000782 options_.screencast_min_bitrate.Set(0);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000783}
784
785WebRtcVideoChannel2::~WebRtcVideoChannel2() {
786 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
787 send_streams_.begin();
788 it != send_streams_.end();
789 ++it) {
790 delete it->second;
791 }
792
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +0000793 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000794 receive_streams_.begin();
795 it != receive_streams_.end();
796 ++it) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000797 delete it->second;
798 }
799}
800
801bool WebRtcVideoChannel2::Init() { return true; }
802
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000803bool WebRtcVideoChannel2::SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000804 LOG(LS_INFO) << "SetRecvCodecs: " << CodecVectorToString(codecs);
805 if (!ValidateCodecFormats(codecs)) {
806 return false;
807 }
808
809 const std::vector<VideoCodecSettings> mapped_codecs = MapCodecs(codecs);
810 if (mapped_codecs.empty()) {
811 LOG(LS_ERROR) << "SetRecvCodecs called without video codec payloads.";
812 return false;
813 }
814
815 // TODO(pbos): Add a decoder factory which controls supported codecs.
816 // Blocked on webrtc:2854.
817 for (size_t i = 0; i < mapped_codecs.size(); ++i) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000818 if (!CodecNameMatches(mapped_codecs[i].codec.name, kVp8CodecName)) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000819 LOG(LS_ERROR) << "SetRecvCodecs called with unsupported codec: '"
820 << mapped_codecs[i].codec.name << "'";
821 return false;
822 }
823 }
824
825 recv_codecs_ = mapped_codecs;
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +0000826
pbos@webrtc.org575d1262014-10-08 14:48:08 +0000827 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +0000828 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
829 receive_streams_.begin();
830 it != receive_streams_.end();
831 ++it) {
832 it->second->SetRecvCodecs(recv_codecs_);
833 }
834
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000835 return true;
836}
837
838bool WebRtcVideoChannel2::SetSendCodecs(const std::vector<VideoCodec>& codecs) {
839 LOG(LS_INFO) << "SetSendCodecs: " << CodecVectorToString(codecs);
840 if (!ValidateCodecFormats(codecs)) {
841 return false;
842 }
843
844 const std::vector<VideoCodecSettings> supported_codecs =
845 FilterSupportedCodecs(MapCodecs(codecs));
846
847 if (supported_codecs.empty()) {
848 LOG(LS_ERROR) << "No video codecs supported by encoder factory.";
849 return false;
850 }
851
852 send_codec_.Set(supported_codecs.front());
853 LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString();
854
pbos@webrtc.org575d1262014-10-08 14:48:08 +0000855 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +0000856 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
857 send_streams_.begin();
858 it != send_streams_.end();
859 ++it) {
860 assert(it->second != NULL);
861 it->second->SetCodec(supported_codecs.front());
862 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000863
864 return true;
865}
866
867bool WebRtcVideoChannel2::GetSendCodec(VideoCodec* codec) {
868 VideoCodecSettings codec_settings;
869 if (!send_codec_.Get(&codec_settings)) {
870 LOG(LS_VERBOSE) << "GetSendCodec: No send codec set.";
871 return false;
872 }
873 *codec = codec_settings.codec;
874 return true;
875}
876
877bool WebRtcVideoChannel2::SetSendStreamFormat(uint32 ssrc,
878 const VideoFormat& format) {
879 LOG(LS_VERBOSE) << "SetSendStreamFormat:" << ssrc << " -> "
880 << format.ToString();
pbos@webrtc.org575d1262014-10-08 14:48:08 +0000881 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000882 if (send_streams_.find(ssrc) == send_streams_.end()) {
883 return false;
884 }
885 return send_streams_[ssrc]->SetVideoFormat(format);
886}
887
888bool WebRtcVideoChannel2::SetRender(bool render) {
889 // TODO(pbos): Implement. Or refactor away as it shouldn't be needed.
890 LOG(LS_VERBOSE) << "SetRender: " << (render ? "true" : "false");
891 return true;
892}
893
894bool WebRtcVideoChannel2::SetSend(bool send) {
895 LOG(LS_VERBOSE) << "SetSend: " << (send ? "true" : "false");
896 if (send && !send_codec_.IsSet()) {
897 LOG(LS_ERROR) << "SetSend(true) called before setting codec.";
898 return false;
899 }
900 if (send) {
901 StartAllSendStreams();
902 } else {
903 StopAllSendStreams();
904 }
905 sending_ = send;
906 return true;
907}
908
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000909bool WebRtcVideoChannel2::AddSendStream(const StreamParams& sp) {
910 LOG(LS_INFO) << "AddSendStream: " << sp.ToString();
911 if (sp.ssrcs.empty()) {
912 LOG(LS_ERROR) << "No SSRCs in stream parameters.";
913 return false;
914 }
915
916 uint32 ssrc = sp.first_ssrc();
917 assert(ssrc != 0);
918 // TODO(pbos): Make sure none of sp.ssrcs are used, not just the identifying
919 // ssrc.
pbos@webrtc.org575d1262014-10-08 14:48:08 +0000920 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000921 if (send_streams_.find(ssrc) != send_streams_.end()) {
922 LOG(LS_ERROR) << "Send stream with ssrc '" << ssrc << "' already exists.";
923 return false;
924 }
925
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +0000926 std::vector<uint32> primary_ssrcs;
927 sp.GetPrimarySsrcs(&primary_ssrcs);
928 std::vector<uint32> rtx_ssrcs;
929 sp.GetFidSsrcs(primary_ssrcs, &rtx_ssrcs);
930 if (!rtx_ssrcs.empty() && primary_ssrcs.size() != rtx_ssrcs.size()) {
931 LOG(LS_ERROR)
932 << "RTX SSRCs exist, but don't cover all SSRCs (unsupported): "
933 << sp.ToString();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000934 return false;
935 }
936
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000937 WebRtcVideoSendStream* stream =
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000938 new WebRtcVideoSendStream(call_.get(),
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +0000939 external_encoder_factory_,
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +0000940 encoder_factory_,
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +0000941 options_,
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +0000942 send_codec_,
943 sp,
944 send_rtp_extensions_);
945
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000946 send_streams_[ssrc] = stream;
947
948 if (rtcp_receiver_report_ssrc_ == kDefaultRtcpReceiverReportSsrc) {
949 rtcp_receiver_report_ssrc_ = ssrc;
950 }
951 if (default_send_ssrc_ == 0) {
952 default_send_ssrc_ = ssrc;
953 }
954 if (sending_) {
955 stream->Start();
956 }
957
958 return true;
959}
960
961bool WebRtcVideoChannel2::RemoveSendStream(uint32 ssrc) {
962 LOG(LS_INFO) << "RemoveSendStream: " << ssrc;
963
964 if (ssrc == 0) {
965 if (default_send_ssrc_ == 0) {
966 LOG(LS_ERROR) << "No default send stream active.";
967 return false;
968 }
969
970 LOG(LS_VERBOSE) << "Removing default stream: " << default_send_ssrc_;
971 ssrc = default_send_ssrc_;
972 }
973
pbos@webrtc.org575d1262014-10-08 14:48:08 +0000974 WebRtcVideoSendStream* removed_stream;
975 {
976 rtc::CritScope stream_lock(&stream_crit_);
977 std::map<uint32, WebRtcVideoSendStream*>::iterator it =
978 send_streams_.find(ssrc);
979 if (it == send_streams_.end()) {
980 return false;
981 }
982
983 removed_stream = it->second;
984 send_streams_.erase(it);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000985 }
986
pbos@webrtc.org575d1262014-10-08 14:48:08 +0000987 delete removed_stream;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +0000988
989 if (ssrc == default_send_ssrc_) {
990 default_send_ssrc_ = 0;
991 }
992
993 return true;
994}
995
996bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
997 LOG(LS_INFO) << "AddRecvStream: " << sp.ToString();
998 assert(sp.ssrcs.size() > 0);
999
1000 uint32 ssrc = sp.first_ssrc();
1001 assert(ssrc != 0); // TODO(pbos): Is this ever valid?
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001002
1003 // TODO(pbos): Check if any of the SSRCs overlap.
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001004 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001005 if (receive_streams_.find(ssrc) != receive_streams_.end()) {
1006 LOG(LS_ERROR) << "Receive stream for SSRC " << ssrc << "already exists.";
1007 return false;
1008 }
1009
pbos@webrtc.orgbd249bc2014-07-07 04:45:15 +00001010 webrtc::VideoReceiveStream::Config config;
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001011 ConfigureReceiverRtp(&config, sp);
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001012 receive_streams_[ssrc] = new WebRtcVideoReceiveStream(
1013 call_.get(), external_decoder_factory_, config, recv_codecs_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001014
1015 return true;
1016}
1017
1018void WebRtcVideoChannel2::ConfigureReceiverRtp(
1019 webrtc::VideoReceiveStream::Config* config,
1020 const StreamParams& sp) const {
1021 uint32 ssrc = sp.first_ssrc();
1022
1023 config->rtp.remote_ssrc = ssrc;
1024 config->rtp.local_ssrc = rtcp_receiver_report_ssrc_;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001025
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001026 config->rtp.extensions = recv_rtp_extensions_;
pbos@webrtc.org257e1302014-07-25 19:01:32 +00001027
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001028 // TODO(pbos): This protection is against setting the same local ssrc as
1029 // remote which is not permitted by the lower-level API. RTCP requires a
1030 // corresponding sender SSRC. Figure out what to do when we don't have
1031 // (receive-only) or know a good local SSRC.
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001032 if (config->rtp.remote_ssrc == config->rtp.local_ssrc) {
1033 if (config->rtp.local_ssrc != kDefaultRtcpReceiverReportSsrc) {
1034 config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001035 } else {
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001036 config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc + 1;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001037 }
1038 }
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001039
1040 for (size_t i = 0; i < recv_codecs_.size(); ++i) {
1041 if (recv_codecs_[i].codec.id == kDefaultVideoCodecPref.payload_type) {
1042 config->rtp.fec = recv_codecs_[i].fec;
1043 uint32 rtx_ssrc;
1044 if (recv_codecs_[i].rtx_payload_type != -1 &&
1045 sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
1046 config->rtp.rtx[kDefaultVideoCodecPref.payload_type].ssrc = rtx_ssrc;
1047 config->rtp.rtx[kDefaultVideoCodecPref.payload_type].payload_type =
1048 recv_codecs_[i].rtx_payload_type;
1049 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001050 break;
1051 }
1052 }
1053
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001054}
1055
1056bool WebRtcVideoChannel2::RemoveRecvStream(uint32 ssrc) {
1057 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc;
1058 if (ssrc == 0) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001059 LOG(LS_ERROR) << "RemoveRecvStream with 0 ssrc is not supported.";
1060 return false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001061 }
1062
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001063 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001064 std::map<uint32, WebRtcVideoReceiveStream*>::iterator stream =
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001065 receive_streams_.find(ssrc);
1066 if (stream == receive_streams_.end()) {
1067 LOG(LS_ERROR) << "Stream not found for ssrc: " << ssrc;
1068 return false;
1069 }
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001070 delete stream->second;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001071 receive_streams_.erase(stream);
1072
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001073 return true;
1074}
1075
1076bool WebRtcVideoChannel2::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
1077 LOG(LS_INFO) << "SetRenderer: ssrc:" << ssrc << " "
1078 << (renderer ? "(ptr)" : "NULL");
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001079 if (ssrc == 0) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001080 default_unsignalled_ssrc_handler_.SetDefaultRenderer(this, renderer);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001081 return true;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001082 }
1083
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001084 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001085 std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
1086 receive_streams_.find(ssrc);
1087 if (it == receive_streams_.end()) {
1088 return false;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001089 }
1090
1091 it->second->SetRenderer(renderer);
1092 return true;
1093}
1094
1095bool WebRtcVideoChannel2::GetRenderer(uint32 ssrc, VideoRenderer** renderer) {
1096 if (ssrc == 0) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001097 *renderer = default_unsignalled_ssrc_handler_.GetDefaultRenderer();
1098 return *renderer != NULL;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001099 }
1100
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001101 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001102 std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
1103 receive_streams_.find(ssrc);
1104 if (it == receive_streams_.end()) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001105 return false;
1106 }
1107 *renderer = it->second->GetRenderer();
1108 return true;
1109}
1110
1111bool WebRtcVideoChannel2::GetStats(const StatsOptions& options,
1112 VideoMediaInfo* info) {
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001113 info->Clear();
1114 FillSenderStats(info);
1115 FillReceiverStats(info);
1116 FillBandwidthEstimationStats(info);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001117 return true;
1118}
1119
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001120void WebRtcVideoChannel2::FillSenderStats(VideoMediaInfo* video_media_info) {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001121 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001122 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
1123 send_streams_.begin();
1124 it != send_streams_.end();
1125 ++it) {
1126 video_media_info->senders.push_back(it->second->GetVideoSenderInfo());
1127 }
1128}
1129
1130void WebRtcVideoChannel2::FillReceiverStats(VideoMediaInfo* video_media_info) {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001131 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001132 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
1133 receive_streams_.begin();
1134 it != receive_streams_.end();
1135 ++it) {
1136 video_media_info->receivers.push_back(it->second->GetVideoReceiverInfo());
1137 }
1138}
1139
1140void WebRtcVideoChannel2::FillBandwidthEstimationStats(
1141 VideoMediaInfo* video_media_info) {
1142 // TODO(pbos): Implement.
1143}
1144
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001145bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
1146 LOG(LS_INFO) << "SetCapturer: " << ssrc << " -> "
1147 << (capturer != NULL ? "(capturer)" : "NULL");
1148 assert(ssrc != 0);
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001149 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001150 if (send_streams_.find(ssrc) == send_streams_.end()) {
1151 LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
1152 return false;
1153 }
1154 return send_streams_[ssrc]->SetCapturer(capturer);
1155}
1156
1157bool WebRtcVideoChannel2::SendIntraFrame() {
1158 // TODO(pbos): Implement.
1159 LOG(LS_VERBOSE) << "SendIntraFrame().";
1160 return true;
1161}
1162
1163bool WebRtcVideoChannel2::RequestIntraFrame() {
1164 // TODO(pbos): Implement.
1165 LOG(LS_VERBOSE) << "SendIntraFrame().";
1166 return true;
1167}
1168
1169void WebRtcVideoChannel2::OnPacketReceived(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001170 rtc::Buffer* packet,
1171 const rtc::PacketTime& packet_time) {
pbos@webrtc.org4e545cc2014-05-14 13:58:13 +00001172 const webrtc::PacketReceiver::DeliveryStatus delivery_result =
1173 call_->Receiver()->DeliverPacket(
1174 reinterpret_cast<const uint8_t*>(packet->data()), packet->length());
1175 switch (delivery_result) {
1176 case webrtc::PacketReceiver::DELIVERY_OK:
1177 return;
1178 case webrtc::PacketReceiver::DELIVERY_PACKET_ERROR:
1179 return;
1180 case webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC:
1181 break;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001182 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001183
1184 uint32 ssrc = 0;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001185 if (!GetRtpSsrc(packet->data(), packet->length(), &ssrc)) {
1186 return;
1187 }
1188
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001189 // TODO(pbos): Make sure that the unsignalled SSRC uses the video payload.
1190 // Also figure out whether RTX needs to be handled.
1191 switch (unsignalled_ssrc_handler_->OnUnsignalledSsrc(this, ssrc)) {
1192 case UnsignalledSsrcHandler::kDropPacket:
1193 return;
1194 case UnsignalledSsrcHandler::kDeliverPacket:
1195 break;
1196 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001197
pbos@webrtc.org1e019d12014-05-16 11:38:45 +00001198 if (call_->Receiver()->DeliverPacket(
1199 reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) !=
1200 webrtc::PacketReceiver::DELIVERY_OK) {
pbos@webrtc.orgafb554f42014-08-12 23:17:13 +00001201 LOG(LS_WARNING) << "Failed to deliver RTP packet on re-delivery.";
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001202 return;
1203 }
1204}
1205
1206void WebRtcVideoChannel2::OnRtcpReceived(
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001207 rtc::Buffer* packet,
1208 const rtc::PacketTime& packet_time) {
pbos@webrtc.org1e019d12014-05-16 11:38:45 +00001209 if (call_->Receiver()->DeliverPacket(
1210 reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) !=
1211 webrtc::PacketReceiver::DELIVERY_OK) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001212 LOG(LS_WARNING) << "Failed to deliver RTCP packet.";
1213 }
1214}
1215
1216void WebRtcVideoChannel2::OnReadyToSend(bool ready) {
pbos@webrtc.org26c0c412014-09-03 16:17:12 +00001217 LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
1218 call_->SignalNetworkState(ready ? webrtc::Call::kNetworkUp
1219 : webrtc::Call::kNetworkDown);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001220}
1221
1222bool WebRtcVideoChannel2::MuteStream(uint32 ssrc, bool mute) {
1223 LOG(LS_VERBOSE) << "MuteStream: " << ssrc << " -> "
1224 << (mute ? "mute" : "unmute");
1225 assert(ssrc != 0);
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001226 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001227 if (send_streams_.find(ssrc) == send_streams_.end()) {
1228 LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc;
1229 return false;
1230 }
pbos@webrtc.orgef8bb8d2014-08-13 21:36:18 +00001231
1232 send_streams_[ssrc]->MuteStream(mute);
1233 return true;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001234}
1235
1236bool WebRtcVideoChannel2::SetRecvRtpHeaderExtensions(
1237 const std::vector<RtpHeaderExtension>& extensions) {
pbos@webrtc.org587ef602014-06-16 17:32:02 +00001238 LOG(LS_INFO) << "SetRecvRtpHeaderExtensions: "
1239 << RtpExtensionsToString(extensions);
pbos@webrtc.org3c107582014-07-20 15:27:35 +00001240 if (!ValidateRtpHeaderExtensionIds(extensions))
1241 return false;
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001242
pbos@webrtc.org3c107582014-07-20 15:27:35 +00001243 recv_rtp_extensions_ = FilterRtpExtensions(extensions);
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001244 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001245 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it =
1246 receive_streams_.begin();
1247 it != receive_streams_.end();
1248 ++it) {
1249 it->second->SetRtpExtensions(recv_rtp_extensions_);
1250 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001251 return true;
1252}
1253
1254bool WebRtcVideoChannel2::SetSendRtpHeaderExtensions(
1255 const std::vector<RtpHeaderExtension>& extensions) {
pbos@webrtc.org587ef602014-06-16 17:32:02 +00001256 LOG(LS_INFO) << "SetSendRtpHeaderExtensions: "
1257 << RtpExtensionsToString(extensions);
pbos@webrtc.org3c107582014-07-20 15:27:35 +00001258 if (!ValidateRtpHeaderExtensionIds(extensions))
1259 return false;
1260
1261 send_rtp_extensions_ = FilterRtpExtensions(extensions);
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001262 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001263 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
1264 send_streams_.begin();
1265 it != send_streams_.end();
1266 ++it) {
1267 it->second->SetRtpExtensions(send_rtp_extensions_);
1268 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001269 return true;
1270}
1271
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001272bool WebRtcVideoChannel2::SetMaxSendBandwidth(int bps) {
1273 // TODO(pbos): Implement.
1274 LOG(LS_VERBOSE) << "SetMaxSendBandwidth: " << bps;
1275 return true;
1276}
1277
1278bool WebRtcVideoChannel2::SetOptions(const VideoOptions& options) {
1279 LOG(LS_VERBOSE) << "SetOptions: " << options.ToString();
1280 options_.SetAll(options);
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001281 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001282 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
1283 send_streams_.begin();
1284 it != send_streams_.end();
1285 ++it) {
1286 it->second->SetOptions(options_);
1287 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001288 return true;
1289}
1290
1291void WebRtcVideoChannel2::SetInterface(NetworkInterface* iface) {
1292 MediaChannel::SetInterface(iface);
1293 // Set the RTP recv/send buffer to a bigger size
1294 MediaChannel::SetOption(NetworkInterface::ST_RTP,
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001295 rtc::Socket::OPT_RCVBUF,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001296 kVideoRtpBufferSize);
1297
buildbot@webrtc.orgae694ef2014-10-28 17:37:17 +00001298 // Speculative change to increase the outbound socket buffer size.
1299 // In b/15152257, we are seeing a significant number of packets discarded
1300 // due to lack of socket buffer space, although it's not yet clear what the
1301 // ideal value should be.
1302 MediaChannel::SetOption(NetworkInterface::ST_RTP,
1303 rtc::Socket::OPT_SNDBUF,
1304 kVideoRtpBufferSize);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001305}
1306
1307void WebRtcVideoChannel2::UpdateAspectRatio(int ratio_w, int ratio_h) {
1308 // TODO(pbos): Implement.
1309}
1310
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001311void WebRtcVideoChannel2::OnMessage(rtc::Message* msg) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001312 // Ignored.
1313}
1314
pbos@webrtc.org42684be2014-10-03 11:25:45 +00001315void WebRtcVideoChannel2::OnLoadUpdate(Load load) {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001316 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.org42684be2014-10-03 11:25:45 +00001317 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
1318 send_streams_.begin();
1319 it != send_streams_.end();
1320 ++it) {
1321 it->second->OnCpuResolutionRequest(load == kOveruse
1322 ? CoordinatedVideoAdapter::DOWNGRADE
1323 : CoordinatedVideoAdapter::UPGRADE);
1324 }
1325}
1326
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001327bool WebRtcVideoChannel2::SendRtp(const uint8_t* data, size_t len) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001328 rtc::Buffer packet(data, len, kMaxRtpPacketLen);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001329 return MediaChannel::SendPacket(&packet);
1330}
1331
1332bool WebRtcVideoChannel2::SendRtcp(const uint8_t* data, size_t len) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001333 rtc::Buffer packet(data, len, kMaxRtpPacketLen);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001334 return MediaChannel::SendRtcp(&packet);
1335}
1336
1337void WebRtcVideoChannel2::StartAllSendStreams() {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001338 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001339 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
1340 send_streams_.begin();
1341 it != send_streams_.end();
1342 ++it) {
1343 it->second->Start();
1344 }
1345}
1346
1347void WebRtcVideoChannel2::StopAllSendStreams() {
pbos@webrtc.org575d1262014-10-08 14:48:08 +00001348 rtc::CritScope stream_lock(&stream_crit_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001349 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it =
1350 send_streams_.begin();
1351 it != send_streams_.end();
1352 ++it) {
1353 it->second->Stop();
1354 }
1355}
1356
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001357WebRtcVideoChannel2::WebRtcVideoSendStream::VideoSendStreamParameters::
1358 VideoSendStreamParameters(
1359 const webrtc::VideoSendStream::Config& config,
1360 const VideoOptions& options,
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001361 const Settable<VideoCodecSettings>& codec_settings)
1362 : config(config), options(options), codec_settings(codec_settings) {
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001363}
1364
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001365WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
1366 webrtc::Call* call,
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001367 WebRtcVideoEncoderFactory* external_encoder_factory,
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001368 WebRtcVideoEncoderFactory2* encoder_factory,
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001369 const VideoOptions& options,
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001370 const Settable<VideoCodecSettings>& codec_settings,
1371 const StreamParams& sp,
1372 const std::vector<webrtc::RtpExtension>& rtp_extensions)
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001373 : call_(call),
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001374 external_encoder_factory_(external_encoder_factory),
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001375 encoder_factory_(encoder_factory),
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001376 stream_(NULL),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +00001377 parameters_(webrtc::VideoSendStream::Config(), options, codec_settings),
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001378 allocated_encoder_(NULL, webrtc::kVideoCodecUnknown, false),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +00001379 capturer_(NULL),
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001380 sending_(false),
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001381 muted_(false) {
1382 parameters_.config.rtp.max_packet_size = kVideoMtu;
1383
1384 sp.GetPrimarySsrcs(&parameters_.config.rtp.ssrcs);
1385 sp.GetFidSsrcs(parameters_.config.rtp.ssrcs,
1386 &parameters_.config.rtp.rtx.ssrcs);
1387 parameters_.config.rtp.c_name = sp.cname;
1388 parameters_.config.rtp.extensions = rtp_extensions;
1389
1390 VideoCodecSettings params;
1391 if (codec_settings.Get(&params)) {
1392 SetCodec(params);
1393 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001394}
1395
1396WebRtcVideoChannel2::WebRtcVideoSendStream::~WebRtcVideoSendStream() {
1397 DisconnectCapturer();
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001398 if (stream_ != NULL) {
1399 call_->DestroyVideoSendStream(stream_);
1400 }
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001401 DestroyVideoEncoder(&allocated_encoder_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001402}
1403
1404static void SetWebRtcFrameToBlack(webrtc::I420VideoFrame* video_frame) {
1405 assert(video_frame != NULL);
1406 memset(video_frame->buffer(webrtc::kYPlane),
1407 16,
1408 video_frame->allocated_size(webrtc::kYPlane));
1409 memset(video_frame->buffer(webrtc::kUPlane),
1410 128,
1411 video_frame->allocated_size(webrtc::kUPlane));
1412 memset(video_frame->buffer(webrtc::kVPlane),
1413 128,
1414 video_frame->allocated_size(webrtc::kVPlane));
1415}
1416
1417static void CreateBlackFrame(webrtc::I420VideoFrame* video_frame,
1418 int width,
1419 int height) {
1420 video_frame->CreateEmptyFrame(
1421 width, height, width, (width + 1) / 2, (width + 1) / 2);
1422 SetWebRtcFrameToBlack(video_frame);
1423}
1424
1425static void ConvertToI420VideoFrame(const VideoFrame& frame,
1426 webrtc::I420VideoFrame* i420_frame) {
1427 i420_frame->CreateFrame(
1428 static_cast<int>(frame.GetYPitch() * frame.GetHeight()),
1429 frame.GetYPlane(),
1430 static_cast<int>(frame.GetUPitch() * ((frame.GetHeight() + 1) / 2)),
1431 frame.GetUPlane(),
1432 static_cast<int>(frame.GetVPitch() * ((frame.GetHeight() + 1) / 2)),
1433 frame.GetVPlane(),
1434 static_cast<int>(frame.GetWidth()),
1435 static_cast<int>(frame.GetHeight()),
1436 static_cast<int>(frame.GetYPitch()),
1437 static_cast<int>(frame.GetUPitch()),
1438 static_cast<int>(frame.GetVPitch()));
1439}
1440
1441void WebRtcVideoChannel2::WebRtcVideoSendStream::InputFrame(
1442 VideoCapturer* capturer,
1443 const VideoFrame* frame) {
1444 LOG(LS_VERBOSE) << "InputFrame: " << frame->GetWidth() << "x"
1445 << frame->GetHeight();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001446 // Lock before copying, can be called concurrently when swapping input source.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001447 rtc::CritScope frame_cs(&frame_lock_);
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +00001448 ConvertToI420VideoFrame(*frame, &video_frame_);
1449
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001450 rtc::CritScope cs(&lock_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001451 if (stream_ == NULL) {
1452 LOG(LS_WARNING) << "Capturer inputting frames before send codecs are "
1453 "configured, dropping.";
1454 return;
1455 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001456 if (format_.width == 0) { // Dropping frames.
1457 assert(format_.height == 0);
1458 LOG(LS_VERBOSE) << "VideoFormat 0x0 set, Dropping frame.";
1459 return;
1460 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +00001461 if (muted_) {
1462 // Create a black frame to transmit instead.
1463 CreateBlackFrame(&video_frame_,
1464 static_cast<int>(frame->GetWidth()),
1465 static_cast<int>(frame->GetHeight()));
1466 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001467 // Reconfigure codec if necessary.
pbos@webrtc.orgc4175b92014-09-03 15:25:49 +00001468 SetDimensions(
1469 video_frame_.width(), video_frame_.height(), capturer->IsScreencast());
1470
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001471 LOG(LS_VERBOSE) << "SwapFrame: " << video_frame_.width() << "x"
1472 << video_frame_.height() << " -> (codec) "
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001473 << parameters_.encoder_config.streams.back().width << "x"
1474 << parameters_.encoder_config.streams.back().height;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001475 stream_->Input()->SwapFrame(&video_frame_);
1476}
1477
1478bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer(
1479 VideoCapturer* capturer) {
1480 if (!DisconnectCapturer() && capturer == NULL) {
1481 return false;
1482 }
1483
1484 {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001485 rtc::CritScope cs(&lock_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001486
pbos@webrtc.org9359cb32014-07-23 15:44:48 +00001487 if (capturer == NULL) {
1488 if (stream_ != NULL) {
1489 LOG(LS_VERBOSE) << "Disabling capturer, sending black frame.";
1490 webrtc::I420VideoFrame black_frame;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001491
pbos@webrtc.org9359cb32014-07-23 15:44:48 +00001492 int width = format_.width;
1493 int height = format_.height;
1494 int half_width = (width + 1) / 2;
1495 black_frame.CreateEmptyFrame(
1496 width, height, width, half_width, half_width);
1497 SetWebRtcFrameToBlack(&black_frame);
pbos@webrtc.orgc4175b92014-09-03 15:25:49 +00001498 SetDimensions(width, height, false);
pbos@webrtc.org9359cb32014-07-23 15:44:48 +00001499 stream_->Input()->SwapFrame(&black_frame);
1500 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001501
1502 capturer_ = NULL;
1503 return true;
1504 }
1505
1506 capturer_ = capturer;
1507 }
1508 // Lock cannot be held while connecting the capturer to prevent lock-order
1509 // violations.
1510 capturer->SignalVideoFrame.connect(this, &WebRtcVideoSendStream::InputFrame);
1511 return true;
1512}
1513
1514bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoFormat(
1515 const VideoFormat& format) {
1516 if ((format.width == 0 || format.height == 0) &&
1517 format.width != format.height) {
1518 LOG(LS_ERROR) << "Can't set VideoFormat, width or height is zero (but not "
1519 "both, 0x0 drops frames).";
1520 return false;
1521 }
1522
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001523 rtc::CritScope cs(&lock_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001524 if (format.width == 0 && format.height == 0) {
1525 LOG(LS_INFO)
1526 << "0x0 resolution selected. Captured frames will be dropped for ssrc: "
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001527 << parameters_.config.rtp.ssrcs[0] << ".";
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001528 } else {
1529 // TODO(pbos): Fix me, this only affects the last stream!
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001530 parameters_.encoder_config.streams.back().max_framerate =
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001531 VideoFormat::IntervalToFps(format.interval);
pbos@webrtc.orgc4175b92014-09-03 15:25:49 +00001532 SetDimensions(format.width, format.height, false);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001533 }
1534
1535 format_ = format;
1536 return true;
1537}
1538
pbos@webrtc.orgef8bb8d2014-08-13 21:36:18 +00001539void WebRtcVideoChannel2::WebRtcVideoSendStream::MuteStream(bool mute) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001540 rtc::CritScope cs(&lock_);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001541 muted_ = mute;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001542}
1543
1544bool WebRtcVideoChannel2::WebRtcVideoSendStream::DisconnectCapturer() {
pbos@webrtc.org963b9792014-10-07 14:27:27 +00001545 cricket::VideoCapturer* capturer;
1546 {
1547 rtc::CritScope cs(&lock_);
1548 if (capturer_ == NULL) {
1549 return false;
1550 }
1551 capturer = capturer_;
1552 capturer_ = NULL;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001553 }
pbos@webrtc.org963b9792014-10-07 14:27:27 +00001554 capturer->SignalVideoFrame.disconnect(this);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001555 return true;
1556}
1557
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001558void WebRtcVideoChannel2::WebRtcVideoSendStream::SetOptions(
1559 const VideoOptions& options) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001560 rtc::CritScope cs(&lock_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001561 VideoCodecSettings codec_settings;
1562 if (parameters_.codec_settings.Get(&codec_settings)) {
1563 SetCodecAndOptions(codec_settings, options);
1564 } else {
1565 parameters_.options = options;
1566 }
1567}
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001568
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001569void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodec(
1570 const VideoCodecSettings& codec_settings) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001571 rtc::CritScope cs(&lock_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001572 SetCodecAndOptions(codec_settings, parameters_.options);
1573}
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001574
1575webrtc::VideoCodecType CodecTypeFromName(const std::string& name) {
1576 if (CodecNameMatches(name, kVp8CodecName)) {
1577 return webrtc::kVideoCodecVP8;
1578 } else if (CodecNameMatches(name, kH264CodecName)) {
1579 return webrtc::kVideoCodecH264;
1580 }
1581 return webrtc::kVideoCodecUnknown;
1582}
1583
1584WebRtcVideoChannel2::WebRtcVideoSendStream::AllocatedEncoder
1585WebRtcVideoChannel2::WebRtcVideoSendStream::CreateVideoEncoder(
1586 const VideoCodec& codec) {
1587 webrtc::VideoCodecType type = CodecTypeFromName(codec.name);
1588
1589 // Do not re-create encoders of the same type.
1590 if (type == allocated_encoder_.type && allocated_encoder_.encoder != NULL) {
1591 return allocated_encoder_;
1592 }
1593
1594 if (external_encoder_factory_ != NULL) {
1595 webrtc::VideoEncoder* encoder =
1596 external_encoder_factory_->CreateVideoEncoder(type);
1597 if (encoder != NULL) {
1598 return AllocatedEncoder(encoder, type, true);
1599 }
1600 }
1601
1602 if (type == webrtc::kVideoCodecVP8) {
1603 return AllocatedEncoder(
1604 webrtc::VideoEncoder::Create(webrtc::VideoEncoder::kVp8), type, false);
1605 }
1606
1607 // This shouldn't happen, we should not be trying to create something we don't
1608 // support.
1609 assert(false);
1610 return AllocatedEncoder(NULL, webrtc::kVideoCodecUnknown, false);
1611}
1612
1613void WebRtcVideoChannel2::WebRtcVideoSendStream::DestroyVideoEncoder(
1614 AllocatedEncoder* encoder) {
1615 if (encoder->external) {
1616 external_encoder_factory_->DestroyVideoEncoder(encoder->encoder);
1617 } else {
1618 delete encoder->encoder;
1619 }
1620}
1621
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001622void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodecAndOptions(
1623 const VideoCodecSettings& codec_settings,
1624 const VideoOptions& options) {
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001625 std::vector<webrtc::VideoStream> video_streams =
1626 encoder_factory_->CreateVideoStreams(
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001627 codec_settings.codec, options, parameters_.config.rtp.ssrcs.size());
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001628 if (video_streams.empty()) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001629 return;
1630 }
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001631 parameters_.encoder_config.streams = video_streams;
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001632 format_ = VideoFormat(codec_settings.codec.width,
1633 codec_settings.codec.height,
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001634 VideoFormat::FpsToInterval(30),
1635 FOURCC_I420);
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001636
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001637 AllocatedEncoder new_encoder = CreateVideoEncoder(codec_settings.codec);
1638 parameters_.config.encoder_settings.encoder = new_encoder.encoder;
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001639 parameters_.config.encoder_settings.payload_name = codec_settings.codec.name;
1640 parameters_.config.encoder_settings.payload_type = codec_settings.codec.id;
1641 parameters_.config.rtp.fec = codec_settings.fec;
1642
1643 // Set RTX payload type if RTX is enabled.
1644 if (!parameters_.config.rtp.rtx.ssrcs.empty()) {
1645 parameters_.config.rtp.rtx.payload_type = codec_settings.rtx_payload_type;
pbos@webrtc.org543e5892014-07-23 07:01:31 +00001646
1647 options.use_payload_padding.Get(
1648 &parameters_.config.rtp.rtx.pad_with_redundant_payloads);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001649 }
1650
1651 if (IsNackEnabled(codec_settings.codec)) {
1652 parameters_.config.rtp.nack.rtp_history_ms = kNackHistoryMs;
1653 }
1654
pbos@webrtc.org5ff71ab2014-07-23 07:28:56 +00001655 options.suspend_below_min_bitrate.Get(
1656 &parameters_.config.suspend_below_min_bitrate);
1657
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001658 parameters_.codec_settings.Set(codec_settings);
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001659 parameters_.options = options;
pbos@webrtc.org543e5892014-07-23 07:01:31 +00001660
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001661 RecreateWebRtcStream();
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00001662 if (allocated_encoder_.encoder != new_encoder.encoder) {
1663 DestroyVideoEncoder(&allocated_encoder_);
1664 allocated_encoder_ = new_encoder;
1665 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001666}
1667
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001668void WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpExtensions(
1669 const std::vector<webrtc::RtpExtension>& rtp_extensions) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001670 rtc::CritScope cs(&lock_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001671 parameters_.config.rtp.extensions = rtp_extensions;
1672 RecreateWebRtcStream();
1673}
1674
pbos@webrtc.orgc4175b92014-09-03 15:25:49 +00001675void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions(
1676 int width,
1677 int height,
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +00001678 bool is_screencast) {
1679 if (last_dimensions_.width == width && last_dimensions_.height == height &&
1680 last_dimensions_.is_screencast == is_screencast) {
1681 // Configured using the same parameters, do not reconfigure.
1682 return;
1683 }
1684
1685 last_dimensions_.width = width;
1686 last_dimensions_.height = height;
1687 last_dimensions_.is_screencast = is_screencast;
1688
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001689 assert(!parameters_.encoder_config.streams.empty());
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001690 LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height;
pbos@webrtc.orgc4175b92014-09-03 15:25:49 +00001691
1692 VideoCodecSettings codec_settings;
1693 parameters_.codec_settings.Get(&codec_settings);
1694 // Restrict dimensions according to codec max.
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +00001695 if (!is_screencast) {
pbos@webrtc.orgc4175b92014-09-03 15:25:49 +00001696 if (codec_settings.codec.width < width)
1697 width = codec_settings.codec.width;
1698 if (codec_settings.codec.height < height)
1699 height = codec_settings.codec.height;
1700 }
1701
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001702 webrtc::VideoEncoderConfig encoder_config = parameters_.encoder_config;
1703 encoder_config.encoder_specific_settings =
1704 encoder_factory_->CreateVideoEncoderSettings(codec_settings.codec,
1705 parameters_.options);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001706
pbos@webrtc.orgefc82c22014-10-27 13:58:00 +00001707 if (is_screencast) {
1708 int screencast_min_bitrate_kbps;
1709 parameters_.options.screencast_min_bitrate.Get(
1710 &screencast_min_bitrate_kbps);
1711 encoder_config.min_transmit_bitrate_bps =
1712 screencast_min_bitrate_kbps * 1000;
1713 encoder_config.content_type = webrtc::VideoEncoderConfig::kScreenshare;
1714 } else {
1715 encoder_config.min_transmit_bitrate_bps = 0;
1716 encoder_config.content_type = webrtc::VideoEncoderConfig::kRealtimeVideo;
1717 }
1718
pbos@webrtc.orgcddd17c2014-09-16 16:33:13 +00001719 VideoCodec codec = codec_settings.codec;
1720 codec.width = width;
1721 codec.height = height;
pbos@webrtc.orgcddd17c2014-09-16 16:33:13 +00001722
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001723 encoder_config.streams = encoder_factory_->CreateVideoStreams(
1724 codec, parameters_.options, parameters_.config.rtp.ssrcs.size());
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001725
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001726 bool stream_reconfigured = stream_->ReconfigureVideoEncoder(encoder_config);
1727
1728 encoder_factory_->DestroyVideoEncoderSettings(
1729 codec_settings.codec,
1730 encoder_config.encoder_specific_settings);
1731
1732 encoder_config.encoder_specific_settings = NULL;
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001733
1734 if (!stream_reconfigured) {
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001735 LOG(LS_WARNING) << "Failed to reconfigure video encoder for dimensions: "
1736 << width << "x" << height;
1737 return;
1738 }
pbos@webrtc.orgcddd17c2014-09-16 16:33:13 +00001739
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001740 parameters_.encoder_config = encoder_config;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001741}
1742
1743void WebRtcVideoChannel2::WebRtcVideoSendStream::Start() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001744 rtc::CritScope cs(&lock_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001745 assert(stream_ != NULL);
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001746 stream_->Start();
1747 sending_ = true;
1748}
1749
1750void WebRtcVideoChannel2::WebRtcVideoSendStream::Stop() {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001751 rtc::CritScope cs(&lock_);
pbos@webrtc.org5301b0f2014-07-17 08:51:46 +00001752 if (stream_ != NULL) {
1753 stream_->Stop();
1754 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001755 sending_ = false;
1756}
1757
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001758VideoSenderInfo
1759WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() {
1760 VideoSenderInfo info;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001761 rtc::CritScope cs(&lock_);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001762 for (size_t i = 0; i < parameters_.config.rtp.ssrcs.size(); ++i) {
1763 info.add_ssrc(parameters_.config.rtp.ssrcs[i]);
1764 }
1765
pbos@webrtc.orgc3d2bd22014-08-12 20:55:10 +00001766 if (stream_ == NULL) {
1767 return info;
1768 }
1769
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001770 webrtc::VideoSendStream::Stats stats = stream_->GetStats();
1771 info.framerate_input = stats.input_frame_rate;
1772 info.framerate_sent = stats.encode_frame_rate;
1773
1774 for (std::map<uint32_t, webrtc::StreamStats>::iterator it =
1775 stats.substreams.begin();
1776 it != stats.substreams.end();
1777 ++it) {
1778 // TODO(pbos): Wire up additional stats, such as padding bytes.
1779 webrtc::StreamStats stream_stats = it->second;
1780 info.bytes_sent += stream_stats.rtp_stats.bytes +
1781 stream_stats.rtp_stats.header_bytes +
1782 stream_stats.rtp_stats.padding_bytes;
1783 info.packets_sent += stream_stats.rtp_stats.packets;
1784 info.packets_lost += stream_stats.rtcp_stats.cumulative_lost;
1785 }
1786
1787 if (!stats.substreams.empty()) {
1788 // TODO(pbos): Report fraction lost per SSRC.
1789 webrtc::StreamStats first_stream_stats = stats.substreams.begin()->second;
1790 info.fraction_lost =
1791 static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) /
1792 (1 << 8);
1793 }
1794
1795 if (capturer_ != NULL && !capturer_->IsMuted()) {
1796 VideoFormat last_captured_frame_format;
1797 capturer_->GetStats(&info.adapt_frame_drops,
1798 &info.effects_frame_drops,
1799 &info.capturer_frame_time,
1800 &last_captured_frame_format);
1801 info.input_frame_width = last_captured_frame_format.width;
1802 info.input_frame_height = last_captured_frame_format.height;
1803 info.send_frame_width =
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001804 static_cast<int>(parameters_.encoder_config.streams.front().width);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001805 info.send_frame_height =
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001806 static_cast<int>(parameters_.encoder_config.streams.front().height);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001807 }
1808
1809 // TODO(pbos): Support or remove the following stats.
1810 info.packets_cached = -1;
1811 info.rtt_ms = -1;
1812
1813 return info;
1814}
1815
pbos@webrtc.org42684be2014-10-03 11:25:45 +00001816void WebRtcVideoChannel2::WebRtcVideoSendStream::OnCpuResolutionRequest(
1817 CoordinatedVideoAdapter::AdaptRequest adapt_request) {
1818 rtc::CritScope cs(&lock_);
1819 bool adapt_cpu;
1820 parameters_.options.cpu_overuse_detection.Get(&adapt_cpu);
1821 if (!adapt_cpu) {
1822 return;
1823 }
1824 if (capturer_ == NULL || capturer_->video_adapter() == NULL) {
1825 return;
1826 }
1827
1828 capturer_->video_adapter()->OnCpuResolutionRequest(adapt_request);
1829}
1830
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001831void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
1832 if (stream_ != NULL) {
1833 call_->DestroyVideoSendStream(stream_);
1834 }
pbos@webrtc.org6ae48c62014-06-06 10:49:19 +00001835
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001836 VideoCodecSettings codec_settings;
1837 parameters_.codec_settings.Get(&codec_settings);
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001838 parameters_.encoder_config.encoder_specific_settings =
1839 encoder_factory_->CreateVideoEncoderSettings(codec_settings.codec,
1840 parameters_.options);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001841
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001842 stream_ = call_->CreateVideoSendStream(parameters_.config,
1843 parameters_.encoder_config);
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001844
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001845 encoder_factory_->DestroyVideoEncoderSettings(
1846 codec_settings.codec,
1847 parameters_.encoder_config.encoder_specific_settings);
1848
1849 parameters_.encoder_config.encoder_specific_settings = NULL;
pbos@webrtc.org6f48f1b2014-07-22 16:29:54 +00001850
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00001851 if (sending_) {
1852 stream_->Start();
1853 }
1854}
1855
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001856WebRtcVideoChannel2::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream(
1857 webrtc::Call* call,
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001858 WebRtcVideoDecoderFactory* external_decoder_factory,
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001859 const webrtc::VideoReceiveStream::Config& config,
1860 const std::vector<VideoCodecSettings>& recv_codecs)
1861 : call_(call),
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001862 stream_(NULL),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +00001863 config_(config),
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001864 external_decoder_factory_(external_decoder_factory),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +00001865 renderer_(NULL),
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001866 last_width_(-1),
pbos@webrtc.orgb648b9d2014-08-26 11:08:06 +00001867 last_height_(-1) {
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001868 config_.renderer = this;
1869 // SetRecvCodecs will also reset (start) the VideoReceiveStream.
1870 SetRecvCodecs(recv_codecs);
1871}
1872
1873WebRtcVideoChannel2::WebRtcVideoReceiveStream::~WebRtcVideoReceiveStream() {
1874 call_->DestroyVideoReceiveStream(stream_);
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001875 ClearDecoders();
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001876}
1877
1878void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRecvCodecs(
1879 const std::vector<VideoCodecSettings>& recv_codecs) {
1880 // TODO(pbos): Reconfigure RTX based on incoming recv_codecs.
1881 // TODO(pbos): Base receive codecs off recv_codecs_ and set up using a
1882 // DecoderFactory similar to send side. Pending webrtc:2854.
1883 // Also set up default codecs if there's nothing in recv_codecs_.
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001884 ClearDecoders();
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001885
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001886 AllocatedDecoder allocated_decoder(
1887 webrtc::VideoDecoder::Create(webrtc::VideoDecoder::kVp8), false);
1888 allocated_decoders_.push_back(allocated_decoder);
1889
1890 webrtc::VideoReceiveStream::Decoder decoder;
1891 decoder.decoder = allocated_decoder.decoder;
1892 decoder.payload_type = kDefaultVideoCodecPref.payload_type;
1893 decoder.payload_name = "VP8";
1894
1895 config_.decoders.push_back(decoder);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001896
1897 config_.rtp.fec = recv_codecs.front().fec;
1898
pbos@webrtc.org257e1302014-07-25 19:01:32 +00001899 config_.rtp.nack.rtp_history_ms =
1900 IsNackEnabled(recv_codecs.begin()->codec) ? kNackHistoryMs : 0;
1901 config_.rtp.remb = IsRembEnabled(recv_codecs.begin()->codec);
1902
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001903 RecreateWebRtcStream();
1904}
1905
1906void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRtpExtensions(
1907 const std::vector<webrtc::RtpExtension>& extensions) {
1908 config_.rtp.extensions = extensions;
1909 RecreateWebRtcStream();
1910}
1911
1912void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RecreateWebRtcStream() {
1913 if (stream_ != NULL) {
1914 call_->DestroyVideoReceiveStream(stream_);
1915 }
1916 stream_ = call_->CreateVideoReceiveStream(config_);
1917 stream_->Start();
1918}
1919
pbos@webrtc.org776e6f22014-10-29 15:28:39 +00001920void WebRtcVideoChannel2::WebRtcVideoReceiveStream::ClearDecoders() {
1921 for (size_t i = 0; i < allocated_decoders_.size(); ++i) {
1922 if (allocated_decoders_[i].external) {
1923 external_decoder_factory_->DestroyVideoDecoder(
1924 allocated_decoders_[i].decoder);
1925 } else {
1926 delete allocated_decoders_[i].decoder;
1927 }
1928 }
1929 allocated_decoders_.clear();
1930}
1931
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001932void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RenderFrame(
1933 const webrtc::I420VideoFrame& frame,
1934 int time_to_render_ms) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001935 rtc::CritScope crit(&renderer_lock_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001936 if (renderer_ == NULL) {
1937 LOG(LS_WARNING) << "VideoReceiveStream not connected to a VideoRenderer.";
1938 return;
1939 }
1940
1941 if (frame.width() != last_width_ || frame.height() != last_height_) {
1942 SetSize(frame.width(), frame.height());
1943 }
1944
1945 LOG(LS_VERBOSE) << "RenderFrame: (" << frame.width() << "x" << frame.height()
1946 << ")";
1947
1948 const WebRtcVideoRenderFrame render_frame(&frame);
1949 renderer_->RenderFrame(&render_frame);
1950}
1951
1952void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRenderer(
1953 cricket::VideoRenderer* renderer) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001954 rtc::CritScope crit(&renderer_lock_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001955 renderer_ = renderer;
1956 if (renderer_ != NULL && last_width_ != -1) {
1957 SetSize(last_width_, last_height_);
1958 }
1959}
1960
1961VideoRenderer* WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetRenderer() {
1962 // TODO(pbos): Remove GetRenderer and all uses of it, it's thread-unsafe by
1963 // design.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001964 rtc::CritScope crit(&renderer_lock_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001965 return renderer_;
1966}
1967
1968void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetSize(int width,
1969 int height) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001970 rtc::CritScope crit(&renderer_lock_);
pbos@webrtc.orgd1ea06b2014-07-18 09:35:58 +00001971 if (!renderer_->SetSize(width, height, 0)) {
1972 LOG(LS_ERROR) << "Could not set renderer size.";
1973 }
1974 last_width_ = width;
1975 last_height_ = height;
1976}
1977
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001978VideoReceiverInfo
1979WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo() {
1980 VideoReceiverInfo info;
1981 info.add_ssrc(config_.rtp.remote_ssrc);
1982 webrtc::VideoReceiveStream::Stats stats = stream_->GetStats();
1983 info.bytes_rcvd = stats.rtp_stats.bytes + stats.rtp_stats.header_bytes +
1984 stats.rtp_stats.padding_bytes;
1985 info.packets_rcvd = stats.rtp_stats.packets;
1986
1987 info.framerate_rcvd = stats.network_frame_rate;
1988 info.framerate_decoded = stats.decode_frame_rate;
1989 info.framerate_output = stats.render_frame_rate;
1990
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001991 rtc::CritScope frame_cs(&renderer_lock_);
pbos@webrtc.orge6f84ae2014-07-18 11:11:55 +00001992 info.frame_width = last_width_;
1993 info.frame_height = last_height_;
1994
1995 // TODO(pbos): Support or remove the following stats.
1996 info.packets_concealed = -1;
1997
1998 return info;
1999}
2000
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002001WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings()
2002 : rtx_payload_type(-1) {}
2003
2004std::vector<WebRtcVideoChannel2::VideoCodecSettings>
2005WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) {
2006 assert(!codecs.empty());
2007
2008 std::vector<VideoCodecSettings> video_codecs;
2009 std::map<int, bool> payload_used;
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002010 std::map<int, VideoCodec::CodecType> payload_codec_type;
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002011 std::map<int, int> rtx_mapping; // video payload type -> rtx payload type.
2012
2013 webrtc::FecConfig fec_settings;
2014
2015 for (size_t i = 0; i < codecs.size(); ++i) {
2016 const VideoCodec& in_codec = codecs[i];
2017 int payload_type = in_codec.id;
2018
2019 if (payload_used[payload_type]) {
2020 LOG(LS_ERROR) << "Payload type already registered: "
2021 << in_codec.ToString();
2022 return std::vector<VideoCodecSettings>();
2023 }
2024 payload_used[payload_type] = true;
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002025 payload_codec_type[payload_type] = in_codec.GetCodecType();
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002026
2027 switch (in_codec.GetCodecType()) {
2028 case VideoCodec::CODEC_RED: {
2029 // RED payload type, should not have duplicates.
2030 assert(fec_settings.red_payload_type == -1);
2031 fec_settings.red_payload_type = in_codec.id;
2032 continue;
2033 }
2034
2035 case VideoCodec::CODEC_ULPFEC: {
2036 // ULPFEC payload type, should not have duplicates.
2037 assert(fec_settings.ulpfec_payload_type == -1);
2038 fec_settings.ulpfec_payload_type = in_codec.id;
2039 continue;
2040 }
2041
2042 case VideoCodec::CODEC_RTX: {
2043 int associated_payload_type;
2044 if (!in_codec.GetParam(kCodecParamAssociatedPayloadType,
2045 &associated_payload_type)) {
2046 LOG(LS_ERROR) << "RTX codec without associated payload type: "
2047 << in_codec.ToString();
2048 return std::vector<VideoCodecSettings>();
2049 }
2050 rtx_mapping[associated_payload_type] = in_codec.id;
2051 continue;
2052 }
2053
2054 case VideoCodec::CODEC_VIDEO:
2055 break;
2056 }
2057
2058 video_codecs.push_back(VideoCodecSettings());
2059 video_codecs.back().codec = in_codec;
2060 }
2061
2062 // One of these codecs should have been a video codec. Only having FEC
2063 // parameters into this code is a logic error.
2064 assert(!video_codecs.empty());
2065
pbos@webrtc.orge322a172014-06-13 11:47:28 +00002066 for (std::map<int, int>::const_iterator it = rtx_mapping.begin();
2067 it != rtx_mapping.end();
2068 ++it) {
2069 if (!payload_used[it->first]) {
2070 LOG(LS_ERROR) << "RTX mapped to payload not in codec list.";
2071 return std::vector<VideoCodecSettings>();
2072 }
2073 if (payload_codec_type[it->first] != VideoCodec::CODEC_VIDEO) {
2074 LOG(LS_ERROR) << "RTX not mapped to regular video codec.";
2075 return std::vector<VideoCodecSettings>();
2076 }
2077 }
2078
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002079 // TODO(pbos): Write tests that figure out that I have not verified that RTX
2080 // codecs aren't mapped to bogus payloads.
2081 for (size_t i = 0; i < video_codecs.size(); ++i) {
2082 video_codecs[i].fec = fec_settings;
2083 if (rtx_mapping[video_codecs[i].codec.id] != 0) {
2084 video_codecs[i].rtx_payload_type = rtx_mapping[video_codecs[i].codec.id];
2085 }
2086 }
2087
2088 return video_codecs;
2089}
2090
2091std::vector<WebRtcVideoChannel2::VideoCodecSettings>
2092WebRtcVideoChannel2::FilterSupportedCodecs(
2093 const std::vector<WebRtcVideoChannel2::VideoCodecSettings>& mapped_codecs) {
2094 std::vector<VideoCodecSettings> supported_codecs;
2095 for (size_t i = 0; i < mapped_codecs.size(); ++i) {
pbos@webrtc.org7fe1e032014-10-14 04:25:33 +00002096 const VideoCodecSettings& codec = mapped_codecs[i];
2097 if (CodecIsInternallySupported(codec.codec.name)) {
2098 supported_codecs.push_back(codec);
2099 }
2100
2101 if (external_encoder_factory_ == NULL) {
2102 continue;
2103 }
2104 const std::vector<WebRtcVideoEncoderFactory::VideoCodec> external_codecs =
2105 external_encoder_factory_->codecs();
2106 for (size_t c = 0; c < external_codecs.size(); ++c) {
2107 if (CodecNameMatches(codec.codec.name, external_codecs[c].name)) {
2108 supported_codecs.push_back(codec);
2109 break;
2110 }
pbos@webrtc.orgb5a22b12014-05-13 11:07:01 +00002111 }
2112 }
2113 return supported_codecs;
2114}
2115
2116} // namespace cricket
2117
2118#endif // HAVE_WEBRTC_VIDEO