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