OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/media/video_capture_controller.h" | 5 #include "content/browser/renderer_host/media/video_capture_controller.h" |
6 | 6 |
| 7 #include <set> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
9 #include "base/stl_util.h" | 11 #include "base/stl_util.h" |
10 #include "content/browser/renderer_host/media/media_stream_manager.h" | 12 #include "content/browser/renderer_host/media/media_stream_manager.h" |
11 #include "content/browser/renderer_host/media/video_capture_manager.h" | 13 #include "content/browser/renderer_host/media/video_capture_manager.h" |
12 #include "content/public/browser/browser_thread.h" | 14 #include "content/public/browser/browser_thread.h" |
13 #include "media/base/yuv_convert.h" | 15 #include "media/base/yuv_convert.h" |
14 | 16 |
15 using content::BrowserThread; | 17 using content::BrowserThread; |
16 | 18 |
17 // The number of DIBs VideoCaptureController allocate. | 19 // The number of DIBs VideoCaptureController allocate. |
18 static const size_t kNoOfDIBS = 3; | 20 static const size_t kNoOfDIBS = 3; |
19 | 21 |
20 struct VideoCaptureController::ControllerClient { | 22 struct VideoCaptureController::ControllerClient { |
21 ControllerClient( | 23 ControllerClient( |
22 const VideoCaptureControllerID& id, | 24 const VideoCaptureControllerID& id, |
23 VideoCaptureControllerEventHandler* handler, | 25 VideoCaptureControllerEventHandler* handler, |
24 base::ProcessHandle render_process, | 26 base::ProcessHandle render_process, |
25 const media::VideoCaptureParams& params) | 27 const media::VideoCaptureParams& params) |
26 : controller_id(id), | 28 : controller_id(id), |
27 event_handler(handler), | 29 event_handler(handler), |
28 render_process_handle(render_process), | 30 render_process_handle(render_process), |
29 parameters(params), | 31 parameters(params), |
30 session_closed(false), | 32 session_closed(false) { |
31 report_ready_to_delete(false) { | |
32 } | 33 } |
33 | 34 |
34 ~ControllerClient() {} | 35 ~ControllerClient() {} |
35 | 36 |
36 // ID used for identifying this object. | 37 // ID used for identifying this object. |
37 VideoCaptureControllerID controller_id; | 38 VideoCaptureControllerID controller_id; |
38 VideoCaptureControllerEventHandler* event_handler; | 39 VideoCaptureControllerEventHandler* event_handler; |
39 | 40 |
40 // Handle to the render process that will receive the DIBs. | 41 // Handle to the render process that will receive the DIBs. |
41 base::ProcessHandle render_process_handle; | 42 base::ProcessHandle render_process_handle; |
42 media::VideoCaptureParams parameters; | 43 media::VideoCaptureParams parameters; |
43 | 44 |
44 // Buffers used by this client. | 45 // Buffers used by this client. |
45 std::list<int> buffers; | 46 std::set<int> buffers; |
46 | 47 |
47 // State of capture session, controlled by VideoCaptureManager directly. | 48 // State of capture session, controlled by VideoCaptureManager directly. |
48 bool session_closed; | 49 bool session_closed; |
49 | |
50 // Record client's status when it has called StopCapture, but haven't | |
51 // returned all buffers. | |
52 bool report_ready_to_delete; | |
53 }; | 50 }; |
54 | 51 |
55 struct VideoCaptureController::SharedDIB { | 52 struct VideoCaptureController::SharedDIB { |
56 SharedDIB(base::SharedMemory* ptr) | 53 SharedDIB(base::SharedMemory* ptr) |
57 : shared_memory(ptr), | 54 : shared_memory(ptr), |
58 references(0) { | 55 references(0) { |
59 } | 56 } |
60 | 57 |
61 ~SharedDIB() {} | 58 ~SharedDIB() {} |
62 | 59 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 controller_clients_.push_back(client); | 135 controller_clients_.push_back(client); |
139 current_params_ = params; | 136 current_params_ = params; |
140 // Order the manager to start the actual capture. | 137 // Order the manager to start the actual capture. |
141 video_capture_manager_->Start(params, this); | 138 video_capture_manager_->Start(params, this); |
142 state_ = video_capture::kStarted; | 139 state_ = video_capture::kStarted; |
143 device_in_use_ = true; | 140 device_in_use_ = true; |
144 } | 141 } |
145 | 142 |
146 void VideoCaptureController::StopCapture( | 143 void VideoCaptureController::StopCapture( |
147 const VideoCaptureControllerID& id, | 144 const VideoCaptureControllerID& id, |
148 VideoCaptureControllerEventHandler* event_handler, | 145 VideoCaptureControllerEventHandler* event_handler) { |
149 bool force_buffer_return) { | |
150 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
151 DVLOG(1) << "VideoCaptureController::StopCapture, id " << id.device_id; | 147 DVLOG(1) << "VideoCaptureController::StopCapture, id " << id.device_id; |
152 | 148 |
153 ControllerClient* client = FindClient(id, event_handler, pending_clients_); | 149 ControllerClient* client = FindClient(id, event_handler, pending_clients_); |
154 // If the client is still in pending queue, just remove it. | 150 // If the client is still in pending queue, just remove it. |
155 if (client) { | 151 if (client) { |
156 client->event_handler->OnReadyToDelete(client->controller_id); | |
157 pending_clients_.remove(client); | 152 pending_clients_.remove(client); |
158 return; | 153 return; |
159 } | 154 } |
160 | 155 |
161 client = FindClient(id, event_handler, controller_clients_); | 156 client = FindClient(id, event_handler, controller_clients_); |
162 DCHECK(client) << "Client should have called StartCapture()"; | 157 if (!client) |
| 158 return; |
163 | 159 |
164 if (force_buffer_return) { | 160 // Take back all buffers held by the |client|. |
165 // The client requests to return buffers which means it can't return | 161 for (std::set<int>::iterator buffer_it = client->buffers.begin(); |
166 // buffers normally. After buffers are returned, client is free to | 162 buffer_it != client->buffers.end(); ++buffer_it) { |
167 // delete itself. No need to call OnReadyToDelete. | 163 int buffer_id = *buffer_it; |
| 164 DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); |
| 165 if (dib_it == owned_dibs_.end()) |
| 166 continue; |
168 | 167 |
169 // Return all buffers held by the clients. | 168 { |
170 for (std::list<int>::iterator buffer_it = client->buffers.begin(); | 169 base::AutoLock lock(lock_); |
171 buffer_it != client->buffers.end(); ++buffer_it) { | 170 DCHECK_GT(dib_it->second->references, 0) |
172 int buffer_id = *buffer_it; | 171 << "The buffer is not used by renderer."; |
173 DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); | 172 dib_it->second->references -= 1; |
174 if (dib_it == owned_dibs_.end()) | |
175 continue; | |
176 | |
177 { | |
178 base::AutoLock lock(lock_); | |
179 DCHECK_GT(dib_it->second->references, 0) | |
180 << "The buffer is not used by renderer."; | |
181 dib_it->second->references -= 1; | |
182 } | |
183 } | 173 } |
184 client->buffers.clear(); | |
185 } else { | |
186 // Normal way to stop capture. | |
187 if (!client->buffers.empty()) { | |
188 // There are still some buffers held by the client. | |
189 client->report_ready_to_delete = true; | |
190 return; | |
191 } | |
192 // No buffer is held by the client. Ready to delete. | |
193 client->event_handler->OnReadyToDelete(client->controller_id); | |
194 } | 174 } |
| 175 client->buffers.clear(); |
195 | 176 |
196 int session_id = client->parameters.session_id; | 177 int session_id = client->parameters.session_id; |
197 delete client; | 178 delete client; |
198 controller_clients_.remove(client); | 179 controller_clients_.remove(client); |
199 | 180 |
200 // No more clients. Stop device. | 181 // No more clients. Stop device. |
201 if (controller_clients_.empty()) { | 182 if (controller_clients_.empty() && state_ == video_capture::kStarted) { |
202 video_capture_manager_->Stop(session_id, | 183 video_capture_manager_->Stop(session_id, |
203 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); | 184 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); |
204 frame_info_available_ = false; | 185 frame_info_available_ = false; |
205 state_ = video_capture::kStopping; | 186 state_ = video_capture::kStopping; |
206 } | 187 } |
207 } | 188 } |
208 | 189 |
209 void VideoCaptureController::StopSession( | 190 void VideoCaptureController::StopSession( |
210 int session_id) { | 191 int session_id) { |
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
(...skipping 13 matching lines...) Expand all Loading... |
225 const VideoCaptureControllerID& id, | 206 const VideoCaptureControllerID& id, |
226 VideoCaptureControllerEventHandler* event_handler, | 207 VideoCaptureControllerEventHandler* event_handler, |
227 int buffer_id) { | 208 int buffer_id) { |
228 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
229 | 210 |
230 ControllerClient* client = FindClient(id, event_handler, | 211 ControllerClient* client = FindClient(id, event_handler, |
231 controller_clients_); | 212 controller_clients_); |
232 DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); | 213 DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); |
233 // If this buffer is not held by this client, or this client doesn't exist | 214 // If this buffer is not held by this client, or this client doesn't exist |
234 // in controller, do nothing. | 215 // in controller, do nothing. |
235 if (!client || dib_it == owned_dibs_.end()) | 216 if (!client || |
| 217 client->buffers.find(buffer_id) == client->buffers.end() || |
| 218 dib_it == owned_dibs_.end()) |
236 return; | 219 return; |
237 | 220 |
238 client->buffers.remove(buffer_id); | 221 client->buffers.erase(buffer_id); |
239 // If this client has called StopCapture and doesn't hold any buffer after | |
240 // after this return, ready to delete this client. | |
241 if (client->report_ready_to_delete && client->buffers.empty()) { | |
242 client->event_handler->OnReadyToDelete(client->controller_id); | |
243 delete client; | |
244 controller_clients_.remove(client); | |
245 | |
246 if (controller_clients_.empty()) { | |
247 // No more clients. Stop device. | |
248 video_capture_manager_->Stop(current_params_.session_id, | |
249 base::Bind(&VideoCaptureController::OnDeviceStopped, this)); | |
250 frame_info_available_ = false; | |
251 state_ = video_capture::kStopping; | |
252 } | |
253 } | |
254 { | 222 { |
255 base::AutoLock lock(lock_); | 223 base::AutoLock lock(lock_); |
256 DCHECK_GT(dib_it->second->references, 0) | 224 DCHECK_GT(dib_it->second->references, 0) |
257 << "The buffer is not used by renderer."; | 225 << "The buffer is not used by renderer."; |
258 dib_it->second->references -= 1; | 226 dib_it->second->references -= 1; |
259 if (dib_it->second->references > 0) | 227 if (dib_it->second->references > 0) |
260 return; | 228 return; |
261 } | 229 } |
262 | 230 |
263 // When all buffers have been returned by clients and device has been | 231 // When all buffers have been returned by clients and device has been |
264 // called to stop, check if restart is needed. This could happen when | 232 // called to stop, check if restart is needed. This could happen when |
265 // some clients call StopCapture before returning all buffers. | 233 // capture needs to be restarted due to resolution change. |
266 if (!ClientHasDIB() && state_ == video_capture::kStopping) { | 234 if (!ClientHasDIB() && state_ == video_capture::kStopping) { |
267 PostStopping(); | 235 PostStopping(); |
268 } | 236 } |
269 } | 237 } |
270 | 238 |
271 /////////////////////////////////////////////////////////////////////////////// | 239 /////////////////////////////////////////////////////////////////////////////// |
272 // Implements VideoCaptureDevice::EventHandler. | 240 // Implements VideoCaptureDevice::EventHandler. |
273 // OnIncomingCapturedFrame is called the thread running the capture device. | 241 // OnIncomingCapturedFrame is called the thread running the capture device. |
274 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. | 242 // I.e.- DirectShow thread on windows and v4l2_thread on Linux. |
275 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, | 243 void VideoCaptureController::OnIncomingCapturedFrame(const uint8* data, |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 } | 365 } |
398 | 366 |
399 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( | 367 void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( |
400 int buffer_id, base::Time timestamp) { | 368 int buffer_id, base::Time timestamp) { |
401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 369 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
402 | 370 |
403 int count = 0; | 371 int count = 0; |
404 if (state_ == video_capture::kStarted) { | 372 if (state_ == video_capture::kStarted) { |
405 for (ControllerClients::iterator client_it = controller_clients_.begin(); | 373 for (ControllerClients::iterator client_it = controller_clients_.begin(); |
406 client_it != controller_clients_.end(); client_it++) { | 374 client_it != controller_clients_.end(); client_it++) { |
407 if ((*client_it)->report_ready_to_delete || | 375 if ((*client_it)->session_closed) |
408 (*client_it)->session_closed) | |
409 continue; | 376 continue; |
410 | 377 |
411 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, | 378 (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, |
412 buffer_id, timestamp); | 379 buffer_id, timestamp); |
413 (*client_it)->buffers.push_back(buffer_id); | 380 (*client_it)->buffers.insert(buffer_id); |
414 count++; | 381 count++; |
415 } | 382 } |
416 } | 383 } |
417 | 384 |
418 base::AutoLock lock(lock_); | 385 base::AutoLock lock(lock_); |
419 if (owned_dibs_.find(buffer_id) != owned_dibs_.end()) { | 386 if (owned_dibs_.find(buffer_id) != owned_dibs_.end()) { |
420 DCHECK_EQ(owned_dibs_[buffer_id]->references, -1); | 387 DCHECK_EQ(owned_dibs_[buffer_id]->references, -1); |
421 owned_dibs_[buffer_id]->references = count; | 388 owned_dibs_[buffer_id]->references = count; |
422 } | 389 } |
423 } | 390 } |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 bool VideoCaptureController::ClientHasDIB() { | 549 bool VideoCaptureController::ClientHasDIB() { |
583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
584 base::AutoLock lock(lock_); | 551 base::AutoLock lock(lock_); |
585 for (DIBMap::iterator dib_it = owned_dibs_.begin(); | 552 for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
586 dib_it != owned_dibs_.end(); dib_it++) { | 553 dib_it != owned_dibs_.end(); dib_it++) { |
587 if (dib_it->second->references > 0) | 554 if (dib_it->second->references > 0) |
588 return true; | 555 return true; |
589 } | 556 } |
590 return false; | 557 return false; |
591 } | 558 } |
OLD | NEW |