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