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