• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
VideoCaptureImplManager()36 VideoCaptureImplManager::VideoCaptureImplManager()
37     : next_client_id_(0),
38       filter_(new VideoCaptureMessageFilter()),
39       weak_factory_(this) {
40 }
41 
~VideoCaptureImplManager()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 
UseDevice(media::VideoCaptureSessionId id)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 
StartCapture(media::VideoCaptureSessionId id,const media::VideoCaptureParams & params,const VideoCaptureStateUpdateCB & state_update_cb,const VideoCaptureDeliverFrameCB & deliver_frame_cb)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 
GetDeviceSupportedFormats(media::VideoCaptureSessionId id,const VideoCaptureDeviceFormatsCB & callback)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 
GetDeviceFormatsInUse(media::VideoCaptureSessionId id,const VideoCaptureDeviceFormatsCB & 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(
131       FROM_HERE,
132       base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
133                  base::Unretained(impl), callback));
134 }
135 
136 VideoCaptureImpl*
CreateVideoCaptureImplForTesting(media::VideoCaptureSessionId id,VideoCaptureMessageFilter * filter) const137 VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
138     media::VideoCaptureSessionId id,
139     VideoCaptureMessageFilter* filter) const {
140   return NULL;
141 }
142 
StopCapture(int client_id,media::VideoCaptureSessionId id)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 
UnrefDevice(media::VideoCaptureSessionId 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;
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 
SuspendDevices(bool suspend)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