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