| 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 |