Chromium Code Reviews| Index: content/browser/renderer_host/media/video_capture_controller.cc |
| =================================================================== |
| --- content/browser/renderer_host/media/video_capture_controller.cc (revision 107874) |
| +++ content/browser/renderer_host/media/video_capture_controller.cc (working copy) |
| @@ -11,56 +11,229 @@ |
| #include "content/public/browser/browser_thread.h" |
| #include "media/base/yuv_convert.h" |
| -// The number of TransportDIBs VideoCaptureController allocate. |
| +// The number of DIBs VideoCaptureController allocate. |
| static const size_t kNoOfDIBS = 3; |
| +struct VideoCaptureController::ControllerClient { |
| + ControllerClient( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* handler, |
| + base::ProcessHandle render_process, |
| + const media::VideoCaptureParams& params) |
| + : controller_id(id), |
| + event_handler(handler), |
| + render_process_handle(render_process), |
| + parameters(params), |
| + report_ready_to_delete(false) { |
| + } |
| + |
| + ~ControllerClient() {} |
| + |
| + // ID used for identifying this object. |
| + VideoCaptureControllerID controller_id; |
| + VideoCaptureControllerEventHandler* event_handler; |
| + |
| + // Handle to the render process that will receive the DIBs. |
| + base::ProcessHandle render_process_handle; |
| + media::VideoCaptureParams parameters; |
| + |
| + // Buffers used by this client. |
| + std::list<int> buffers; |
| + |
| + // Record client's status when it has called StopCapture, but haven't |
| + // returned all buffers. |
| + bool report_ready_to_delete; |
| +}; |
| + |
| +struct VideoCaptureController::SharedDIB { |
| + SharedDIB(base::SharedMemory* ptr) |
| + : shared_memory(ptr), |
| + references(0) { |
| + } |
| + |
| + ~SharedDIB() {} |
| + |
| + scoped_ptr<base::SharedMemory> shared_memory; |
| + int references; |
|
scherkus (not reviewing)
2011/11/01 02:18:38
documentation for these fields
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| +}; |
| + |
| VideoCaptureController::VideoCaptureController( |
| - const VideoCaptureControllerID& id, |
| - base::ProcessHandle render_process, |
| - VideoCaptureControllerEventHandler* event_handler, |
| media_stream::VideoCaptureManager* video_capture_manager) |
| - : render_handle_(render_process), |
| - report_ready_to_delete_(false), |
| - event_handler_(event_handler), |
| - id_(id), |
| - video_capture_manager_(video_capture_manager) { |
| - memset(¶ms_, 0, sizeof(params_)); |
| + : frame_info_available_(false), |
| + video_capture_manager_(video_capture_manager), |
| + device_in_use_(false), |
| + state_(media::VideoCapture::kStopped) { |
| + memset(¤t_params_, 0, sizeof(current_params_)); |
| } |
| VideoCaptureController::~VideoCaptureController() { |
| - // Delete all TransportDIBs. |
| + // Delete all DIBs. |
| STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), |
| owned_dibs_.end()); |
| + STLDeleteContainerPointers(controller_clients_.begin(), |
| + controller_clients_.end()); |
| + STLDeleteContainerPointers(pending_clients_.begin(), |
| + pending_clients_.end()); |
| } |
| void VideoCaptureController::StartCapture( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* event_handler, |
| + base::ProcessHandle render_process, |
| const media::VideoCaptureParams& params) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + // Signal error in case device is already in error state. |
| + if (state_ == media::VideoCapture::kError) { |
| + event_handler->OnError(id); |
| + return; |
| + } |
| - params_ = params; |
| + // Do nothing if this client has called StartCapture before. |
| + if (FindClient(id, event_handler, controller_clients_) || |
| + FindClient(id, event_handler, pending_clients_)) |
| + return; |
| + |
| + ControllerClient* client = new ControllerClient(id, event_handler, |
| + render_process, params); |
| + // In case capture has been started, need to check different condtions. |
| + if (state_ == media::VideoCapture::kStarted) { |
| + // This client has higher resolution than what is currently requested. |
| + // Need restart capturing. |
| + if (params.width > current_params_.width || |
| + params.height > current_params_.height) { |
| + video_capture_manager_->Stop(current_params_.session_id, |
| + base::Bind(&VideoCaptureController::OnDeviceStopped, this)); |
| + frame_info_available_ = false; |
| + state_ = media::VideoCapture::kStopping; |
| + pending_clients_.push_back(client); |
| + return; |
| + } |
| + |
| + // This client's resolution is no larger than what's currently requested. |
| + // When frame_info has been returned by device, send them to client. |
| + if (frame_info_available_) { |
| + int buffer_size = (frame_info_.width * frame_info_.height * 3) / 2; |
| + SendFrameInfoAndBuffers(client, buffer_size); |
| + } |
| + controller_clients_.push_back(client); |
| + return; |
| + } |
| + |
| + // In case the device is in the middle of stopping, put the client in |
| + // pending queue. |
| + if (state_ == media::VideoCapture::kStopping) { |
| + pending_clients_.push_back(client); |
| + return; |
| + } |
| + |
| + // Fresh start. |
| + controller_clients_.push_back(client); |
| + current_params_ = params; |
| // Order the manager to start the actual capture. |
| video_capture_manager_->Start(params, this); |
| + state_ = media::VideoCapture::kStarted; |
| } |
| -void VideoCaptureController::StopCapture(base::Closure stopped_cb) { |
| +void VideoCaptureController::StopCapture( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* event_handler, |
| + bool force_buffer_return) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - video_capture_manager_->Stop(params_.session_id, |
| - base::Bind(&VideoCaptureController::OnDeviceStopped, this, stopped_cb)); |
| + ControllerClient* client = FindClient(id, event_handler, pending_clients_); |
| + // If the client is still in pending queue, just remove it. |
| + if (client) { |
| + client->event_handler->OnReadyToDelete(client->controller_id); |
| + pending_clients_.remove(client); |
| + return; |
| + } |
| + |
| + client = FindClient(id, event_handler, controller_clients_); |
| + // The client should have called StartCapture. |
| + DCHECK(client); |
|
scherkus (not reviewing)
2011/11/01 02:18:38
what about making the comment into a string?
DCHE
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + |
| + if (force_buffer_return) { |
| + // The client requests to return buffers which means it can't return |
| + // buffers normally. After buffers are returned, client is free to |
| + // delete itself. No need to call OnReadyToDelete. |
| + |
| + // Return all buffers held by the clients. |
| + for (std::list<int>::iterator buffer_it = client->buffers.begin(); |
| + buffer_it != client->buffers.end(); ++buffer_it) { |
| + int buffer_id = *buffer_it; |
| + DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); |
| + if (dib_it == owned_dibs_.end()) |
| + continue; |
| + |
| + if (--dib_it->second->references > 0) |
|
scherkus (not reviewing)
2011/11/01 02:18:38
from a quick glance this isn't very clear -- what
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + continue; |
| + |
| + // Now this |buffer_id| is not used by any client. |
| + { |
| + base::AutoLock lock(lock_); |
| + free_dibs_.push_back(buffer_id); |
|
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + } |
| + } |
| + client->buffers.clear(); |
| + } else { |
| + // Normal way to stop capture. |
| + if (!client->buffers.empty()) { |
| + // There are still some buffers held by the client. |
| + client->report_ready_to_delete = true; |
| + return; |
| + } |
| + // No buffer is held by the client. Ready to delete. |
| + client->event_handler->OnReadyToDelete(client->controller_id); |
| + } |
| + |
| + delete client; |
| + controller_clients_.remove(client); |
| + |
| + // No more clients. Stop device. |
| + if (controller_clients_.empty()) { |
| + video_capture_manager_->Stop(current_params_.session_id, |
| + base::Bind(&VideoCaptureController::OnDeviceStopped, this)); |
| + frame_info_available_ = false; |
| + state_ = media::VideoCapture::kStopping; |
| + } |
| } |
| -void VideoCaptureController::ReturnBuffer(int buffer_id) { |
| +void VideoCaptureController::ReturnBuffer( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* event_handler, |
| + int buffer_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - bool ready_to_delete; |
| + ControllerClient* client = FindClient(id, event_handler, |
| + controller_clients_); |
|
scherkus (not reviewing)
2011/11/01 02:18:38
indentation
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + DIBMap::iterator dib_it = owned_dibs_.find(buffer_id); |
| + // If this buffer is not held by this client, or this client doesn't exist |
| + // in controller, do nothing. |
| + if (!client || dib_it == owned_dibs_.end()) |
| + return; |
| + |
| + client->buffers.remove(buffer_id); |
| + // If this client has called StopCapture and doesn't hold any buffer after |
| + // after this return, ready to delete this client. |
| + if (client->report_ready_to_delete && client->buffers.empty()) { |
| + client->event_handler->OnReadyToDelete(client->controller_id); |
| + delete client; |
| + controller_clients_.remove(client); |
| + } |
| + if (--dib_it->second->references > 0) |
|
scherkus (not reviewing)
2011/11/01 02:18:38
ditto
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + return; |
| + |
| + // Now this |buffer_id| is not used by any client. |
| { |
| base::AutoLock lock(lock_); |
| free_dibs_.push_back(buffer_id); |
|
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| - ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && |
| - report_ready_to_delete_; |
| } |
| - if (ready_to_delete) { |
| - event_handler_->OnReadyToDelete(id_); |
| + |
| + // When all buffers have been returned by clients and device has been |
| + // called to stop, check if restart is needed. This could happen when |
| + // some clients call StopCapture before returning all buffers. |
| + if (!ClientHasDIB() && state_ == media::VideoCapture::kStopping) { |
| + PostStopping(); |
| } |
| } |
| @@ -73,22 +246,19 @@ |
| base::Time timestamp) { |
| int buffer_id = 0; |
| base::SharedMemory* dib = NULL; |
| - // Check if there is a TransportDIB to fill. |
| - bool buffer_exist = false; |
| { |
| base::AutoLock lock(lock_); |
| - if (!report_ready_to_delete_ && free_dibs_.size() > 0) { |
| + if (!free_dibs_.empty()) { |
|
scherkus (not reviewing)
2011/11/01 02:18:38
using free_dibs_ isn't really any more efficient b
wjia(left Chromium)
2011/11/01 21:34:23
removed free_dibss_. I have to use a special value
|
| buffer_id = free_dibs_.front(); |
| free_dibs_.pop_front(); |
| DIBMap::iterator it = owned_dibs_.find(buffer_id); |
| if (it != owned_dibs_.end()) { |
| - dib = it->second; |
| - buffer_exist = true; |
| + dib = it->second->shared_memory.get(); |
| } |
| } |
| } |
| - if (!buffer_exist) { |
| + if (!dib) { |
| return; |
| } |
| @@ -96,6 +266,9 @@ |
| CHECK(dib->created_size() >= static_cast<size_t> (frame_info_.width * |
| frame_info_.height * 3) / |
| 2); |
| + uint8* yplane = target; |
| + uint8* uplane = target + frame_info_.width * frame_info_.height; |
| + uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
| // Do color conversion from the camera format to I420. |
| switch (frame_info_.color) { |
| @@ -106,29 +279,18 @@ |
| break; |
| } |
| case media::VideoCaptureDevice::kYUY2: { |
| - uint8* yplane = target; |
| - uint8* uplane = target + frame_info_.width * frame_info_.height; |
| - uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
| media::ConvertYUY2ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| frame_info_.height); |
| break; |
| } |
| case media::VideoCaptureDevice::kRGB24: { |
| -#if defined(OS_WIN) // RGB on Windows start at the bottom line. |
| - uint8* yplane = target; |
| - uint8* uplane = target + frame_info_.width * frame_info_.height; |
| - uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
| int ystride = frame_info_.width; |
| int uvstride = frame_info_.width / 2; |
| - int rgb_stride = - 3 * frame_info_.width; |
| +#if defined(OS_WIN) // RGB on Windows start at the bottom line. |
| + int rgb_stride = -3 * frame_info_.width; |
| const uint8* rgb_src = data + 3 * frame_info_.width * |
| (frame_info_.height -1); |
| #else |
| - uint8* yplane = target; |
| - uint8* uplane = target + frame_info_.width * frame_info_.height; |
| - uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
| - int ystride = frame_info_.width; |
| - int uvstride = frame_info_.width / 2; |
| int rgb_stride = 3 * frame_info_.width; |
| const uint8* rgb_src = data; |
| #endif |
| @@ -138,9 +300,6 @@ |
| break; |
| } |
| case media::VideoCaptureDevice::kARGB: { |
| - uint8* yplane = target; |
| - uint8* uplane = target + frame_info_.width * frame_info_.height; |
| - uint8* vplane = uplane + (frame_info_.width * frame_info_.height) / 4; |
| media::ConvertRGB32ToYUV(data, yplane, uplane, vplane, frame_info_.width, |
| frame_info_.height, frame_info_.width * 4, |
| frame_info_.width, frame_info_.width / 2); |
| @@ -150,62 +309,215 @@ |
| NOTREACHED(); |
| } |
| - event_handler_->OnBufferReady(id_, buffer_id, timestamp); |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&VideoCaptureController::DoIncomingCapturedFrameOnIOThread, |
| + this, buffer_id, timestamp)); |
| } |
| void VideoCaptureController::OnError() { |
| - event_handler_->OnError(id_); |
| - video_capture_manager_->Error(params_.session_id); |
| + video_capture_manager_->Error(current_params_.session_id); |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&VideoCaptureController::DoErrorOnIOThread, this)); |
| } |
| void VideoCaptureController::OnFrameInfo( |
| const media::VideoCaptureDevice::Capability& info) { |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&VideoCaptureController::DoFrameInfoOnIOThread, |
| + this, info)); |
| +} |
| + |
| +void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( |
| + int buffer_id, base::Time timestamp) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (state_ != media::VideoCapture::kStarted) { |
|
scherkus (not reviewing)
2011/11/01 02:18:38
without free_dibs_ you could rewrite this whole fu
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + base::AutoLock lock(lock_); |
| + free_dibs_.push_back(buffer_id); |
| + return; |
| + } |
| + |
| + int count = 0; |
| + for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| + client_it != controller_clients_.end(); client_it++) { |
| + if ((*client_it)->report_ready_to_delete) |
| + continue; |
| + |
| + (*client_it)->event_handler->OnBufferReady((*client_it)->controller_id, |
| + buffer_id, timestamp); |
| + (*client_it)->buffers.push_back(buffer_id); |
| + count++; |
| + } |
| + if (count > 0) { |
| + owned_dibs_[buffer_id]->references = count; |
| + } else { |
| + base::AutoLock lock(lock_); |
| + free_dibs_.push_back(buffer_id); |
| + } |
| +} |
| + |
| +void VideoCaptureController::DoErrorOnIOThread() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + state_ = media::VideoCapture::kError; |
| + ControllerClients::iterator client_it; |
| + for (client_it = controller_clients_.begin(); |
| + client_it != controller_clients_.end(); client_it++) { |
| + (*client_it)->event_handler->OnError((*client_it)->controller_id); |
| + } |
| + for (client_it = pending_clients_.begin(); |
| + client_it != pending_clients_.end(); client_it++) { |
| + (*client_it)->event_handler->OnError((*client_it)->controller_id); |
| + } |
| +} |
| + |
| +void VideoCaptureController::DoFrameInfoOnIOThread( |
| + const media::VideoCaptureDevice::Capability info) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| DCHECK(owned_dibs_.empty()); |
| + |
| bool frames_created = true; |
| const size_t needed_size = (info.width * info.height * 3) / 2; |
| - for (size_t i = 1; i <= kNoOfDIBS; ++i) { |
| - base::SharedMemory* shared_memory = new base::SharedMemory(); |
| - if (!shared_memory->CreateAndMapAnonymous(needed_size)) { |
| - frames_created = false; |
| - break; |
| + { |
| + base::AutoLock lock(lock_); |
| + for (size_t i = 1; i <= kNoOfDIBS; ++i) { |
| + base::SharedMemory* shared_memory = new base::SharedMemory(); |
| + if (!shared_memory->CreateAndMapAnonymous(needed_size)) { |
| + frames_created = false; |
| + break; |
| + } |
| + SharedDIB* dib = new SharedDIB(shared_memory); |
| + owned_dibs_.insert(std::make_pair(i, dib)); |
| + free_dibs_.push_back(i); |
|
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| } |
| + } |
| + // Check whether all DIBs were created successfully. |
| + if (!frames_created) { |
| + state_ = media::VideoCapture::kError; |
| + for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| + client_it != controller_clients_.end(); client_it++) { |
| + (*client_it)->event_handler->OnError((*client_it)->controller_id); |
| + } |
| + return; |
| + } |
| + frame_info_= info; |
| + frame_info_available_ = true; |
| + |
| + for (ControllerClients::iterator client_it = controller_clients_.begin(); |
| + client_it != controller_clients_.end(); client_it++) { |
| + SendFrameInfoAndBuffers((*client_it), static_cast<int>(needed_size)); |
| + } |
| +} |
| + |
| +void VideoCaptureController::SendFrameInfoAndBuffers( |
| + ControllerClient* client, int buffer_size) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(frame_info_available_); |
| + client->event_handler->OnFrameInfo(client->controller_id, |
| + frame_info_.width, frame_info_.height, |
| + frame_info_.frame_rate); |
| + for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| + dib_it != owned_dibs_.end(); dib_it++) { |
| + base::SharedMemory* shared_memory = dib_it->second->shared_memory.get(); |
| + int index = dib_it->first; |
| base::SharedMemoryHandle remote_handle; |
| - shared_memory->ShareToProcess(render_handle_, &remote_handle); |
| + shared_memory->ShareToProcess(client->render_process_handle, |
| + &remote_handle); |
| + client->event_handler->OnBufferCreated(client->controller_id, |
| + remote_handle, |
| + buffer_size, |
| + index); |
| + } |
| +} |
| - base::AutoLock lock(lock_); |
| - owned_dibs_.insert(std::make_pair(i, shared_memory)); |
| - free_dibs_.push_back(i); |
| - event_handler_->OnBufferCreated(id_, remote_handle, |
| - static_cast<int>(needed_size), |
| - static_cast<int>(i)); |
| +// This function is called when all buffers have been returned to controller, |
| +// or when device is stopped. It decides whether the device needs to be |
| +// restarted. |
| +void VideoCaptureController::PostStopping() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_EQ(state_, media::VideoCapture::kStopping); |
| + |
| + // When clients still have some buffers, or device has not been stopped yet, |
| + // do nothing. |
| + if (ClientHasDIB() || device_in_use_) |
| + return; |
| + |
| + // It's safe to free all DIB's on IO thread since device won't send |
| + // buffer over. |
| + free_dibs_.clear(); |
|
scherkus (not reviewing)
2011/11/01 02:18:38
if you didn't have free_dibs_ this code would go a
wjia(left Chromium)
2011/11/01 21:34:23
Done.
|
| + STLDeleteValues(&owned_dibs_); |
| + |
| + // No more client. Therefore the controller is stopped. |
| + if (controller_clients_.empty() && pending_clients_.empty()) { |
| + state_ = media::VideoCapture::kStopped; |
| + return; |
| } |
| - frame_info_= info; |
| - // Check that all DIBs where created successfully. |
| - if (!frames_created) { |
| - event_handler_->OnError(id_); |
| + // Restart the device. |
| + current_params_.width = 0; |
| + current_params_.height = 0; |
| + ControllerClients::iterator client_it; |
| + for (client_it = controller_clients_.begin(); |
| + client_it != controller_clients_.end(); client_it++) { |
| + if (current_params_.width < (*client_it)->parameters.width) |
| + current_params_.width = (*client_it)->parameters.width; |
| + if (current_params_.height < (*client_it)->parameters.height) |
| + current_params_.height = (*client_it)->parameters.height; |
| } |
| - event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); |
| + for (client_it = pending_clients_.begin(); |
| + client_it != pending_clients_.end(); ) { |
| + if (current_params_.width < (*client_it)->parameters.width) |
| + current_params_.width = (*client_it)->parameters.width; |
| + if (current_params_.height < (*client_it)->parameters.height) |
| + current_params_.height = (*client_it)->parameters.height; |
| + controller_clients_.push_back((*client_it)); |
| + pending_clients_.erase(client_it++); |
| + } |
| + // Request the manager to start the actual capture. |
| + video_capture_manager_->Start(current_params_, this); |
| + state_ = media::VideoCapture::kStarted; |
| } |
| +bool VideoCaptureController::ClientHasDIB() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + for (DIBMap::iterator dib_it = owned_dibs_.begin(); |
| + dib_it != owned_dibs_.end(); dib_it++) { |
| + if (dib_it->second->references > 0) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| +VideoCaptureController::ControllerClient* |
| +VideoCaptureController::FindClient( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* handler, |
| + ControllerClients& clients) { |
| + for (ControllerClients::iterator client_it = clients.begin(); |
| + client_it != clients.end(); client_it++) { |
| + if ((*client_it)->controller_id == id && |
| + (*client_it)->event_handler == handler) { |
| + return *client_it; |
| + } |
| + } |
| + return NULL; |
| +} |
| + |
| /////////////////////////////////////////////////////////////////////////////// |
| // Called by VideoCaptureManager when a device have been stopped. |
| -// This will report to the event handler that this object is ready to be deleted |
| -// if all DIBS have been returned. |
| -void VideoCaptureController::OnDeviceStopped(base::Closure stopped_cb) { |
| - bool ready_to_delete_now; |
| +void VideoCaptureController::OnDeviceStopped() { |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&VideoCaptureController::DoDeviceStoppedOnIOThread, this)); |
| +} |
| - { |
| - base::AutoLock lock(lock_); |
| - // Set flag to indicate we need to report when all DIBs have been returned. |
| - report_ready_to_delete_ = true; |
| - ready_to_delete_now = (free_dibs_.size() == owned_dibs_.size()); |
| +void VideoCaptureController::DoDeviceStoppedOnIOThread() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + device_in_use_ = false; |
| + if (state_ == media::VideoCapture::kStopping) { |
| + PostStopping(); |
| } |
| +} |
| - if (ready_to_delete_now) { |
| - event_handler_->OnReadyToDelete(id_); |
| - } |
| - |
| - if (!stopped_cb.is_null()) |
| - stopped_cb.Run(); |
| -} |