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 13namespace { 14 15bool 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 24namespace 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. 30class 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 80WebRtcVideoTrackAdapter::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 91WebRtcVideoTrackAdapter::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 102void WebRtcVideoTrackAdapter::WebRtcVideoSourceAdapter:: 103ReleaseSourceOnMainThread() { 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 114void 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 125void 126WebRtcVideoTrackAdapter::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 136WebRtcVideoTrackAdapter::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 173WebRtcVideoTrackAdapter::~WebRtcVideoTrackAdapter() { 174 DCHECK(thread_checker_.CalledOnValidThread()); 175 DVLOG(3) << "WebRtcVideoTrackAdapter dtor()."; 176 RemoveFromVideoTrack(this, web_track_); 177 source_adapter_->ReleaseSourceOnMainThread(); 178} 179 180void WebRtcVideoTrackAdapter::OnEnabledChanged(bool enabled) { 181 DCHECK(thread_checker_.CalledOnValidThread()); 182 video_track_->set_enabled(enabled); 183} 184 185} // namespace content 186