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.
5 // Implementation notes about interactions with VideoCaptureImpl.
7 // How is VideoCaptureImpl used:
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.
13 // How is VideoCaptureImpl deleted:
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.
20 // The use of Unretained:
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.
25 #include "content/renderer/media/video_capture_impl_manager.h"
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"
36 VideoCaptureImplManager::VideoCaptureImplManager()
38 filter_(new VideoCaptureMessageFilter()),
42 VideoCaptureImplManager::~VideoCaptureImplManager() {
43 DCHECK(thread_checker_
.CalledOnValidThread());
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(
52 base::Bind(&VideoCaptureImpl::DeInit
,
53 base::Unretained(impl
)));
54 ChildProcess::current()->io_message_loop_proxy()->PostTask(
56 base::Bind(&base::DeletePointer
<VideoCaptureImpl
>,
57 base::Unretained(impl
)));
62 base::Closure
VideoCaptureImplManager::UseDevice(
63 media::VideoCaptureSessionId id
) {
64 DCHECK(thread_checker_
.CalledOnValidThread());
66 VideoCaptureImpl
* impl
= NULL
;
67 VideoCaptureDeviceMap::iterator it
= devices_
.find(id
);
68 if (it
== devices_
.end()) {
69 impl
= CreateVideoCaptureImplForTesting(id
, filter_
.get());
71 impl
= new VideoCaptureImpl(id
, filter_
.get());
72 devices_
[id
] = std::make_pair(1, impl
);
73 ChildProcess::current()->io_message_loop_proxy()->PostTask(
75 base::Bind(&VideoCaptureImpl::Init
,
76 base::Unretained(impl
)));
80 return base::Bind(&VideoCaptureImplManager::UnrefDevice
,
81 weak_factory_
.GetWeakPtr(), id
);
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
;
94 // This ID is used to identify a client of VideoCaptureImpl.
95 const int client_id
= ++next_client_id_
;
97 ChildProcess::current()->io_message_loop_proxy()->PostTask(
99 base::Bind(&VideoCaptureImpl::StartCapture
,
100 base::Unretained(impl
),
105 return base::Bind(&VideoCaptureImplManager::StopCapture
,
106 weak_factory_
.GetWeakPtr(),
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(
119 base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats
,
120 base::Unretained(impl
), callback
));
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(
132 base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse
,
133 base::Unretained(impl
), callback
));
137 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
138 media::VideoCaptureSessionId id
,
139 VideoCaptureMessageFilter
* filter
) const {
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(
151 base::Bind(&VideoCaptureImpl::StopCapture
,
152 base::Unretained(impl
), client_id
));
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
;
162 // Unref and destroy on the IO thread if there's no more client.
163 DCHECK(it
->second
.first
);
165 if (!it
->second
.first
) {
167 ChildProcess::current()->io_message_loop_proxy()->PostTask(
169 base::Bind(&VideoCaptureImpl::DeInit
,
170 base::Unretained(impl
)));
171 ChildProcess::current()->io_message_loop_proxy()->PostTask(
173 base::Bind(&base::DeletePointer
<VideoCaptureImpl
>,
174 base::Unretained(impl
)));
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(
185 base::Bind(&VideoCaptureImpl::SuspendCapture
,
186 base::Unretained(impl
), suspend
));
190 } // namespace content