Home | History | Annotate | Download | only in webrtc
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/media/webrtc/webrtc_video_track_adapter.h"
      6 
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "base/synchronization/lock.h"
      9 #include "content/common/media/media_stream_options.h"
     10 #include "content/renderer/media/media_stream_video_source.h"
     11 #include "content/renderer/media/media_stream_video_track.h"
     12 
     13 namespace {
     14 
     15 bool ConstraintKeyExists(const blink::WebMediaConstraints& constraints,
     16                          const blink::WebString& name) {
     17   blink::WebString value_str;
     18   return constraints.getMandatoryConstraintValue(name, value_str) ||
     19       constraints.getOptionalConstraintValue(name, value_str);
     20 }
     21 
     22 }  // anonymouse namespace
     23 
     24 namespace content {
     25 
     26 // Simple help class used for receiving video frames on the IO-thread from
     27 // a MediaStreamVideoTrack and forward the frames to a
     28 // WebRtcVideoCapturerAdapter on libjingle's worker thread.
     29 // WebRtcVideoCapturerAdapter implements a video capturer for libjingle.
     30 class WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter
     31     : public base::RefCountedThreadSafe<WebRtcVideoSourceAdapter> {
     32  public:
     33   WebRtcVideoSourceAdapter(
     34       const scoped_refptr<base::MessageLoopProxy>& libjingle_worker_thread,
     35       const scoped_refptr<webrtc::VideoSourceInterface>& source,
     36       WebRtcVideoCapturerAdapter* capture_adapter);
     37 
     38   // WebRtcVideoTrackAdapter can be destroyed on the main render thread or
     39   // libjingles worker thread since it posts video frames on that thread. But
     40   // |video_source_| must be released on the main render thread before the
     41   // PeerConnectionFactory has been destroyed. The only way to ensure that is
     42   // to make sure |video_source_| is released when WebRtcVideoTrackAdapter() is
     43   // destroyed.
     44   void ReleaseSourceOnMainThread();
     45 
     46   void OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame>& frame,
     47                         const media::VideoCaptureFormat& format,
     48                         const base::TimeTicks& estimated_capture_time);
     49 
     50  private:
     51   void OnVideoFrameOnWorkerThread(
     52       const scoped_refptr<media::VideoFrame>& frame,
     53       const media::VideoCaptureFormat& format,
     54       const base::TimeTicks& estimated_capture_time);
     55   friend class base::RefCountedThreadSafe<WebRtcVideoSourceAdapter>;
     56   virtual ~WebRtcVideoSourceAdapter();
     57 
     58   scoped_refptr<base::MessageLoopProxy> render_thread_message_loop_;
     59 
     60   // |render_thread_checker_| is bound to the main render thread.
     61   base::ThreadChecker render_thread_checker_;
     62   // Used to DCHECK that frames are called on the IO-thread.
     63   base::ThreadChecker io_thread_checker_;
     64 
     65   // Used for posting frames to libjingle's worker thread. Accessed on the
     66   // IO-thread.
     67   scoped_refptr<base::MessageLoopProxy> libjingle_worker_thread_;
     68 
     69   scoped_refptr<webrtc::VideoSourceInterface> video_source_;
     70 
     71   // Used to protect |capture_adapter_|. It is taken by libjingle's worker
     72   // thread for each video frame that is delivered but only taken on the
     73   // main render thread in ReleaseSourceOnMainThread() when
     74   // the owning WebRtcVideoTrackAdapter is being destroyed.
     75   base::Lock capture_adapter_stop_lock_;
     76   // |capture_adapter_| is owned by |video_source_|
     77   WebRtcVideoCapturerAdapter* capture_adapter_;
     78 };
     79 
     80 WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::WebRtcVideoSourceAdapter(
     81     const scoped_refptr<base::MessageLoopProxy>& libjingle_worker_thread,
     82     const scoped_refptr<webrtc::VideoSourceInterface>& source,
     83     WebRtcVideoCapturerAdapter* capture_adapter)
     84     : render_thread_message_loop_(base::MessageLoopProxy::current()),
     85       libjingle_worker_thread_(libjingle_worker_thread),
     86       video_source_(source),
     87       capture_adapter_(capture_adapter) {
     88   io_thread_checker_.DetachFromThread();
     89 }
     90 
     91 WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::~WebRtcVideoSourceAdapter() {
     92   DVLOG(3) << "~WebRtcVideoSourceAdapter()";
     93   DCHECK(!capture_adapter_);
     94   // This object can be destroyed on the main render thread or libjingles
     95   // worker thread since it posts video frames on that thread. But
     96   // |video_source_| must be released on the main render thread before the
     97   // PeerConnectionFactory has been destroyed. The only way to ensure that is
     98   // to make sure |video_source_| is released when WebRtcVideoTrackAdapter() is
     99   // destroyed.
    100 }
    101 
    102 void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::
    103 ReleaseSourceOnMainThread() {
    104   DCHECK(render_thread_checker_.CalledOnValidThread());
    105   // Since frames are posted to the worker thread, this object might be deleted
    106   // on that thread. However, since |video_source_| was created on the render
    107   // thread, it should be released on the render thread.
    108   base::AutoLock auto_lock(capture_adapter_stop_lock_);
    109   // |video_source| owns |capture_adapter_|.
    110   capture_adapter_ = NULL;
    111   video_source_ = NULL;
    112 }
    113 
    114 void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnIO(
    115     const scoped_refptr<media::VideoFrame>& frame,
    116     const media::VideoCaptureFormat& format,
    117     const base::TimeTicks& estimated_capture_time) {
    118   DCHECK(io_thread_checker_.CalledOnValidThread());
    119   libjingle_worker_thread_->PostTask(
    120       FROM_HERE,
    121       base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread,
    122                  this, frame, format, estimated_capture_time));
    123 }
    124 
    125 void
    126 WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter::OnVideoFrameOnWorkerThread(
    127     const scoped_refptr<media::VideoFrame>& frame,
    128     const media::VideoCaptureFormat& format,
    129     const base::TimeTicks& estimated_capture_time) {
    130   DCHECK(libjingle_worker_thread_->BelongsToCurrentThread());
    131   base::AutoLock auto_lock(capture_adapter_stop_lock_);
    132   if (capture_adapter_)
    133     capture_adapter_->OnFrameCaptured(frame);
    134 }
    135 
    136 WebRtcVideoTrackAdapter::WebRtcVideoTrackAdapter(
    137     const blink::WebMediaStreamTrack& track,
    138     PeerConnectionDependencyFactory* factory)
    139     : web_track_(track) {
    140   const blink::WebMediaConstraints& constraints =
    141       MediaStreamVideoTrack::GetVideoTrack(track)->constraints();
    142 
    143   bool is_screencast = ConstraintKeyExists(
    144       constraints, base::UTF8ToUTF16(kMediaStreamSource));
    145   WebRtcVideoCapturerAdapter* capture_adapter =
    146       factory->CreateVideoCapturer(is_screencast);
    147 
    148   // |video_source| owns |capture_adapter|
    149   scoped_refptr<webrtc::VideoSourceInterface> video_source(
    150       factory->CreateVideoSource(capture_adapter,
    151                                  track.source().constraints()));
    152 
    153   video_track_ = factory->CreateLocalVideoTrack(web_track_.id().utf8(),
    154                                                 video_source.get());
    155 
    156   video_track_->set_enabled(web_track_.isEnabled());
    157 
    158   source_adapter_ = new WebRtcVideoSourceAdapter(
    159       factory->GetWebRtcWorkerThread(),
    160       video_source,
    161       capture_adapter);
    162 
    163   AddToVideoTrack(
    164       this,
    165       base::Bind(&WebRtcVideoSourceAdapter::OnVideoFrameOnIO,
    166                  source_adapter_),
    167       web_track_);
    168 
    169   DVLOG(3) << "WebRtcVideoTrackAdapter ctor() : is_screencast "
    170            << is_screencast;
    171 }
    172 
    173 WebRtcVideoTrackAdapter::~WebRtcVideoTrackAdapter() {
    174   DCHECK(thread_checker_.CalledOnValidThread());
    175   DVLOG(3) << "WebRtcVideoTrackAdapter dtor().";
    176   RemoveFromVideoTrack(this, web_track_);
    177   source_adapter_->ReleaseSourceOnMainThread();
    178 }
    179 
    180 void WebRtcVideoTrackAdapter::OnEnabledChanged(bool enabled) {
    181   DCHECK(thread_checker_.CalledOnValidThread());
    182   video_track_->set_enabled(enabled);
    183 }
    184 
    185 }  // namespace content
    186