webrtcvideoengine2.cc revision cddd17c0f89cfaa9d2f21118ae90b45dae3b4aee
1/* 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 31#include <set> 32#include <string> 33 34#include "libyuv/convert_from.h" 35#include "talk/media/base/videocapturer.h" 36#include "talk/media/base/videorenderer.h" 37#include "talk/media/webrtc/constants.h" 38#include "talk/media/webrtc/webrtcvideocapturer.h" 39#include "talk/media/webrtc/webrtcvideoframe.h" 40#include "talk/media/webrtc/webrtcvoiceengine.h" 41#include "webrtc/base/buffer.h" 42#include "webrtc/base/logging.h" 43#include "webrtc/base/stringutils.h" 44#include "webrtc/call.h" 45// TODO(pbos): Move codecs out of modules (webrtc:3070). 46#include "webrtc/modules/video_coding/codecs/vp8/include/vp8.h" 47 48#define UNIMPLEMENTED \ 49 LOG(LS_ERROR) << "Call to unimplemented function " << __FUNCTION__; \ 50 ASSERT(false) 51 52namespace cricket { 53 54// This constant is really an on/off, lower-level configurable NACK history 55// duration hasn't been implemented. 56static const int kNackHistoryMs = 1000; 57 58static const int kDefaultRtcpReceiverReportSsrc = 1; 59 60struct VideoCodecPref { 61 int payload_type; 62 int width; 63 int height; 64 const char* name; 65 int rtx_payload_type; 66} kDefaultVideoCodecPref = {100, 640, 400, kVp8CodecName, 96}; 67 68VideoCodecPref kRedPref = {116, -1, -1, kRedCodecName, -1}; 69VideoCodecPref kUlpfecPref = {117, -1, -1, kUlpfecCodecName, -1}; 70 71static bool FindFirstMatchingCodec(const std::vector<VideoCodec>& codecs, 72 const VideoCodec& requested_codec, 73 VideoCodec* matching_codec) { 74 for (size_t i = 0; i < codecs.size(); ++i) { 75 if (requested_codec.Matches(codecs[i])) { 76 *matching_codec = codecs[i]; 77 return true; 78 } 79 } 80 return false; 81} 82 83static void AddDefaultFeedbackParams(VideoCodec* codec) { 84 const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir); 85 codec->AddFeedbackParam(kFir); 86 const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty); 87 codec->AddFeedbackParam(kNack); 88 const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli); 89 codec->AddFeedbackParam(kPli); 90 const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty); 91 codec->AddFeedbackParam(kRemb); 92} 93 94static bool IsNackEnabled(const VideoCodec& codec) { 95 return codec.HasFeedbackParam( 96 FeedbackParam(kRtcpFbParamNack, kParamValueEmpty)); 97} 98 99static bool IsRembEnabled(const VideoCodec& codec) { 100 return codec.HasFeedbackParam( 101 FeedbackParam(kRtcpFbParamRemb, kParamValueEmpty)); 102} 103 104static VideoCodec DefaultVideoCodec() { 105 VideoCodec default_codec(kDefaultVideoCodecPref.payload_type, 106 kDefaultVideoCodecPref.name, 107 kDefaultVideoCodecPref.width, 108 kDefaultVideoCodecPref.height, 109 kDefaultFramerate, 110 0); 111 AddDefaultFeedbackParams(&default_codec); 112 return default_codec; 113} 114 115static VideoCodec DefaultRedCodec() { 116 return VideoCodec(kRedPref.payload_type, kRedPref.name, 0, 0, 0, 0); 117} 118 119static VideoCodec DefaultUlpfecCodec() { 120 return VideoCodec(kUlpfecPref.payload_type, kUlpfecPref.name, 0, 0, 0, 0); 121} 122 123static std::vector<VideoCodec> DefaultVideoCodecs() { 124 std::vector<VideoCodec> codecs; 125 codecs.push_back(DefaultVideoCodec()); 126 codecs.push_back(DefaultRedCodec()); 127 codecs.push_back(DefaultUlpfecCodec()); 128 if (kDefaultVideoCodecPref.rtx_payload_type != -1) { 129 codecs.push_back( 130 VideoCodec::CreateRtxCodec(kDefaultVideoCodecPref.rtx_payload_type, 131 kDefaultVideoCodecPref.payload_type)); 132 } 133 return codecs; 134} 135 136static bool ValidateRtpHeaderExtensionIds( 137 const std::vector<RtpHeaderExtension>& extensions) { 138 std::set<int> extensions_used; 139 for (size_t i = 0; i < extensions.size(); ++i) { 140 if (extensions[i].id < 0 || extensions[i].id >= 15 || 141 !extensions_used.insert(extensions[i].id).second) { 142 LOG(LS_ERROR) << "RTP extensions are with incorrect or duplicate ids."; 143 return false; 144 } 145 } 146 return true; 147} 148 149static std::vector<webrtc::RtpExtension> FilterRtpExtensions( 150 const std::vector<RtpHeaderExtension>& extensions) { 151 std::vector<webrtc::RtpExtension> webrtc_extensions; 152 for (size_t i = 0; i < extensions.size(); ++i) { 153 // Unsupported extensions will be ignored. 154 if (webrtc::RtpExtension::IsSupported(extensions[i].uri)) { 155 webrtc_extensions.push_back(webrtc::RtpExtension( 156 extensions[i].uri, extensions[i].id)); 157 } else { 158 LOG(LS_WARNING) << "Unsupported RTP extension: " << extensions[i].uri; 159 } 160 } 161 return webrtc_extensions; 162} 163 164WebRtcVideoEncoderFactory2::~WebRtcVideoEncoderFactory2() { 165} 166 167std::vector<webrtc::VideoStream> WebRtcVideoEncoderFactory2::CreateVideoStreams( 168 const VideoCodec& codec, 169 const VideoOptions& options, 170 size_t num_streams) { 171 assert(SupportsCodec(codec)); 172 if (num_streams != 1) { 173 LOG(LS_ERROR) << "Unsupported number of streams: " << num_streams; 174 return std::vector<webrtc::VideoStream>(); 175 } 176 177 webrtc::VideoStream stream; 178 stream.width = codec.width; 179 stream.height = codec.height; 180 stream.max_framerate = 181 codec.framerate != 0 ? codec.framerate : kDefaultFramerate; 182 183 int min_bitrate = kMinVideoBitrate; 184 codec.GetParam(kCodecParamMinBitrate, &min_bitrate); 185 int max_bitrate = kMaxVideoBitrate; 186 codec.GetParam(kCodecParamMaxBitrate, &max_bitrate); 187 stream.min_bitrate_bps = min_bitrate * 1000; 188 stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate * 1000; 189 190 int max_qp = 56; 191 codec.GetParam(kCodecParamMaxQuantization, &max_qp); 192 stream.max_qp = max_qp; 193 std::vector<webrtc::VideoStream> streams; 194 streams.push_back(stream); 195 return streams; 196} 197 198webrtc::VideoEncoder* WebRtcVideoEncoderFactory2::CreateVideoEncoder( 199 const VideoCodec& codec, 200 const VideoOptions& options) { 201 assert(SupportsCodec(codec)); 202 if (_stricmp(codec.name.c_str(), kVp8CodecName) == 0) { 203 return webrtc::VP8Encoder::Create(); 204 } 205 // This shouldn't happen, we should be able to create encoders for all codecs 206 // we support. 207 assert(false); 208 return NULL; 209} 210 211void* WebRtcVideoEncoderFactory2::CreateVideoEncoderSettings( 212 const VideoCodec& codec, 213 const VideoOptions& options) { 214 assert(SupportsCodec(codec)); 215 if (_stricmp(codec.name.c_str(), kVp8CodecName) == 0) { 216 webrtc::VideoCodecVP8* settings = new webrtc::VideoCodecVP8(); 217 settings->resilience = webrtc::kResilientStream; 218 settings->numberOfTemporalLayers = 1; 219 options.video_noise_reduction.Get(&settings->denoisingOn); 220 settings->errorConcealmentOn = false; 221 settings->automaticResizeOn = false; 222 settings->frameDroppingOn = true; 223 settings->keyFrameInterval = 3000; 224 return settings; 225 } 226 return NULL; 227} 228 229void WebRtcVideoEncoderFactory2::DestroyVideoEncoderSettings( 230 const VideoCodec& codec, 231 void* encoder_settings) { 232 assert(SupportsCodec(codec)); 233 if (encoder_settings == NULL) { 234 return; 235 } 236 237 if (_stricmp(codec.name.c_str(), kVp8CodecName) == 0) { 238 delete reinterpret_cast<webrtc::VideoCodecVP8*>(encoder_settings); 239 return; 240 } 241 // We should be able to destroy all encoder settings we've allocated. 242 assert(false); 243} 244 245bool WebRtcVideoEncoderFactory2::SupportsCodec(const VideoCodec& codec) { 246 return _stricmp(codec.name.c_str(), kVp8CodecName) == 0; 247} 248 249DefaultUnsignalledSsrcHandler::DefaultUnsignalledSsrcHandler() 250 : default_recv_ssrc_(0), default_renderer_(NULL) {} 251 252UnsignalledSsrcHandler::Action DefaultUnsignalledSsrcHandler::OnUnsignalledSsrc( 253 VideoMediaChannel* channel, 254 uint32_t ssrc) { 255 if (default_recv_ssrc_ != 0) { // Already one default stream. 256 LOG(LS_WARNING) << "Unknown SSRC, but default receive stream already set."; 257 return kDropPacket; 258 } 259 260 StreamParams sp; 261 sp.ssrcs.push_back(ssrc); 262 LOG(LS_INFO) << "Creating default receive stream for SSRC=" << ssrc << "."; 263 if (!channel->AddRecvStream(sp)) { 264 LOG(LS_WARNING) << "Could not create default receive stream."; 265 } 266 267 channel->SetRenderer(ssrc, default_renderer_); 268 default_recv_ssrc_ = ssrc; 269 return kDeliverPacket; 270} 271 272VideoRenderer* DefaultUnsignalledSsrcHandler::GetDefaultRenderer() const { 273 return default_renderer_; 274} 275 276void DefaultUnsignalledSsrcHandler::SetDefaultRenderer( 277 VideoMediaChannel* channel, 278 VideoRenderer* renderer) { 279 default_renderer_ = renderer; 280 if (default_recv_ssrc_ != 0) { 281 channel->SetRenderer(default_recv_ssrc_, default_renderer_); 282 } 283} 284 285WebRtcVideoEngine2::WebRtcVideoEngine2() 286 : worker_thread_(NULL), 287 voice_engine_(NULL), 288 video_codecs_(DefaultVideoCodecs()), 289 default_codec_format_(kDefaultVideoCodecPref.width, 290 kDefaultVideoCodecPref.height, 291 FPS_TO_INTERVAL(kDefaultFramerate), 292 FOURCC_ANY), 293 initialized_(false), 294 cpu_monitor_(new rtc::CpuMonitor(NULL)), 295 channel_factory_(NULL) { 296 LOG(LS_INFO) << "WebRtcVideoEngine2::WebRtcVideoEngine2()"; 297 rtp_header_extensions_.push_back( 298 RtpHeaderExtension(kRtpTimestampOffsetHeaderExtension, 299 kRtpTimestampOffsetHeaderExtensionDefaultId)); 300 rtp_header_extensions_.push_back( 301 RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, 302 kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); 303} 304 305void WebRtcVideoEngine2::SetChannelFactory( 306 WebRtcVideoChannelFactory* channel_factory) { 307 channel_factory_ = channel_factory; 308} 309 310WebRtcVideoEngine2::~WebRtcVideoEngine2() { 311 LOG(LS_INFO) << "WebRtcVideoEngine2::~WebRtcVideoEngine2"; 312 313 if (initialized_) { 314 Terminate(); 315 } 316} 317 318bool WebRtcVideoEngine2::Init(rtc::Thread* worker_thread) { 319 LOG(LS_INFO) << "WebRtcVideoEngine2::Init"; 320 worker_thread_ = worker_thread; 321 ASSERT(worker_thread_ != NULL); 322 323 cpu_monitor_->set_thread(worker_thread_); 324 if (!cpu_monitor_->Start(kCpuMonitorPeriodMs)) { 325 LOG(LS_ERROR) << "Failed to start CPU monitor."; 326 cpu_monitor_.reset(); 327 } 328 329 initialized_ = true; 330 return true; 331} 332 333void WebRtcVideoEngine2::Terminate() { 334 LOG(LS_INFO) << "WebRtcVideoEngine2::Terminate"; 335 336 cpu_monitor_->Stop(); 337 338 initialized_ = false; 339} 340 341int WebRtcVideoEngine2::GetCapabilities() { return VIDEO_RECV | VIDEO_SEND; } 342 343bool WebRtcVideoEngine2::SetOptions(const VideoOptions& options) { 344 // TODO(pbos): Do we need this? This is a no-op in the existing 345 // WebRtcVideoEngine implementation. 346 LOG(LS_VERBOSE) << "SetOptions: " << options.ToString(); 347 // options_ = options; 348 return true; 349} 350 351bool WebRtcVideoEngine2::SetDefaultEncoderConfig( 352 const VideoEncoderConfig& config) { 353 const VideoCodec& codec = config.max_codec; 354 // TODO(pbos): Make use of external encoder factory. 355 if (!GetVideoEncoderFactory()->SupportsCodec(codec)) { 356 LOG(LS_ERROR) << "SetDefaultEncoderConfig, codec not supported:" 357 << codec.ToString(); 358 return false; 359 } 360 361 default_codec_format_ = 362 VideoFormat(codec.width, 363 codec.height, 364 VideoFormat::FpsToInterval(codec.framerate), 365 FOURCC_ANY); 366 video_codecs_.clear(); 367 video_codecs_.push_back(codec); 368 return true; 369} 370 371VideoEncoderConfig WebRtcVideoEngine2::GetDefaultEncoderConfig() const { 372 return VideoEncoderConfig(DefaultVideoCodec()); 373} 374 375WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel( 376 VoiceMediaChannel* voice_channel) { 377 LOG(LS_INFO) << "CreateChannel: " 378 << (voice_channel != NULL ? "With" : "Without") 379 << " voice channel."; 380 WebRtcVideoChannel2* channel = 381 channel_factory_ != NULL 382 ? channel_factory_->Create(this, voice_channel) 383 : new WebRtcVideoChannel2( 384 this, voice_channel, GetVideoEncoderFactory()); 385 if (!channel->Init()) { 386 delete channel; 387 return NULL; 388 } 389 channel->SetRecvCodecs(video_codecs_); 390 return channel; 391} 392 393const std::vector<VideoCodec>& WebRtcVideoEngine2::codecs() const { 394 return video_codecs_; 395} 396 397const std::vector<RtpHeaderExtension>& 398WebRtcVideoEngine2::rtp_header_extensions() const { 399 return rtp_header_extensions_; 400} 401 402void WebRtcVideoEngine2::SetLogging(int min_sev, const char* filter) { 403 // TODO(pbos): Set up logging. 404 LOG(LS_VERBOSE) << "SetLogging: " << min_sev << '"' << filter << '"'; 405 // if min_sev == -1, we keep the current log level. 406 if (min_sev < 0) { 407 assert(min_sev == -1); 408 return; 409 } 410} 411 412bool WebRtcVideoEngine2::EnableTimedRender() { 413 // TODO(pbos): Figure out whether this can be removed. 414 return true; 415} 416 417// Checks to see whether we comprehend and could receive a particular codec 418bool WebRtcVideoEngine2::FindCodec(const VideoCodec& in) { 419 // TODO(pbos): Probe encoder factory to figure out that the codec is supported 420 // if supported by the encoder factory. Add a corresponding test that fails 421 // with this code (that doesn't ask the factory). 422 for (size_t j = 0; j < video_codecs_.size(); ++j) { 423 VideoCodec codec(video_codecs_[j].id, video_codecs_[j].name, 0, 0, 0, 0); 424 if (codec.Matches(in)) { 425 return true; 426 } 427 } 428 return false; 429} 430 431// Tells whether the |requested| codec can be transmitted or not. If it can be 432// transmitted |out| is set with the best settings supported. Aspect ratio will 433// be set as close to |current|'s as possible. If not set |requested|'s 434// dimensions will be used for aspect ratio matching. 435bool WebRtcVideoEngine2::CanSendCodec(const VideoCodec& requested, 436 const VideoCodec& current, 437 VideoCodec* out) { 438 assert(out != NULL); 439 440 if (requested.width != requested.height && 441 (requested.height == 0 || requested.width == 0)) { 442 // 0xn and nx0 are invalid resolutions. 443 return false; 444 } 445 446 VideoCodec matching_codec; 447 if (!FindFirstMatchingCodec(video_codecs_, requested, &matching_codec)) { 448 // Codec not supported. 449 return false; 450 } 451 452 out->id = requested.id; 453 out->name = requested.name; 454 out->preference = requested.preference; 455 out->params = requested.params; 456 out->framerate = 457 rtc::_min(requested.framerate, matching_codec.framerate); 458 out->params = requested.params; 459 out->feedback_params = requested.feedback_params; 460 out->width = requested.width; 461 out->height = requested.height; 462 if (requested.width == 0 && requested.height == 0) { 463 return true; 464 } 465 466 while (out->width > matching_codec.width) { 467 out->width /= 2; 468 out->height /= 2; 469 } 470 471 return out->width > 0 && out->height > 0; 472} 473 474bool WebRtcVideoEngine2::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) { 475 if (initialized_) { 476 LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init"; 477 return false; 478 } 479 voice_engine_ = voice_engine; 480 return true; 481} 482 483// Ignore spammy trace messages, mostly from the stats API when we haven't 484// gotten RTCP info yet from the remote side. 485bool WebRtcVideoEngine2::ShouldIgnoreTrace(const std::string& trace) { 486 static const char* const kTracesToIgnore[] = {NULL}; 487 for (const char* const* p = kTracesToIgnore; *p; ++p) { 488 if (trace.find(*p) == 0) { 489 return true; 490 } 491 } 492 return false; 493} 494 495WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() { 496 return &default_video_encoder_factory_; 497} 498 499// Thin map between VideoFrame and an existing webrtc::I420VideoFrame 500// to avoid having to copy the rendered VideoFrame prematurely. 501// This implementation is only safe to use in a const context and should never 502// be written to. 503class WebRtcVideoRenderFrame : public VideoFrame { 504 public: 505 explicit WebRtcVideoRenderFrame(const webrtc::I420VideoFrame* frame) 506 : frame_(frame) {} 507 508 virtual bool InitToBlack(int w, 509 int h, 510 size_t pixel_width, 511 size_t pixel_height, 512 int64 elapsed_time, 513 int64 time_stamp) OVERRIDE { 514 UNIMPLEMENTED; 515 return false; 516 } 517 518 virtual bool Reset(uint32 fourcc, 519 int w, 520 int h, 521 int dw, 522 int dh, 523 uint8* sample, 524 size_t sample_size, 525 size_t pixel_width, 526 size_t pixel_height, 527 int64 elapsed_time, 528 int64 time_stamp, 529 int rotation) OVERRIDE { 530 UNIMPLEMENTED; 531 return false; 532 } 533 534 virtual size_t GetWidth() const OVERRIDE { 535 return static_cast<size_t>(frame_->width()); 536 } 537 virtual size_t GetHeight() const OVERRIDE { 538 return static_cast<size_t>(frame_->height()); 539 } 540 541 virtual const uint8* GetYPlane() const OVERRIDE { 542 return frame_->buffer(webrtc::kYPlane); 543 } 544 virtual const uint8* GetUPlane() const OVERRIDE { 545 return frame_->buffer(webrtc::kUPlane); 546 } 547 virtual const uint8* GetVPlane() const OVERRIDE { 548 return frame_->buffer(webrtc::kVPlane); 549 } 550 551 virtual uint8* GetYPlane() OVERRIDE { 552 UNIMPLEMENTED; 553 return NULL; 554 } 555 virtual uint8* GetUPlane() OVERRIDE { 556 UNIMPLEMENTED; 557 return NULL; 558 } 559 virtual uint8* GetVPlane() OVERRIDE { 560 UNIMPLEMENTED; 561 return NULL; 562 } 563 564 virtual int32 GetYPitch() const OVERRIDE { 565 return frame_->stride(webrtc::kYPlane); 566 } 567 virtual int32 GetUPitch() const OVERRIDE { 568 return frame_->stride(webrtc::kUPlane); 569 } 570 virtual int32 GetVPitch() const OVERRIDE { 571 return frame_->stride(webrtc::kVPlane); 572 } 573 574 virtual void* GetNativeHandle() const OVERRIDE { return NULL; } 575 576 virtual size_t GetPixelWidth() const OVERRIDE { return 1; } 577 virtual size_t GetPixelHeight() const OVERRIDE { return 1; } 578 579 virtual int64 GetElapsedTime() const OVERRIDE { 580 // Convert millisecond render time to ns timestamp. 581 return frame_->render_time_ms() * rtc::kNumNanosecsPerMillisec; 582 } 583 virtual int64 GetTimeStamp() const OVERRIDE { 584 // Convert 90K rtp timestamp to ns timestamp. 585 return (frame_->timestamp() / 90) * rtc::kNumNanosecsPerMillisec; 586 } 587 virtual void SetElapsedTime(int64 elapsed_time) OVERRIDE { UNIMPLEMENTED; } 588 virtual void SetTimeStamp(int64 time_stamp) OVERRIDE { UNIMPLEMENTED; } 589 590 virtual int GetRotation() const OVERRIDE { 591 UNIMPLEMENTED; 592 return ROTATION_0; 593 } 594 595 virtual VideoFrame* Copy() const OVERRIDE { 596 UNIMPLEMENTED; 597 return NULL; 598 } 599 600 virtual bool MakeExclusive() OVERRIDE { 601 UNIMPLEMENTED; 602 return false; 603 } 604 605 virtual size_t CopyToBuffer(uint8* buffer, size_t size) const { 606 UNIMPLEMENTED; 607 return 0; 608 } 609 610 // TODO(fbarchard): Refactor into base class and share with LMI 611 virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, 612 uint8* buffer, 613 size_t size, 614 int stride_rgb) const OVERRIDE { 615 size_t width = GetWidth(); 616 size_t height = GetHeight(); 617 size_t needed = (stride_rgb >= 0 ? stride_rgb : -stride_rgb) * height; 618 if (size < needed) { 619 LOG(LS_WARNING) << "RGB buffer is not large enough"; 620 return needed; 621 } 622 623 if (libyuv::ConvertFromI420(GetYPlane(), 624 GetYPitch(), 625 GetUPlane(), 626 GetUPitch(), 627 GetVPlane(), 628 GetVPitch(), 629 buffer, 630 stride_rgb, 631 static_cast<int>(width), 632 static_cast<int>(height), 633 to_fourcc)) { 634 LOG(LS_ERROR) << "RGB type not supported: " << to_fourcc; 635 return 0; // 0 indicates error 636 } 637 return needed; 638 } 639 640 protected: 641 virtual VideoFrame* CreateEmptyFrame(int w, 642 int h, 643 size_t pixel_width, 644 size_t pixel_height, 645 int64 elapsed_time, 646 int64 time_stamp) const OVERRIDE { 647 WebRtcVideoFrame* frame = new WebRtcVideoFrame(); 648 frame->InitToBlack( 649 w, h, pixel_width, pixel_height, elapsed_time, time_stamp); 650 return frame; 651 } 652 653 private: 654 const webrtc::I420VideoFrame* const frame_; 655}; 656 657WebRtcVideoChannel2::WebRtcVideoChannel2( 658 WebRtcVideoEngine2* engine, 659 VoiceMediaChannel* voice_channel, 660 WebRtcVideoEncoderFactory2* encoder_factory) 661 : unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_), 662 encoder_factory_(encoder_factory) { 663 // TODO(pbos): Connect the video and audio with |voice_channel|. 664 webrtc::Call::Config config(this); 665 Construct(webrtc::Call::Create(config), engine); 666} 667 668WebRtcVideoChannel2::WebRtcVideoChannel2( 669 webrtc::Call* call, 670 WebRtcVideoEngine2* engine, 671 WebRtcVideoEncoderFactory2* encoder_factory) 672 : unsignalled_ssrc_handler_(&default_unsignalled_ssrc_handler_), 673 encoder_factory_(encoder_factory) { 674 Construct(call, engine); 675} 676 677void WebRtcVideoChannel2::Construct(webrtc::Call* call, 678 WebRtcVideoEngine2* engine) { 679 rtcp_receiver_report_ssrc_ = kDefaultRtcpReceiverReportSsrc; 680 sending_ = false; 681 call_.reset(call); 682 default_send_ssrc_ = 0; 683 684 SetDefaultOptions(); 685} 686 687void WebRtcVideoChannel2::SetDefaultOptions() { 688 options_.video_noise_reduction.Set(true); 689 options_.use_payload_padding.Set(false); 690 options_.suspend_below_min_bitrate.Set(false); 691} 692 693WebRtcVideoChannel2::~WebRtcVideoChannel2() { 694 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 695 send_streams_.begin(); 696 it != send_streams_.end(); 697 ++it) { 698 delete it->second; 699 } 700 701 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it = 702 receive_streams_.begin(); 703 it != receive_streams_.end(); 704 ++it) { 705 delete it->second; 706 } 707} 708 709bool WebRtcVideoChannel2::Init() { return true; } 710 711namespace { 712 713static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) { 714 std::stringstream out; 715 out << '{'; 716 for (size_t i = 0; i < codecs.size(); ++i) { 717 out << codecs[i].ToString(); 718 if (i != codecs.size() - 1) { 719 out << ", "; 720 } 721 } 722 out << '}'; 723 return out.str(); 724} 725 726static bool ValidateCodecFormats(const std::vector<VideoCodec>& codecs) { 727 bool has_video = false; 728 for (size_t i = 0; i < codecs.size(); ++i) { 729 if (!codecs[i].ValidateCodecFormat()) { 730 return false; 731 } 732 if (codecs[i].GetCodecType() == VideoCodec::CODEC_VIDEO) { 733 has_video = true; 734 } 735 } 736 if (!has_video) { 737 LOG(LS_ERROR) << "Setting codecs without a video codec is invalid: " 738 << CodecVectorToString(codecs); 739 return false; 740 } 741 return true; 742} 743 744static std::string RtpExtensionsToString( 745 const std::vector<RtpHeaderExtension>& extensions) { 746 std::stringstream out; 747 out << '{'; 748 for (size_t i = 0; i < extensions.size(); ++i) { 749 out << "{" << extensions[i].uri << ": " << extensions[i].id << "}"; 750 if (i != extensions.size() - 1) { 751 out << ", "; 752 } 753 } 754 out << '}'; 755 return out.str(); 756} 757 758} // namespace 759 760bool WebRtcVideoChannel2::SetRecvCodecs(const std::vector<VideoCodec>& codecs) { 761 LOG(LS_INFO) << "SetRecvCodecs: " << CodecVectorToString(codecs); 762 if (!ValidateCodecFormats(codecs)) { 763 return false; 764 } 765 766 const std::vector<VideoCodecSettings> mapped_codecs = MapCodecs(codecs); 767 if (mapped_codecs.empty()) { 768 LOG(LS_ERROR) << "SetRecvCodecs called without video codec payloads."; 769 return false; 770 } 771 772 // TODO(pbos): Add a decoder factory which controls supported codecs. 773 // Blocked on webrtc:2854. 774 for (size_t i = 0; i < mapped_codecs.size(); ++i) { 775 if (_stricmp(mapped_codecs[i].codec.name.c_str(), kVp8CodecName) != 0) { 776 LOG(LS_ERROR) << "SetRecvCodecs called with unsupported codec: '" 777 << mapped_codecs[i].codec.name << "'"; 778 return false; 779 } 780 } 781 782 recv_codecs_ = mapped_codecs; 783 784 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it = 785 receive_streams_.begin(); 786 it != receive_streams_.end(); 787 ++it) { 788 it->second->SetRecvCodecs(recv_codecs_); 789 } 790 791 return true; 792} 793 794bool WebRtcVideoChannel2::SetSendCodecs(const std::vector<VideoCodec>& codecs) { 795 LOG(LS_INFO) << "SetSendCodecs: " << CodecVectorToString(codecs); 796 if (!ValidateCodecFormats(codecs)) { 797 return false; 798 } 799 800 const std::vector<VideoCodecSettings> supported_codecs = 801 FilterSupportedCodecs(MapCodecs(codecs)); 802 803 if (supported_codecs.empty()) { 804 LOG(LS_ERROR) << "No video codecs supported by encoder factory."; 805 return false; 806 } 807 808 send_codec_.Set(supported_codecs.front()); 809 LOG(LS_INFO) << "Using codec: " << supported_codecs.front().codec.ToString(); 810 811 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 812 send_streams_.begin(); 813 it != send_streams_.end(); 814 ++it) { 815 assert(it->second != NULL); 816 it->second->SetCodec(supported_codecs.front()); 817 } 818 819 return true; 820} 821 822bool WebRtcVideoChannel2::GetSendCodec(VideoCodec* codec) { 823 VideoCodecSettings codec_settings; 824 if (!send_codec_.Get(&codec_settings)) { 825 LOG(LS_VERBOSE) << "GetSendCodec: No send codec set."; 826 return false; 827 } 828 *codec = codec_settings.codec; 829 return true; 830} 831 832bool WebRtcVideoChannel2::SetSendStreamFormat(uint32 ssrc, 833 const VideoFormat& format) { 834 LOG(LS_VERBOSE) << "SetSendStreamFormat:" << ssrc << " -> " 835 << format.ToString(); 836 if (send_streams_.find(ssrc) == send_streams_.end()) { 837 return false; 838 } 839 return send_streams_[ssrc]->SetVideoFormat(format); 840} 841 842bool WebRtcVideoChannel2::SetRender(bool render) { 843 // TODO(pbos): Implement. Or refactor away as it shouldn't be needed. 844 LOG(LS_VERBOSE) << "SetRender: " << (render ? "true" : "false"); 845 return true; 846} 847 848bool WebRtcVideoChannel2::SetSend(bool send) { 849 LOG(LS_VERBOSE) << "SetSend: " << (send ? "true" : "false"); 850 if (send && !send_codec_.IsSet()) { 851 LOG(LS_ERROR) << "SetSend(true) called before setting codec."; 852 return false; 853 } 854 if (send) { 855 StartAllSendStreams(); 856 } else { 857 StopAllSendStreams(); 858 } 859 sending_ = send; 860 return true; 861} 862 863bool WebRtcVideoChannel2::AddSendStream(const StreamParams& sp) { 864 LOG(LS_INFO) << "AddSendStream: " << sp.ToString(); 865 if (sp.ssrcs.empty()) { 866 LOG(LS_ERROR) << "No SSRCs in stream parameters."; 867 return false; 868 } 869 870 uint32 ssrc = sp.first_ssrc(); 871 assert(ssrc != 0); 872 // TODO(pbos): Make sure none of sp.ssrcs are used, not just the identifying 873 // ssrc. 874 if (send_streams_.find(ssrc) != send_streams_.end()) { 875 LOG(LS_ERROR) << "Send stream with ssrc '" << ssrc << "' already exists."; 876 return false; 877 } 878 879 std::vector<uint32> primary_ssrcs; 880 sp.GetPrimarySsrcs(&primary_ssrcs); 881 std::vector<uint32> rtx_ssrcs; 882 sp.GetFidSsrcs(primary_ssrcs, &rtx_ssrcs); 883 if (!rtx_ssrcs.empty() && primary_ssrcs.size() != rtx_ssrcs.size()) { 884 LOG(LS_ERROR) 885 << "RTX SSRCs exist, but don't cover all SSRCs (unsupported): " 886 << sp.ToString(); 887 return false; 888 } 889 890 WebRtcVideoSendStream* stream = 891 new WebRtcVideoSendStream(call_.get(), 892 encoder_factory_, 893 options_, 894 send_codec_, 895 sp, 896 send_rtp_extensions_); 897 898 send_streams_[ssrc] = stream; 899 900 if (rtcp_receiver_report_ssrc_ == kDefaultRtcpReceiverReportSsrc) { 901 rtcp_receiver_report_ssrc_ = ssrc; 902 } 903 if (default_send_ssrc_ == 0) { 904 default_send_ssrc_ = ssrc; 905 } 906 if (sending_) { 907 stream->Start(); 908 } 909 910 return true; 911} 912 913bool WebRtcVideoChannel2::RemoveSendStream(uint32 ssrc) { 914 LOG(LS_INFO) << "RemoveSendStream: " << ssrc; 915 916 if (ssrc == 0) { 917 if (default_send_ssrc_ == 0) { 918 LOG(LS_ERROR) << "No default send stream active."; 919 return false; 920 } 921 922 LOG(LS_VERBOSE) << "Removing default stream: " << default_send_ssrc_; 923 ssrc = default_send_ssrc_; 924 } 925 926 std::map<uint32, WebRtcVideoSendStream*>::iterator it = 927 send_streams_.find(ssrc); 928 if (it == send_streams_.end()) { 929 return false; 930 } 931 932 delete it->second; 933 send_streams_.erase(it); 934 935 if (ssrc == default_send_ssrc_) { 936 default_send_ssrc_ = 0; 937 } 938 939 return true; 940} 941 942bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) { 943 LOG(LS_INFO) << "AddRecvStream: " << sp.ToString(); 944 assert(sp.ssrcs.size() > 0); 945 946 uint32 ssrc = sp.first_ssrc(); 947 assert(ssrc != 0); // TODO(pbos): Is this ever valid? 948 949 // TODO(pbos): Check if any of the SSRCs overlap. 950 if (receive_streams_.find(ssrc) != receive_streams_.end()) { 951 LOG(LS_ERROR) << "Receive stream for SSRC " << ssrc << "already exists."; 952 return false; 953 } 954 955 webrtc::VideoReceiveStream::Config config; 956 ConfigureReceiverRtp(&config, sp); 957 receive_streams_[ssrc] = 958 new WebRtcVideoReceiveStream(call_.get(), config, recv_codecs_); 959 960 return true; 961} 962 963void WebRtcVideoChannel2::ConfigureReceiverRtp( 964 webrtc::VideoReceiveStream::Config* config, 965 const StreamParams& sp) const { 966 uint32 ssrc = sp.first_ssrc(); 967 968 config->rtp.remote_ssrc = ssrc; 969 config->rtp.local_ssrc = rtcp_receiver_report_ssrc_; 970 971 config->rtp.extensions = recv_rtp_extensions_; 972 973 // TODO(pbos): This protection is against setting the same local ssrc as 974 // remote which is not permitted by the lower-level API. RTCP requires a 975 // corresponding sender SSRC. Figure out what to do when we don't have 976 // (receive-only) or know a good local SSRC. 977 if (config->rtp.remote_ssrc == config->rtp.local_ssrc) { 978 if (config->rtp.local_ssrc != kDefaultRtcpReceiverReportSsrc) { 979 config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc; 980 } else { 981 config->rtp.local_ssrc = kDefaultRtcpReceiverReportSsrc + 1; 982 } 983 } 984 985 for (size_t i = 0; i < recv_codecs_.size(); ++i) { 986 if (recv_codecs_[i].codec.id == kDefaultVideoCodecPref.payload_type) { 987 config->rtp.fec = recv_codecs_[i].fec; 988 uint32 rtx_ssrc; 989 if (recv_codecs_[i].rtx_payload_type != -1 && 990 sp.GetFidSsrc(ssrc, &rtx_ssrc)) { 991 config->rtp.rtx[kDefaultVideoCodecPref.payload_type].ssrc = rtx_ssrc; 992 config->rtp.rtx[kDefaultVideoCodecPref.payload_type].payload_type = 993 recv_codecs_[i].rtx_payload_type; 994 } 995 break; 996 } 997 } 998 999} 1000 1001bool WebRtcVideoChannel2::RemoveRecvStream(uint32 ssrc) { 1002 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc; 1003 if (ssrc == 0) { 1004 LOG(LS_ERROR) << "RemoveRecvStream with 0 ssrc is not supported."; 1005 return false; 1006 } 1007 1008 std::map<uint32, WebRtcVideoReceiveStream*>::iterator stream = 1009 receive_streams_.find(ssrc); 1010 if (stream == receive_streams_.end()) { 1011 LOG(LS_ERROR) << "Stream not found for ssrc: " << ssrc; 1012 return false; 1013 } 1014 delete stream->second; 1015 receive_streams_.erase(stream); 1016 1017 return true; 1018} 1019 1020bool WebRtcVideoChannel2::SetRenderer(uint32 ssrc, VideoRenderer* renderer) { 1021 LOG(LS_INFO) << "SetRenderer: ssrc:" << ssrc << " " 1022 << (renderer ? "(ptr)" : "NULL"); 1023 if (ssrc == 0) { 1024 default_unsignalled_ssrc_handler_.SetDefaultRenderer(this, renderer); 1025 return true; 1026 } 1027 1028 std::map<uint32, WebRtcVideoReceiveStream*>::iterator it = 1029 receive_streams_.find(ssrc); 1030 if (it == receive_streams_.end()) { 1031 return false; 1032 } 1033 1034 it->second->SetRenderer(renderer); 1035 return true; 1036} 1037 1038bool WebRtcVideoChannel2::GetRenderer(uint32 ssrc, VideoRenderer** renderer) { 1039 if (ssrc == 0) { 1040 *renderer = default_unsignalled_ssrc_handler_.GetDefaultRenderer(); 1041 return *renderer != NULL; 1042 } 1043 1044 std::map<uint32, WebRtcVideoReceiveStream*>::iterator it = 1045 receive_streams_.find(ssrc); 1046 if (it == receive_streams_.end()) { 1047 return false; 1048 } 1049 *renderer = it->second->GetRenderer(); 1050 return true; 1051} 1052 1053bool WebRtcVideoChannel2::GetStats(const StatsOptions& options, 1054 VideoMediaInfo* info) { 1055 info->Clear(); 1056 FillSenderStats(info); 1057 FillReceiverStats(info); 1058 FillBandwidthEstimationStats(info); 1059 return true; 1060} 1061 1062void WebRtcVideoChannel2::FillSenderStats(VideoMediaInfo* video_media_info) { 1063 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 1064 send_streams_.begin(); 1065 it != send_streams_.end(); 1066 ++it) { 1067 video_media_info->senders.push_back(it->second->GetVideoSenderInfo()); 1068 } 1069} 1070 1071void WebRtcVideoChannel2::FillReceiverStats(VideoMediaInfo* video_media_info) { 1072 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it = 1073 receive_streams_.begin(); 1074 it != receive_streams_.end(); 1075 ++it) { 1076 video_media_info->receivers.push_back(it->second->GetVideoReceiverInfo()); 1077 } 1078} 1079 1080void WebRtcVideoChannel2::FillBandwidthEstimationStats( 1081 VideoMediaInfo* video_media_info) { 1082 // TODO(pbos): Implement. 1083} 1084 1085bool WebRtcVideoChannel2::SetCapturer(uint32 ssrc, VideoCapturer* capturer) { 1086 LOG(LS_INFO) << "SetCapturer: " << ssrc << " -> " 1087 << (capturer != NULL ? "(capturer)" : "NULL"); 1088 assert(ssrc != 0); 1089 if (send_streams_.find(ssrc) == send_streams_.end()) { 1090 LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc; 1091 return false; 1092 } 1093 return send_streams_[ssrc]->SetCapturer(capturer); 1094} 1095 1096bool WebRtcVideoChannel2::SendIntraFrame() { 1097 // TODO(pbos): Implement. 1098 LOG(LS_VERBOSE) << "SendIntraFrame()."; 1099 return true; 1100} 1101 1102bool WebRtcVideoChannel2::RequestIntraFrame() { 1103 // TODO(pbos): Implement. 1104 LOG(LS_VERBOSE) << "SendIntraFrame()."; 1105 return true; 1106} 1107 1108void WebRtcVideoChannel2::OnPacketReceived( 1109 rtc::Buffer* packet, 1110 const rtc::PacketTime& packet_time) { 1111 const webrtc::PacketReceiver::DeliveryStatus delivery_result = 1112 call_->Receiver()->DeliverPacket( 1113 reinterpret_cast<const uint8_t*>(packet->data()), packet->length()); 1114 switch (delivery_result) { 1115 case webrtc::PacketReceiver::DELIVERY_OK: 1116 return; 1117 case webrtc::PacketReceiver::DELIVERY_PACKET_ERROR: 1118 return; 1119 case webrtc::PacketReceiver::DELIVERY_UNKNOWN_SSRC: 1120 break; 1121 } 1122 1123 uint32 ssrc = 0; 1124 if (!GetRtpSsrc(packet->data(), packet->length(), &ssrc)) { 1125 return; 1126 } 1127 1128 // TODO(pbos): Make sure that the unsignalled SSRC uses the video payload. 1129 // Also figure out whether RTX needs to be handled. 1130 switch (unsignalled_ssrc_handler_->OnUnsignalledSsrc(this, ssrc)) { 1131 case UnsignalledSsrcHandler::kDropPacket: 1132 return; 1133 case UnsignalledSsrcHandler::kDeliverPacket: 1134 break; 1135 } 1136 1137 if (call_->Receiver()->DeliverPacket( 1138 reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) != 1139 webrtc::PacketReceiver::DELIVERY_OK) { 1140 LOG(LS_WARNING) << "Failed to deliver RTP packet on re-delivery."; 1141 return; 1142 } 1143} 1144 1145void WebRtcVideoChannel2::OnRtcpReceived( 1146 rtc::Buffer* packet, 1147 const rtc::PacketTime& packet_time) { 1148 if (call_->Receiver()->DeliverPacket( 1149 reinterpret_cast<const uint8_t*>(packet->data()), packet->length()) != 1150 webrtc::PacketReceiver::DELIVERY_OK) { 1151 LOG(LS_WARNING) << "Failed to deliver RTCP packet."; 1152 } 1153} 1154 1155void WebRtcVideoChannel2::OnReadyToSend(bool ready) { 1156 LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready."); 1157 call_->SignalNetworkState(ready ? webrtc::Call::kNetworkUp 1158 : webrtc::Call::kNetworkDown); 1159} 1160 1161bool WebRtcVideoChannel2::MuteStream(uint32 ssrc, bool mute) { 1162 LOG(LS_VERBOSE) << "MuteStream: " << ssrc << " -> " 1163 << (mute ? "mute" : "unmute"); 1164 assert(ssrc != 0); 1165 if (send_streams_.find(ssrc) == send_streams_.end()) { 1166 LOG(LS_ERROR) << "No sending stream on ssrc " << ssrc; 1167 return false; 1168 } 1169 1170 send_streams_[ssrc]->MuteStream(mute); 1171 return true; 1172} 1173 1174bool WebRtcVideoChannel2::SetRecvRtpHeaderExtensions( 1175 const std::vector<RtpHeaderExtension>& extensions) { 1176 LOG(LS_INFO) << "SetRecvRtpHeaderExtensions: " 1177 << RtpExtensionsToString(extensions); 1178 if (!ValidateRtpHeaderExtensionIds(extensions)) 1179 return false; 1180 1181 recv_rtp_extensions_ = FilterRtpExtensions(extensions); 1182 for (std::map<uint32, WebRtcVideoReceiveStream*>::iterator it = 1183 receive_streams_.begin(); 1184 it != receive_streams_.end(); 1185 ++it) { 1186 it->second->SetRtpExtensions(recv_rtp_extensions_); 1187 } 1188 return true; 1189} 1190 1191bool WebRtcVideoChannel2::SetSendRtpHeaderExtensions( 1192 const std::vector<RtpHeaderExtension>& extensions) { 1193 LOG(LS_INFO) << "SetSendRtpHeaderExtensions: " 1194 << RtpExtensionsToString(extensions); 1195 if (!ValidateRtpHeaderExtensionIds(extensions)) 1196 return false; 1197 1198 send_rtp_extensions_ = FilterRtpExtensions(extensions); 1199 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 1200 send_streams_.begin(); 1201 it != send_streams_.end(); 1202 ++it) { 1203 it->second->SetRtpExtensions(send_rtp_extensions_); 1204 } 1205 return true; 1206} 1207 1208bool WebRtcVideoChannel2::SetStartSendBandwidth(int bps) { 1209 // TODO(pbos): Implement. 1210 LOG(LS_VERBOSE) << "SetStartSendBandwidth: " << bps; 1211 return true; 1212} 1213 1214bool WebRtcVideoChannel2::SetMaxSendBandwidth(int bps) { 1215 // TODO(pbos): Implement. 1216 LOG(LS_VERBOSE) << "SetMaxSendBandwidth: " << bps; 1217 return true; 1218} 1219 1220bool WebRtcVideoChannel2::SetOptions(const VideoOptions& options) { 1221 LOG(LS_VERBOSE) << "SetOptions: " << options.ToString(); 1222 options_.SetAll(options); 1223 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 1224 send_streams_.begin(); 1225 it != send_streams_.end(); 1226 ++it) { 1227 it->second->SetOptions(options_); 1228 } 1229 return true; 1230} 1231 1232void WebRtcVideoChannel2::SetInterface(NetworkInterface* iface) { 1233 MediaChannel::SetInterface(iface); 1234 // Set the RTP recv/send buffer to a bigger size 1235 MediaChannel::SetOption(NetworkInterface::ST_RTP, 1236 rtc::Socket::OPT_RCVBUF, 1237 kVideoRtpBufferSize); 1238 1239 // TODO(sriniv): Remove or re-enable this. 1240 // As part of b/8030474, send-buffer is size now controlled through 1241 // portallocator flags. 1242 // network_interface_->SetOption(NetworkInterface::ST_RTP, 1243 // rtc::Socket::OPT_SNDBUF, 1244 // kVideoRtpBufferSize); 1245} 1246 1247void WebRtcVideoChannel2::UpdateAspectRatio(int ratio_w, int ratio_h) { 1248 // TODO(pbos): Implement. 1249} 1250 1251void WebRtcVideoChannel2::OnMessage(rtc::Message* msg) { 1252 // Ignored. 1253} 1254 1255bool WebRtcVideoChannel2::SendRtp(const uint8_t* data, size_t len) { 1256 rtc::Buffer packet(data, len, kMaxRtpPacketLen); 1257 return MediaChannel::SendPacket(&packet); 1258} 1259 1260bool WebRtcVideoChannel2::SendRtcp(const uint8_t* data, size_t len) { 1261 rtc::Buffer packet(data, len, kMaxRtpPacketLen); 1262 return MediaChannel::SendRtcp(&packet); 1263} 1264 1265void WebRtcVideoChannel2::StartAllSendStreams() { 1266 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 1267 send_streams_.begin(); 1268 it != send_streams_.end(); 1269 ++it) { 1270 it->second->Start(); 1271 } 1272} 1273 1274void WebRtcVideoChannel2::StopAllSendStreams() { 1275 for (std::map<uint32, WebRtcVideoSendStream*>::iterator it = 1276 send_streams_.begin(); 1277 it != send_streams_.end(); 1278 ++it) { 1279 it->second->Stop(); 1280 } 1281} 1282 1283WebRtcVideoChannel2::WebRtcVideoSendStream::VideoSendStreamParameters:: 1284 VideoSendStreamParameters( 1285 const webrtc::VideoSendStream::Config& config, 1286 const VideoOptions& options, 1287 const Settable<VideoCodecSettings>& codec_settings) 1288 : config(config), options(options), codec_settings(codec_settings) { 1289} 1290 1291WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream( 1292 webrtc::Call* call, 1293 WebRtcVideoEncoderFactory2* encoder_factory, 1294 const VideoOptions& options, 1295 const Settable<VideoCodecSettings>& codec_settings, 1296 const StreamParams& sp, 1297 const std::vector<webrtc::RtpExtension>& rtp_extensions) 1298 : call_(call), 1299 encoder_factory_(encoder_factory), 1300 stream_(NULL), 1301 parameters_(webrtc::VideoSendStream::Config(), options, codec_settings), 1302 capturer_(NULL), 1303 sending_(false), 1304 muted_(false) { 1305 parameters_.config.rtp.max_packet_size = kVideoMtu; 1306 1307 sp.GetPrimarySsrcs(¶meters_.config.rtp.ssrcs); 1308 sp.GetFidSsrcs(parameters_.config.rtp.ssrcs, 1309 ¶meters_.config.rtp.rtx.ssrcs); 1310 parameters_.config.rtp.c_name = sp.cname; 1311 parameters_.config.rtp.extensions = rtp_extensions; 1312 1313 VideoCodecSettings params; 1314 if (codec_settings.Get(¶ms)) { 1315 SetCodec(params); 1316 } 1317} 1318 1319WebRtcVideoChannel2::WebRtcVideoSendStream::~WebRtcVideoSendStream() { 1320 DisconnectCapturer(); 1321 if (stream_ != NULL) { 1322 call_->DestroyVideoSendStream(stream_); 1323 } 1324 delete parameters_.config.encoder_settings.encoder; 1325} 1326 1327static void SetWebRtcFrameToBlack(webrtc::I420VideoFrame* video_frame) { 1328 assert(video_frame != NULL); 1329 memset(video_frame->buffer(webrtc::kYPlane), 1330 16, 1331 video_frame->allocated_size(webrtc::kYPlane)); 1332 memset(video_frame->buffer(webrtc::kUPlane), 1333 128, 1334 video_frame->allocated_size(webrtc::kUPlane)); 1335 memset(video_frame->buffer(webrtc::kVPlane), 1336 128, 1337 video_frame->allocated_size(webrtc::kVPlane)); 1338} 1339 1340static void CreateBlackFrame(webrtc::I420VideoFrame* video_frame, 1341 int width, 1342 int height) { 1343 video_frame->CreateEmptyFrame( 1344 width, height, width, (width + 1) / 2, (width + 1) / 2); 1345 SetWebRtcFrameToBlack(video_frame); 1346} 1347 1348static void ConvertToI420VideoFrame(const VideoFrame& frame, 1349 webrtc::I420VideoFrame* i420_frame) { 1350 i420_frame->CreateFrame( 1351 static_cast<int>(frame.GetYPitch() * frame.GetHeight()), 1352 frame.GetYPlane(), 1353 static_cast<int>(frame.GetUPitch() * ((frame.GetHeight() + 1) / 2)), 1354 frame.GetUPlane(), 1355 static_cast<int>(frame.GetVPitch() * ((frame.GetHeight() + 1) / 2)), 1356 frame.GetVPlane(), 1357 static_cast<int>(frame.GetWidth()), 1358 static_cast<int>(frame.GetHeight()), 1359 static_cast<int>(frame.GetYPitch()), 1360 static_cast<int>(frame.GetUPitch()), 1361 static_cast<int>(frame.GetVPitch())); 1362} 1363 1364void WebRtcVideoChannel2::WebRtcVideoSendStream::InputFrame( 1365 VideoCapturer* capturer, 1366 const VideoFrame* frame) { 1367 LOG(LS_VERBOSE) << "InputFrame: " << frame->GetWidth() << "x" 1368 << frame->GetHeight(); 1369 // Lock before copying, can be called concurrently when swapping input source. 1370 rtc::CritScope frame_cs(&frame_lock_); 1371 if (!muted_) { 1372 ConvertToI420VideoFrame(*frame, &video_frame_); 1373 } else { 1374 // Create a black frame to transmit instead. 1375 CreateBlackFrame(&video_frame_, 1376 static_cast<int>(frame->GetWidth()), 1377 static_cast<int>(frame->GetHeight())); 1378 } 1379 rtc::CritScope cs(&lock_); 1380 if (stream_ == NULL) { 1381 LOG(LS_WARNING) << "Capturer inputting frames before send codecs are " 1382 "configured, dropping."; 1383 return; 1384 } 1385 if (format_.width == 0) { // Dropping frames. 1386 assert(format_.height == 0); 1387 LOG(LS_VERBOSE) << "VideoFormat 0x0 set, Dropping frame."; 1388 return; 1389 } 1390 // Reconfigure codec if necessary. 1391 SetDimensions( 1392 video_frame_.width(), video_frame_.height(), capturer->IsScreencast()); 1393 1394 LOG(LS_VERBOSE) << "SwapFrame: " << video_frame_.width() << "x" 1395 << video_frame_.height() << " -> (codec) " 1396 << parameters_.video_streams.back().width << "x" 1397 << parameters_.video_streams.back().height; 1398 stream_->Input()->SwapFrame(&video_frame_); 1399} 1400 1401bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetCapturer( 1402 VideoCapturer* capturer) { 1403 if (!DisconnectCapturer() && capturer == NULL) { 1404 return false; 1405 } 1406 1407 { 1408 rtc::CritScope cs(&lock_); 1409 1410 if (capturer == NULL) { 1411 if (stream_ != NULL) { 1412 LOG(LS_VERBOSE) << "Disabling capturer, sending black frame."; 1413 webrtc::I420VideoFrame black_frame; 1414 1415 int width = format_.width; 1416 int height = format_.height; 1417 int half_width = (width + 1) / 2; 1418 black_frame.CreateEmptyFrame( 1419 width, height, width, half_width, half_width); 1420 SetWebRtcFrameToBlack(&black_frame); 1421 SetDimensions(width, height, false); 1422 stream_->Input()->SwapFrame(&black_frame); 1423 } 1424 1425 capturer_ = NULL; 1426 return true; 1427 } 1428 1429 capturer_ = capturer; 1430 } 1431 // Lock cannot be held while connecting the capturer to prevent lock-order 1432 // violations. 1433 capturer->SignalVideoFrame.connect(this, &WebRtcVideoSendStream::InputFrame); 1434 return true; 1435} 1436 1437bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoFormat( 1438 const VideoFormat& format) { 1439 if ((format.width == 0 || format.height == 0) && 1440 format.width != format.height) { 1441 LOG(LS_ERROR) << "Can't set VideoFormat, width or height is zero (but not " 1442 "both, 0x0 drops frames)."; 1443 return false; 1444 } 1445 1446 rtc::CritScope cs(&lock_); 1447 if (format.width == 0 && format.height == 0) { 1448 LOG(LS_INFO) 1449 << "0x0 resolution selected. Captured frames will be dropped for ssrc: " 1450 << parameters_.config.rtp.ssrcs[0] << "."; 1451 } else { 1452 // TODO(pbos): Fix me, this only affects the last stream! 1453 parameters_.video_streams.back().max_framerate = 1454 VideoFormat::IntervalToFps(format.interval); 1455 SetDimensions(format.width, format.height, false); 1456 } 1457 1458 format_ = format; 1459 return true; 1460} 1461 1462void WebRtcVideoChannel2::WebRtcVideoSendStream::MuteStream(bool mute) { 1463 rtc::CritScope cs(&lock_); 1464 muted_ = mute; 1465} 1466 1467bool WebRtcVideoChannel2::WebRtcVideoSendStream::DisconnectCapturer() { 1468 rtc::CritScope cs(&lock_); 1469 if (capturer_ == NULL) { 1470 return false; 1471 } 1472 capturer_->SignalVideoFrame.disconnect(this); 1473 capturer_ = NULL; 1474 return true; 1475} 1476 1477void WebRtcVideoChannel2::WebRtcVideoSendStream::SetOptions( 1478 const VideoOptions& options) { 1479 rtc::CritScope cs(&lock_); 1480 VideoCodecSettings codec_settings; 1481 if (parameters_.codec_settings.Get(&codec_settings)) { 1482 SetCodecAndOptions(codec_settings, options); 1483 } else { 1484 parameters_.options = options; 1485 } 1486} 1487void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodec( 1488 const VideoCodecSettings& codec_settings) { 1489 rtc::CritScope cs(&lock_); 1490 SetCodecAndOptions(codec_settings, parameters_.options); 1491} 1492void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodecAndOptions( 1493 const VideoCodecSettings& codec_settings, 1494 const VideoOptions& options) { 1495 std::vector<webrtc::VideoStream> video_streams = 1496 encoder_factory_->CreateVideoStreams( 1497 codec_settings.codec, options, parameters_.config.rtp.ssrcs.size()); 1498 if (video_streams.empty()) { 1499 return; 1500 } 1501 parameters_.video_streams = video_streams; 1502 format_ = VideoFormat(codec_settings.codec.width, 1503 codec_settings.codec.height, 1504 VideoFormat::FpsToInterval(30), 1505 FOURCC_I420); 1506 1507 webrtc::VideoEncoder* old_encoder = 1508 parameters_.config.encoder_settings.encoder; 1509 parameters_.config.encoder_settings.encoder = 1510 encoder_factory_->CreateVideoEncoder(codec_settings.codec, options); 1511 parameters_.config.encoder_settings.payload_name = codec_settings.codec.name; 1512 parameters_.config.encoder_settings.payload_type = codec_settings.codec.id; 1513 parameters_.config.rtp.fec = codec_settings.fec; 1514 1515 // Set RTX payload type if RTX is enabled. 1516 if (!parameters_.config.rtp.rtx.ssrcs.empty()) { 1517 parameters_.config.rtp.rtx.payload_type = codec_settings.rtx_payload_type; 1518 1519 options.use_payload_padding.Get( 1520 ¶meters_.config.rtp.rtx.pad_with_redundant_payloads); 1521 } 1522 1523 if (IsNackEnabled(codec_settings.codec)) { 1524 parameters_.config.rtp.nack.rtp_history_ms = kNackHistoryMs; 1525 } 1526 1527 options.suspend_below_min_bitrate.Get( 1528 ¶meters_.config.suspend_below_min_bitrate); 1529 1530 parameters_.codec_settings.Set(codec_settings); 1531 parameters_.options = options; 1532 1533 RecreateWebRtcStream(); 1534 delete old_encoder; 1535} 1536 1537void WebRtcVideoChannel2::WebRtcVideoSendStream::SetRtpExtensions( 1538 const std::vector<webrtc::RtpExtension>& rtp_extensions) { 1539 rtc::CritScope cs(&lock_); 1540 parameters_.config.rtp.extensions = rtp_extensions; 1541 RecreateWebRtcStream(); 1542} 1543 1544void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions( 1545 int width, 1546 int height, 1547 bool override_max) { 1548 assert(!parameters_.video_streams.empty()); 1549 LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height; 1550 1551 VideoCodecSettings codec_settings; 1552 parameters_.codec_settings.Get(&codec_settings); 1553 // Restrict dimensions according to codec max. 1554 if (!override_max) { 1555 if (codec_settings.codec.width < width) 1556 width = codec_settings.codec.width; 1557 if (codec_settings.codec.height < height) 1558 height = codec_settings.codec.height; 1559 } 1560 1561 if (parameters_.video_streams.back().width == width && 1562 parameters_.video_streams.back().height == height) { 1563 return; 1564 } 1565 1566 void* encoder_settings = encoder_factory_->CreateVideoEncoderSettings( 1567 codec_settings.codec, parameters_.options); 1568 1569 VideoCodec codec = codec_settings.codec; 1570 codec.width = width; 1571 codec.height = height; 1572 std::vector<webrtc::VideoStream> video_streams = 1573 encoder_factory_->CreateVideoStreams(codec, 1574 parameters_.options, 1575 parameters_.config.rtp.ssrcs.size()); 1576 1577 bool stream_reconfigured = stream_->ReconfigureVideoEncoder( 1578 video_streams, encoder_settings); 1579 1580 encoder_factory_->DestroyVideoEncoderSettings(codec_settings.codec, 1581 encoder_settings); 1582 1583 if (!stream_reconfigured) { 1584 LOG(LS_WARNING) << "Failed to reconfigure video encoder for dimensions: " 1585 << width << "x" << height; 1586 return; 1587 } 1588 1589 parameters_.video_streams = video_streams; 1590} 1591 1592void WebRtcVideoChannel2::WebRtcVideoSendStream::Start() { 1593 rtc::CritScope cs(&lock_); 1594 assert(stream_ != NULL); 1595 stream_->Start(); 1596 sending_ = true; 1597} 1598 1599void WebRtcVideoChannel2::WebRtcVideoSendStream::Stop() { 1600 rtc::CritScope cs(&lock_); 1601 if (stream_ != NULL) { 1602 stream_->Stop(); 1603 } 1604 sending_ = false; 1605} 1606 1607VideoSenderInfo 1608WebRtcVideoChannel2::WebRtcVideoSendStream::GetVideoSenderInfo() { 1609 VideoSenderInfo info; 1610 rtc::CritScope cs(&lock_); 1611 for (size_t i = 0; i < parameters_.config.rtp.ssrcs.size(); ++i) { 1612 info.add_ssrc(parameters_.config.rtp.ssrcs[i]); 1613 } 1614 1615 if (stream_ == NULL) { 1616 return info; 1617 } 1618 1619 webrtc::VideoSendStream::Stats stats = stream_->GetStats(); 1620 info.framerate_input = stats.input_frame_rate; 1621 info.framerate_sent = stats.encode_frame_rate; 1622 1623 for (std::map<uint32_t, webrtc::StreamStats>::iterator it = 1624 stats.substreams.begin(); 1625 it != stats.substreams.end(); 1626 ++it) { 1627 // TODO(pbos): Wire up additional stats, such as padding bytes. 1628 webrtc::StreamStats stream_stats = it->second; 1629 info.bytes_sent += stream_stats.rtp_stats.bytes + 1630 stream_stats.rtp_stats.header_bytes + 1631 stream_stats.rtp_stats.padding_bytes; 1632 info.packets_sent += stream_stats.rtp_stats.packets; 1633 info.packets_lost += stream_stats.rtcp_stats.cumulative_lost; 1634 } 1635 1636 if (!stats.substreams.empty()) { 1637 // TODO(pbos): Report fraction lost per SSRC. 1638 webrtc::StreamStats first_stream_stats = stats.substreams.begin()->second; 1639 info.fraction_lost = 1640 static_cast<float>(first_stream_stats.rtcp_stats.fraction_lost) / 1641 (1 << 8); 1642 } 1643 1644 if (capturer_ != NULL && !capturer_->IsMuted()) { 1645 VideoFormat last_captured_frame_format; 1646 capturer_->GetStats(&info.adapt_frame_drops, 1647 &info.effects_frame_drops, 1648 &info.capturer_frame_time, 1649 &last_captured_frame_format); 1650 info.input_frame_width = last_captured_frame_format.width; 1651 info.input_frame_height = last_captured_frame_format.height; 1652 info.send_frame_width = 1653 static_cast<int>(parameters_.video_streams.front().width); 1654 info.send_frame_height = 1655 static_cast<int>(parameters_.video_streams.front().height); 1656 } 1657 1658 // TODO(pbos): Support or remove the following stats. 1659 info.packets_cached = -1; 1660 info.rtt_ms = -1; 1661 1662 return info; 1663} 1664 1665void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() { 1666 if (stream_ != NULL) { 1667 call_->DestroyVideoSendStream(stream_); 1668 } 1669 1670 VideoCodecSettings codec_settings; 1671 parameters_.codec_settings.Get(&codec_settings); 1672 void* encoder_settings = encoder_factory_->CreateVideoEncoderSettings( 1673 codec_settings.codec, parameters_.options); 1674 1675 stream_ = call_->CreateVideoSendStream( 1676 parameters_.config, parameters_.video_streams, encoder_settings); 1677 1678 encoder_factory_->DestroyVideoEncoderSettings(codec_settings.codec, 1679 encoder_settings); 1680 1681 if (sending_) { 1682 stream_->Start(); 1683 } 1684} 1685 1686WebRtcVideoChannel2::WebRtcVideoReceiveStream::WebRtcVideoReceiveStream( 1687 webrtc::Call* call, 1688 const webrtc::VideoReceiveStream::Config& config, 1689 const std::vector<VideoCodecSettings>& recv_codecs) 1690 : call_(call), 1691 stream_(NULL), 1692 config_(config), 1693 renderer_(NULL), 1694 last_width_(-1), 1695 last_height_(-1) { 1696 config_.renderer = this; 1697 // SetRecvCodecs will also reset (start) the VideoReceiveStream. 1698 SetRecvCodecs(recv_codecs); 1699} 1700 1701WebRtcVideoChannel2::WebRtcVideoReceiveStream::~WebRtcVideoReceiveStream() { 1702 call_->DestroyVideoReceiveStream(stream_); 1703} 1704 1705void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRecvCodecs( 1706 const std::vector<VideoCodecSettings>& recv_codecs) { 1707 // TODO(pbos): Reconfigure RTX based on incoming recv_codecs. 1708 // TODO(pbos): Base receive codecs off recv_codecs_ and set up using a 1709 // DecoderFactory similar to send side. Pending webrtc:2854. 1710 // Also set up default codecs if there's nothing in recv_codecs_. 1711 webrtc::VideoCodec codec; 1712 memset(&codec, 0, sizeof(codec)); 1713 1714 codec.plType = kDefaultVideoCodecPref.payload_type; 1715 strcpy(codec.plName, kDefaultVideoCodecPref.name); 1716 codec.codecType = webrtc::kVideoCodecVP8; 1717 codec.codecSpecific.VP8.resilience = webrtc::kResilientStream; 1718 codec.codecSpecific.VP8.numberOfTemporalLayers = 1; 1719 codec.codecSpecific.VP8.denoisingOn = true; 1720 codec.codecSpecific.VP8.errorConcealmentOn = false; 1721 codec.codecSpecific.VP8.automaticResizeOn = false; 1722 codec.codecSpecific.VP8.frameDroppingOn = true; 1723 codec.codecSpecific.VP8.keyFrameInterval = 3000; 1724 // Bitrates don't matter and are ignored for the receiver. This is put in to 1725 // have the current underlying implementation accept the VideoCodec. 1726 codec.minBitrate = codec.startBitrate = codec.maxBitrate = 300; 1727 config_.codecs.clear(); 1728 config_.codecs.push_back(codec); 1729 1730 config_.rtp.fec = recv_codecs.front().fec; 1731 1732 config_.rtp.nack.rtp_history_ms = 1733 IsNackEnabled(recv_codecs.begin()->codec) ? kNackHistoryMs : 0; 1734 config_.rtp.remb = IsRembEnabled(recv_codecs.begin()->codec); 1735 1736 RecreateWebRtcStream(); 1737} 1738 1739void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRtpExtensions( 1740 const std::vector<webrtc::RtpExtension>& extensions) { 1741 config_.rtp.extensions = extensions; 1742 RecreateWebRtcStream(); 1743} 1744 1745void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RecreateWebRtcStream() { 1746 if (stream_ != NULL) { 1747 call_->DestroyVideoReceiveStream(stream_); 1748 } 1749 stream_ = call_->CreateVideoReceiveStream(config_); 1750 stream_->Start(); 1751} 1752 1753void WebRtcVideoChannel2::WebRtcVideoReceiveStream::RenderFrame( 1754 const webrtc::I420VideoFrame& frame, 1755 int time_to_render_ms) { 1756 rtc::CritScope crit(&renderer_lock_); 1757 if (renderer_ == NULL) { 1758 LOG(LS_WARNING) << "VideoReceiveStream not connected to a VideoRenderer."; 1759 return; 1760 } 1761 1762 if (frame.width() != last_width_ || frame.height() != last_height_) { 1763 SetSize(frame.width(), frame.height()); 1764 } 1765 1766 LOG(LS_VERBOSE) << "RenderFrame: (" << frame.width() << "x" << frame.height() 1767 << ")"; 1768 1769 const WebRtcVideoRenderFrame render_frame(&frame); 1770 renderer_->RenderFrame(&render_frame); 1771} 1772 1773void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetRenderer( 1774 cricket::VideoRenderer* renderer) { 1775 rtc::CritScope crit(&renderer_lock_); 1776 renderer_ = renderer; 1777 if (renderer_ != NULL && last_width_ != -1) { 1778 SetSize(last_width_, last_height_); 1779 } 1780} 1781 1782VideoRenderer* WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetRenderer() { 1783 // TODO(pbos): Remove GetRenderer and all uses of it, it's thread-unsafe by 1784 // design. 1785 rtc::CritScope crit(&renderer_lock_); 1786 return renderer_; 1787} 1788 1789void WebRtcVideoChannel2::WebRtcVideoReceiveStream::SetSize(int width, 1790 int height) { 1791 rtc::CritScope crit(&renderer_lock_); 1792 if (!renderer_->SetSize(width, height, 0)) { 1793 LOG(LS_ERROR) << "Could not set renderer size."; 1794 } 1795 last_width_ = width; 1796 last_height_ = height; 1797} 1798 1799VideoReceiverInfo 1800WebRtcVideoChannel2::WebRtcVideoReceiveStream::GetVideoReceiverInfo() { 1801 VideoReceiverInfo info; 1802 info.add_ssrc(config_.rtp.remote_ssrc); 1803 webrtc::VideoReceiveStream::Stats stats = stream_->GetStats(); 1804 info.bytes_rcvd = stats.rtp_stats.bytes + stats.rtp_stats.header_bytes + 1805 stats.rtp_stats.padding_bytes; 1806 info.packets_rcvd = stats.rtp_stats.packets; 1807 1808 info.framerate_rcvd = stats.network_frame_rate; 1809 info.framerate_decoded = stats.decode_frame_rate; 1810 info.framerate_output = stats.render_frame_rate; 1811 1812 rtc::CritScope frame_cs(&renderer_lock_); 1813 info.frame_width = last_width_; 1814 info.frame_height = last_height_; 1815 1816 // TODO(pbos): Support or remove the following stats. 1817 info.packets_concealed = -1; 1818 1819 return info; 1820} 1821 1822WebRtcVideoChannel2::VideoCodecSettings::VideoCodecSettings() 1823 : rtx_payload_type(-1) {} 1824 1825std::vector<WebRtcVideoChannel2::VideoCodecSettings> 1826WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) { 1827 assert(!codecs.empty()); 1828 1829 std::vector<VideoCodecSettings> video_codecs; 1830 std::map<int, bool> payload_used; 1831 std::map<int, VideoCodec::CodecType> payload_codec_type; 1832 std::map<int, int> rtx_mapping; // video payload type -> rtx payload type. 1833 1834 webrtc::FecConfig fec_settings; 1835 1836 for (size_t i = 0; i < codecs.size(); ++i) { 1837 const VideoCodec& in_codec = codecs[i]; 1838 int payload_type = in_codec.id; 1839 1840 if (payload_used[payload_type]) { 1841 LOG(LS_ERROR) << "Payload type already registered: " 1842 << in_codec.ToString(); 1843 return std::vector<VideoCodecSettings>(); 1844 } 1845 payload_used[payload_type] = true; 1846 payload_codec_type[payload_type] = in_codec.GetCodecType(); 1847 1848 switch (in_codec.GetCodecType()) { 1849 case VideoCodec::CODEC_RED: { 1850 // RED payload type, should not have duplicates. 1851 assert(fec_settings.red_payload_type == -1); 1852 fec_settings.red_payload_type = in_codec.id; 1853 continue; 1854 } 1855 1856 case VideoCodec::CODEC_ULPFEC: { 1857 // ULPFEC payload type, should not have duplicates. 1858 assert(fec_settings.ulpfec_payload_type == -1); 1859 fec_settings.ulpfec_payload_type = in_codec.id; 1860 continue; 1861 } 1862 1863 case VideoCodec::CODEC_RTX: { 1864 int associated_payload_type; 1865 if (!in_codec.GetParam(kCodecParamAssociatedPayloadType, 1866 &associated_payload_type)) { 1867 LOG(LS_ERROR) << "RTX codec without associated payload type: " 1868 << in_codec.ToString(); 1869 return std::vector<VideoCodecSettings>(); 1870 } 1871 rtx_mapping[associated_payload_type] = in_codec.id; 1872 continue; 1873 } 1874 1875 case VideoCodec::CODEC_VIDEO: 1876 break; 1877 } 1878 1879 video_codecs.push_back(VideoCodecSettings()); 1880 video_codecs.back().codec = in_codec; 1881 } 1882 1883 // One of these codecs should have been a video codec. Only having FEC 1884 // parameters into this code is a logic error. 1885 assert(!video_codecs.empty()); 1886 1887 for (std::map<int, int>::const_iterator it = rtx_mapping.begin(); 1888 it != rtx_mapping.end(); 1889 ++it) { 1890 if (!payload_used[it->first]) { 1891 LOG(LS_ERROR) << "RTX mapped to payload not in codec list."; 1892 return std::vector<VideoCodecSettings>(); 1893 } 1894 if (payload_codec_type[it->first] != VideoCodec::CODEC_VIDEO) { 1895 LOG(LS_ERROR) << "RTX not mapped to regular video codec."; 1896 return std::vector<VideoCodecSettings>(); 1897 } 1898 } 1899 1900 // TODO(pbos): Write tests that figure out that I have not verified that RTX 1901 // codecs aren't mapped to bogus payloads. 1902 for (size_t i = 0; i < video_codecs.size(); ++i) { 1903 video_codecs[i].fec = fec_settings; 1904 if (rtx_mapping[video_codecs[i].codec.id] != 0) { 1905 video_codecs[i].rtx_payload_type = rtx_mapping[video_codecs[i].codec.id]; 1906 } 1907 } 1908 1909 return video_codecs; 1910} 1911 1912std::vector<WebRtcVideoChannel2::VideoCodecSettings> 1913WebRtcVideoChannel2::FilterSupportedCodecs( 1914 const std::vector<WebRtcVideoChannel2::VideoCodecSettings>& mapped_codecs) { 1915 std::vector<VideoCodecSettings> supported_codecs; 1916 for (size_t i = 0; i < mapped_codecs.size(); ++i) { 1917 if (encoder_factory_->SupportsCodec(mapped_codecs[i].codec)) { 1918 supported_codecs.push_back(mapped_codecs[i]); 1919 } 1920 } 1921 return supported_codecs; 1922} 1923 1924} // namespace cricket 1925 1926#endif // HAVE_WEBRTC_VIDEO 1927