• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ConstraintKeyExists(const blink::WebMediaConstraints & constraints,const blink::WebString & name)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 
WebRtcVideoSourceAdapter(const scoped_refptr<base::MessageLoopProxy> & libjingle_worker_thread,const scoped_refptr<webrtc::VideoSourceInterface> & source,WebRtcVideoCapturerAdapter * capture_adapter)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 
~WebRtcVideoSourceAdapter()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::
ReleaseSourceOnMainThread()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 
OnVideoFrameOnIO(const scoped_refptr<media::VideoFrame> & frame,const media::VideoCaptureFormat & format,const base::TimeTicks & estimated_capture_time)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
OnVideoFrameOnWorkerThread(const scoped_refptr<media::VideoFrame> & frame,const media::VideoCaptureFormat & format,const base::TimeTicks & estimated_capture_time)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 
WebRtcVideoTrackAdapter(const blink::WebMediaStreamTrack & track,PeerConnectionDependencyFactory * factory)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 
~WebRtcVideoTrackAdapter()173 WebRtcVideoTrackAdapter::~WebRtcVideoTrackAdapter() {
174   DCHECK(thread_checker_.CalledOnValidThread());
175   DVLOG(3) << "WebRtcVideoTrackAdapter dtor().";
176   RemoveFromVideoTrack(this, web_track_);
177   source_adapter_->ReleaseSourceOnMainThread();
178 }
179 
OnEnabledChanged(bool enabled)180 void WebRtcVideoTrackAdapter::OnEnabledChanged(bool enabled) {
181   DCHECK(thread_checker_.CalledOnValidThread());
182   video_track_->set_enabled(enabled);
183 }
184 
185 }  // namespace content
186