1 // Copyright (c) 2012 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 // Implementation notes about interactions with VideoCaptureImpl. 6 // 7 // How is VideoCaptureImpl used: 8 // 9 // VideoCaptureImpl is an IO thread object while VideoCaptureImplManager 10 // lives only on the render thread. It is only possible to access an 11 // object of VideoCaptureImpl via a task on the IO thread. 12 // 13 // How is VideoCaptureImpl deleted: 14 // 15 // A task is posted to the IO thread to delete a VideoCaptureImpl. 16 // Immediately after that the pointer to it is dropped. This means no 17 // access to this VideoCaptureImpl object is possible on the render 18 // thread. Also note that VideoCaptureImpl does not post task to itself. 19 // 20 // The use of Unretained: 21 // 22 // We make sure deletion is the last task on the IO thread for a 23 // VideoCaptureImpl object. This allows the use of Unretained() binding. 24 25 #include "content/renderer/media/video_capture_impl_manager.h" 26 27 #include "base/bind.h" 28 #include "base/bind_helpers.h" 29 #include "content/child/child_process.h" 30 #include "content/renderer/media/video_capture_impl.h" 31 #include "content/renderer/media/video_capture_message_filter.h" 32 #include "media/base/bind_to_current_loop.h" 33 34 namespace content { 35 36 VideoCaptureImplManager::VideoCaptureImplManager() 37 : next_client_id_(0), 38 filter_(new VideoCaptureMessageFilter()), 39 weak_factory_(this) { 40 } 41 42 VideoCaptureImplManager::~VideoCaptureImplManager() { 43 DCHECK(thread_checker_.CalledOnValidThread()); 44 if (devices_.empty()) 45 return; 46 // Forcibly release all video capture resources. 47 for (VideoCaptureDeviceMap::iterator it = devices_.begin(); 48 it != devices_.end(); ++it) { 49 VideoCaptureImpl* impl = it->second.second; 50 ChildProcess::current()->io_message_loop_proxy()->PostTask( 51 FROM_HERE, 52 base::Bind(&VideoCaptureImpl::DeInit, 53 base::Unretained(impl))); 54 ChildProcess::current()->io_message_loop_proxy()->PostTask( 55 FROM_HERE, 56 base::Bind(&base::DeletePointer<VideoCaptureImpl>, 57 base::Unretained(impl))); 58 } 59 devices_.clear(); 60 } 61 62 base::Closure VideoCaptureImplManager::UseDevice( 63 media::VideoCaptureSessionId id) { 64 DCHECK(thread_checker_.CalledOnValidThread()); 65 66 VideoCaptureImpl* impl = NULL; 67 VideoCaptureDeviceMap::iterator it = devices_.find(id); 68 if (it == devices_.end()) { 69 impl = CreateVideoCaptureImplForTesting(id, filter_.get()); 70 if (!impl) 71 impl = new VideoCaptureImpl(id, filter_.get()); 72 devices_[id] = std::make_pair(1, impl); 73 ChildProcess::current()->io_message_loop_proxy()->PostTask( 74 FROM_HERE, 75 base::Bind(&VideoCaptureImpl::Init, 76 base::Unretained(impl))); 77 } else { 78 ++it->second.first; 79 } 80 return base::Bind(&VideoCaptureImplManager::UnrefDevice, 81 weak_factory_.GetWeakPtr(), id); 82 } 83 84 base::Closure VideoCaptureImplManager::StartCapture( 85 media::VideoCaptureSessionId id, 86 const media::VideoCaptureParams& params, 87 const VideoCaptureStateUpdateCB& state_update_cb, 88 const VideoCaptureDeliverFrameCB& deliver_frame_cb) { 89 DCHECK(thread_checker_.CalledOnValidThread()); 90 VideoCaptureDeviceMap::iterator it = devices_.find(id); 91 DCHECK(it != devices_.end()); 92 VideoCaptureImpl* impl = it->second.second; 93 94 // This ID is used to identify a client of VideoCaptureImpl. 95 const int client_id = ++next_client_id_; 96 97 ChildProcess::current()->io_message_loop_proxy()->PostTask( 98 FROM_HERE, 99 base::Bind(&VideoCaptureImpl::StartCapture, 100 base::Unretained(impl), 101 client_id, 102 params, 103 state_update_cb, 104 deliver_frame_cb)); 105 return base::Bind(&VideoCaptureImplManager::StopCapture, 106 weak_factory_.GetWeakPtr(), 107 client_id, id); 108 } 109 110 void VideoCaptureImplManager::GetDeviceSupportedFormats( 111 media::VideoCaptureSessionId id, 112 const VideoCaptureDeviceFormatsCB& callback) { 113 DCHECK(thread_checker_.CalledOnValidThread()); 114 VideoCaptureDeviceMap::iterator it = devices_.find(id); 115 DCHECK(it != devices_.end()); 116 VideoCaptureImpl* impl = it->second.second; 117 ChildProcess::current()->io_message_loop_proxy()->PostTask( 118 FROM_HERE, 119 base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats, 120 base::Unretained(impl), callback)); 121 } 122 123 void VideoCaptureImplManager::GetDeviceFormatsInUse( 124 media::VideoCaptureSessionId id, 125 const VideoCaptureDeviceFormatsCB& callback) { 126 DCHECK(thread_checker_.CalledOnValidThread()); 127 VideoCaptureDeviceMap::iterator it = devices_.find(id); 128 DCHECK(it != devices_.end()); 129 VideoCaptureImpl* impl = it->second.second; 130 ChildProcess::current()->io_message_loop_proxy()->PostTask( 131 FROM_HERE, 132 base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse, 133 base::Unretained(impl), callback)); 134 } 135 136 VideoCaptureImpl* 137 VideoCaptureImplManager::CreateVideoCaptureImplForTesting( 138 media::VideoCaptureSessionId id, 139 VideoCaptureMessageFilter* filter) const { 140 return NULL; 141 } 142 143 void VideoCaptureImplManager::StopCapture( 144 int client_id, media::VideoCaptureSessionId id) { 145 DCHECK(thread_checker_.CalledOnValidThread()); 146 VideoCaptureDeviceMap::iterator it = devices_.find(id); 147 DCHECK(it != devices_.end()); 148 VideoCaptureImpl* impl = it->second.second; 149 ChildProcess::current()->io_message_loop_proxy()->PostTask( 150 FROM_HERE, 151 base::Bind(&VideoCaptureImpl::StopCapture, 152 base::Unretained(impl), client_id)); 153 } 154 155 void VideoCaptureImplManager::UnrefDevice( 156 media::VideoCaptureSessionId id) { 157 DCHECK(thread_checker_.CalledOnValidThread()); 158 VideoCaptureDeviceMap::iterator it = devices_.find(id); 159 DCHECK(it != devices_.end()); 160 VideoCaptureImpl* impl = it->second.second; 161 162 // Unref and destroy on the IO thread if there's no more client. 163 DCHECK(it->second.first); 164 --it->second.first; 165 if (!it->second.first) { 166 devices_.erase(id); 167 ChildProcess::current()->io_message_loop_proxy()->PostTask( 168 FROM_HERE, 169 base::Bind(&VideoCaptureImpl::DeInit, 170 base::Unretained(impl))); 171 ChildProcess::current()->io_message_loop_proxy()->PostTask( 172 FROM_HERE, 173 base::Bind(&base::DeletePointer<VideoCaptureImpl>, 174 base::Unretained(impl))); 175 } 176 } 177 178 void VideoCaptureImplManager::SuspendDevices(bool suspend) { 179 DCHECK(thread_checker_.CalledOnValidThread()); 180 for (VideoCaptureDeviceMap::iterator it = devices_.begin(); 181 it != devices_.end(); ++it) { 182 VideoCaptureImpl* impl = it->second.second; 183 ChildProcess::current()->io_message_loop_proxy()->PostTask( 184 FROM_HERE, 185 base::Bind(&VideoCaptureImpl::SuspendCapture, 186 base::Unretained(impl), suspend)); 187 } 188 } 189 190 } // namespace content 191