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 "base/location.h"
30 #include "base/thread_task_runner_handle.h"
31 #include "content/child/child_process.h"
32 #include "content/renderer/media/video_capture_impl.h"
33 #include "content/renderer/media/video_capture_message_filter.h"
34 #include "media/base/bind_to_current_loop.h"
38 VideoCaptureImplManager::VideoCaptureImplManager()
40 filter_(new VideoCaptureMessageFilter()),
41 render_main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
45 VideoCaptureImplManager::~VideoCaptureImplManager() {
46 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
49 // Forcibly release all video capture resources.
50 for (const auto& device
: devices_
) {
51 VideoCaptureImpl
* const impl
= device
.second
.second
;
52 ChildProcess::current()->io_task_runner()->PostTask(
54 base::Bind(&VideoCaptureImpl::DeInit
, base::Unretained(impl
)));
55 ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE
, impl
);
60 base::Closure
VideoCaptureImplManager::UseDevice(
61 media::VideoCaptureSessionId id
) {
62 DCHECK(render_main_task_runner_
->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_task_runner()->PostTask(
72 FROM_HERE
, base::Bind(&VideoCaptureImpl::Init
, base::Unretained(impl
)));
76 return base::Bind(&VideoCaptureImplManager::UnrefDevice
,
77 weak_factory_
.GetWeakPtr(), id
);
80 base::Closure
VideoCaptureImplManager::StartCapture(
81 media::VideoCaptureSessionId id
,
82 const media::VideoCaptureParams
& params
,
83 const VideoCaptureStateUpdateCB
& state_update_cb
,
84 const VideoCaptureDeliverFrameCB
& deliver_frame_cb
) {
85 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
86 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
87 DCHECK(it
!= devices_
.end());
88 VideoCaptureImpl
* const impl
= it
->second
.second
;
90 // This ID is used to identify a client of VideoCaptureImpl.
91 const int client_id
= ++next_client_id_
;
93 ChildProcess::current()->io_task_runner()->PostTask(
95 base::Bind(&VideoCaptureImpl::StartCapture
, base::Unretained(impl
),
96 client_id
, params
, state_update_cb
, deliver_frame_cb
));
97 return base::Bind(&VideoCaptureImplManager::StopCapture
,
98 weak_factory_
.GetWeakPtr(),
102 void VideoCaptureImplManager::GetDeviceSupportedFormats(
103 media::VideoCaptureSessionId id
,
104 const VideoCaptureDeviceFormatsCB
& callback
) {
105 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
106 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
107 DCHECK(it
!= devices_
.end());
108 VideoCaptureImpl
* const impl
= it
->second
.second
;
109 ChildProcess::current()->io_task_runner()->PostTask(
110 FROM_HERE
, base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats
,
111 base::Unretained(impl
), callback
));
114 void VideoCaptureImplManager::GetDeviceFormatsInUse(
115 media::VideoCaptureSessionId id
,
116 const VideoCaptureDeviceFormatsCB
& callback
) {
117 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
118 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
119 DCHECK(it
!= devices_
.end());
120 VideoCaptureImpl
* const impl
= it
->second
.second
;
121 ChildProcess::current()->io_task_runner()->PostTask(
122 FROM_HERE
, base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse
,
123 base::Unretained(impl
), callback
));
127 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
128 media::VideoCaptureSessionId id
,
129 VideoCaptureMessageFilter
* filter
) const {
133 void VideoCaptureImplManager::StopCapture(int client_id
,
134 media::VideoCaptureSessionId id
) {
135 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
136 const VideoCaptureDeviceMap::const_iterator it
= devices_
.find(id
);
137 DCHECK(it
!= devices_
.end());
138 VideoCaptureImpl
* const impl
= it
->second
.second
;
139 ChildProcess::current()->io_task_runner()->PostTask(
140 FROM_HERE
, base::Bind(&VideoCaptureImpl::StopCapture
,
141 base::Unretained(impl
), client_id
));
144 void VideoCaptureImplManager::UnrefDevice(
145 media::VideoCaptureSessionId id
) {
146 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
147 const VideoCaptureDeviceMap::iterator it
= devices_
.find(id
);
148 DCHECK(it
!= devices_
.end());
149 VideoCaptureImpl
* const impl
= it
->second
.second
;
151 // Unref and destroy on the IO thread if there's no more client.
152 DCHECK(it
->second
.first
);
154 if (!it
->second
.first
) {
156 ChildProcess::current()->io_task_runner()->PostTask(
158 base::Bind(&VideoCaptureImpl::DeInit
, base::Unretained(impl
)));
159 ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE
, impl
);
163 void VideoCaptureImplManager::SuspendDevices(bool suspend
) {
164 DCHECK(render_main_task_runner_
->BelongsToCurrentThread());
165 for (const auto& device
: devices_
) {
166 VideoCaptureImpl
* const impl
= device
.second
.second
;
167 ChildProcess::current()->io_task_runner()->PostTask(
168 FROM_HERE
, base::Bind(&VideoCaptureImpl::SuspendCapture
,
169 base::Unretained(impl
), suspend
));
173 } // namespace content