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()),
39 render_main_message_loop_(base::MessageLoopProxy::current()),
43 VideoCaptureImplManager::~VideoCaptureImplManager() {
44 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
47 // Forcibly release all video capture resources.
48 for (const auto& device
: devices_
) {
49 VideoCaptureImpl
* const impl
= device
.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()->DeleteSoon(FROM_HERE
,
60 base::Closure
VideoCaptureImplManager::UseDevice(
61 media::VideoCaptureSessionId id
) {
62 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
64 VideoCaptureImpl
* impl
= NULL
;
65 const VideoCaptureDeviceMap::iterator it
= devices_
.find(id
);
66 if (it
== devices_
.end()) {
67 impl
= CreateVideoCaptureImplForTesting(id
, filter_
.get());
69 impl
= new VideoCaptureImpl(id
, filter_
.get());
70 devices_
[id
] = std::make_pair(1, impl
);
71 ChildProcess::current()->io_message_loop_proxy()->PostTask(
73 base::Bind(&VideoCaptureImpl::Init
,
74 base::Unretained(impl
)));
78 return base::Bind(&VideoCaptureImplManager::UnrefDevice
,
79 weak_factory_
.GetWeakPtr(), id
);
82 base::Closure
VideoCaptureImplManager::StartCapture(
83 media::VideoCaptureSessionId id
,
84 const media::VideoCaptureParams
& params
,
85 const VideoCaptureStateUpdateCB
& state_update_cb
,
86 const VideoCaptureDeliverFrameCB
& deliver_frame_cb
) {
87 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
88 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
89 DCHECK(it
!= devices_
.end());
90 VideoCaptureImpl
* const impl
= it
->second
.second
;
92 // This ID is used to identify a client of VideoCaptureImpl.
93 const int client_id
= ++next_client_id_
;
95 ChildProcess::current()->io_message_loop_proxy()->PostTask(
97 base::Bind(&VideoCaptureImpl::StartCapture
,
98 base::Unretained(impl
),
103 return base::Bind(&VideoCaptureImplManager::StopCapture
,
104 weak_factory_
.GetWeakPtr(),
108 void VideoCaptureImplManager::GetDeviceSupportedFormats(
109 media::VideoCaptureSessionId id
,
110 const VideoCaptureDeviceFormatsCB
& callback
) {
111 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
112 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
113 DCHECK(it
!= devices_
.end());
114 VideoCaptureImpl
* const impl
= it
->second
.second
;
115 ChildProcess::current()->io_message_loop_proxy()->PostTask(
117 base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats
,
118 base::Unretained(impl
), callback
));
121 void VideoCaptureImplManager::GetDeviceFormatsInUse(
122 media::VideoCaptureSessionId id
,
123 const VideoCaptureDeviceFormatsCB
& callback
) {
124 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
125 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
126 DCHECK(it
!= devices_
.end());
127 VideoCaptureImpl
* const impl
= it
->second
.second
;
128 ChildProcess::current()->io_message_loop_proxy()->PostTask(
130 base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse
,
131 base::Unretained(impl
), callback
));
135 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
136 media::VideoCaptureSessionId id
,
137 VideoCaptureMessageFilter
* filter
) const {
141 void VideoCaptureImplManager::StopCapture(int client_id
,
142 media::VideoCaptureSessionId id
) {
143 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
144 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
145 DCHECK(it
!= devices_
.end());
146 VideoCaptureImpl
* const impl
= it
->second
.second
;
147 ChildProcess::current()->io_message_loop_proxy()->PostTask(
149 base::Bind(&VideoCaptureImpl::StopCapture
,
150 base::Unretained(impl
), client_id
));
153 void VideoCaptureImplManager::UnrefDevice(
154 media::VideoCaptureSessionId id
) {
155 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
156 const VideoCaptureDeviceMap::iterator it
= devices_
.find(id
);
157 DCHECK(it
!= devices_
.end());
158 VideoCaptureImpl
* const impl
= it
->second
.second
;
160 // Unref and destroy on the IO thread if there's no more client.
161 DCHECK(it
->second
.first
);
163 if (!it
->second
.first
) {
165 ChildProcess::current()->io_message_loop_proxy()->PostTask(
167 base::Bind(&VideoCaptureImpl::DeInit
,
168 base::Unretained(impl
)));
169 ChildProcess::current()->io_message_loop_proxy()->DeleteSoon(FROM_HERE
,
174 void VideoCaptureImplManager::SuspendDevices(bool suspend
) {
175 DCHECK(render_main_message_loop_
->BelongsToCurrentThread());
176 for (const auto& device
: devices_
) {
177 VideoCaptureImpl
* const impl
= device
.second
.second
;
178 ChildProcess::current()->io_message_loop_proxy()->PostTask(
179 FROM_HERE
, base::Bind(&VideoCaptureImpl::SuspendCapture
,
180 base::Unretained(impl
), suspend
));
184 } // namespace content