Chromium Code Reviews| Index: content/browser/renderer_host/media/video_capture_controller.cc |
| =================================================================== |
| --- content/browser/renderer_host/media/video_capture_controller.cc (revision 105502) |
| +++ content/browser/renderer_host/media/video_capture_controller.cc (working copy) |
| @@ -11,57 +11,112 @@ |
| #include "content/browser/renderer_host/media/video_capture_manager.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; |
| 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) { |
| + : frame_info_available_(false), |
| + video_capture_manager_(video_capture_manager), |
| + state_(media::VideoCapture::kStopped) { |
| memset(¶ms_, 0, sizeof(params_)); |
| } |
| VideoCaptureController::~VideoCaptureController() { |
| - // Delete all TransportDIBs. |
| + // Delete all DIBs. |
| STLDeleteContainerPairSecondPointers(owned_dibs_.begin(), |
| owned_dibs_.end()); |
| + STLDeleteContainerPointers(controller_clients_.begin(), |
| + controller_clients_.end()); |
| } |
| void VideoCaptureController::StartCapture( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* event_handler, |
| + base::ProcessHandle render_process, |
| const media::VideoCaptureParams& params) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + if (state_ == media::VideoCapture::kError) { |
| + event_handler->OnError(id); |
| + return; |
| + } |
| + if (FindClient(id, event_handler) != controller_clients_.end()) |
| + return; |
| + |
| + ControllerClient* client = new ControllerClient(id, event_handler, |
| + render_process, params); |
| + controller_clients_.push_front(client); |
| + if (state_ == media::VideoCapture::kStarted) { |
|
perkj_chrome
2011/10/17 08:39:43
What if you run webrtc? First you start a local pr
wjia(left Chromium)
2011/10/21 00:56:13
The resolution change in webrtc is handled in rend
|
| + if (frame_info_available_) { |
| + SendFrameInfoAndBuffers(client); |
| + } |
| + return; |
| + } |
| + |
| 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)); |
| + ControllerClients::iterator cit = FindClient(id, event_handler); |
| + if (cit == controller_clients_.end()) |
| + return; |
|
perkj_chrome
2011/10/17 08:39:43
DCHECK ?
wjia(left Chromium)
2011/10/21 00:56:13
Done.
|
| + |
| + if (force_buffer_return) { |
| + for (std::list<int>::iterator bit = (*cit)->buffers.begin(); |
| + bit != (*cit)->buffers.end(); ++bit) { |
| + ReturnBuffer(id, event_handler, *bit); |
| + } |
| + } else { |
| + if ((*cit)->buffers.size() > 0) { |
| + (*cit)->report_ready_to_delete = true; |
| + return; |
| + } |
| + } |
| + |
| + (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); |
| + controller_clients_.erase(cit); |
| + |
| + if (controller_clients_.size() == 0) { |
| + video_capture_manager_->Stop(params_.session_id, base::Closure()); |
|
perkj_chrome
2011/10/17 08:39:43
I think you will need to make sure that the first
mflodman_chromium_OOO
2011/10/19 18:18:23
Or allowing changing settings as long as there is
wjia(left Chromium)
2011/10/21 00:56:13
In the latest design, the final capture resolution
wjia(left Chromium)
2011/10/21 00:56:13
There are two levels of clients: VideoCaptureImpl
|
| + frame_info_available_ = false; |
| + state_ = media::VideoCapture::kStopped; |
| + } |
| } |
| -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; |
| + ControllerClients::iterator cit = FindClient(id, event_handler); |
| + UsedDIBsCount::iterator dit = used_dibs_count_.find(buffer_id); |
| + if (cit == controller_clients_.end() || dit == used_dibs_count_.end()) |
| + return; |
| + |
| + (*cit)->buffers.remove(buffer_id); |
| + if ((*cit)->report_ready_to_delete && (*cit)->buffers.size() == 0) { |
| + (*cit)->event_handler->OnReadyToDelete((*cit)->controller_id); |
| + controller_clients_.erase(cit); |
| + } |
| + if (--dit->second > 0) |
| + return; |
| + |
| + // Now this |buffer_id| is not used by any client. |
| + used_dibs_count_.erase(buffer_id); |
| { |
| base::AutoLock lock(lock_); |
| free_dibs_.push_back(buffer_id); |
| - ready_to_delete = (free_dibs_.size() == owned_dibs_.size()) && |
| - report_ready_to_delete_; |
| } |
| - if (ready_to_delete) { |
| - event_handler_->OnReadyToDelete(id_); |
| - } |
| } |
| /////////////////////////////////////////////////////////////////////////////// |
| @@ -73,11 +128,11 @@ |
| base::Time timestamp) { |
| int buffer_id = 0; |
| base::SharedMemory* dib = NULL; |
| - // Check if there is a TransportDIB to fill. |
| + // Check if there is a DIB to fill. |
| bool buffer_exist = false; |
| { |
| base::AutoLock lock(lock_); |
| - if (!report_ready_to_delete_ && free_dibs_.size() > 0) { |
| + if (free_dibs_.size() > 0) { |
| buffer_id = free_dibs_.front(); |
| free_dibs_.pop_front(); |
| DIBMap::iterator it = owned_dibs_.find(buffer_id); |
| @@ -150,62 +205,167 @@ |
| 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); |
| + 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::OnDeviceState(bool in_use) { |
| + BrowserThread::PostTask(BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&VideoCaptureController::DoDeviceStateOnIOThread, this, |
| + in_use)); |
| +} |
| + |
| +void VideoCaptureController::DoIncomingCapturedFrameOnIOThread( |
| + int buffer_id, base::Time timestamp) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + if (state_ != media::VideoCapture::kStarted) |
| + return; |
| + |
| + int count = 0; |
| + for (ControllerClients::iterator cit = controller_clients_.begin(); |
| + cit != controller_clients_.end(); cit++) { |
| + if ((*cit)->report_ready_to_delete) |
| + continue; |
| + |
| + (*cit)->event_handler->OnBufferReady((*cit)->controller_id, |
| + buffer_id, timestamp); |
| + (*cit)->buffers.push_back(buffer_id); |
| + count++; |
| + } |
| + if (count > 0) { |
| + used_dibs_count_[buffer_id] = count; |
| + } else { |
| + base::AutoLock lock(lock_); |
| + free_dibs_.push_back(buffer_id); |
| + } |
| +} |
| + |
| +void VideoCaptureController::DoErrorOnIOThread() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + state_ = media::VideoCapture::kError; |
| + for (ControllerClients::iterator cit = controller_clients_.begin(); |
| + cit != controller_clients_.end(); cit++) { |
| + (*cit)->event_handler->OnError((*cit)->controller_id); |
| + } |
| +} |
| + |
| +void VideoCaptureController::DoDeviceStateOnIOThread(bool in_use) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + video_capture_manager_->DeviceStatusFromController(this, in_use); |
| +} |
| + |
| +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; |
| + 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; |
| } |
| - base::SharedMemoryHandle remote_handle; |
| - shared_memory->ShareToProcess(render_handle_, &remote_handle); |
| - |
| - 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)); |
| } |
| + // Check whether all DIBs were created successfully. |
| + if (!frames_created) { |
| + state_ = media::VideoCapture::kError; |
| + for (ControllerClients::iterator it = controller_clients_.begin(); |
| + it != controller_clients_.end(); it++) { |
| + (*it)->event_handler->OnError((*it)->controller_id); |
| + } |
| + return; |
| + } |
| frame_info_= info; |
| + frame_info_available_ = true; |
| - // Check that all DIBs where created successfully. |
| - if (!frames_created) { |
| - event_handler_->OnError(id_); |
| + for (ControllerClients::iterator cit = controller_clients_.begin(); |
| + cit != controller_clients_.end(); cit++) { |
| + for (DIBMap::iterator dit = owned_dibs_.begin(); |
| + dit != owned_dibs_.end(); dit++) { |
| + int index = dit->first; |
| + base::SharedMemory* shared_memory = dit->second; |
| + base::SharedMemoryHandle remote_handle; |
| + shared_memory->ShareToProcess((*cit)->render_process_handle, |
| + &remote_handle); |
| + (*cit)->event_handler->OnBufferCreated((*cit)->controller_id, |
| + remote_handle, |
| + static_cast<int>(needed_size), |
| + index); |
| + } |
| + (*cit)->event_handler->OnFrameInfo((*cit)->controller_id, |
| + info.width, info.height, |
| + info.frame_rate); |
| } |
| - event_handler_->OnFrameInfo(id_, info.width, info.height, info.frame_rate); |
| } |
| -/////////////////////////////////////////////////////////////////////////////// |
| -// 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; |
| - |
| - { |
| - 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::SendFrameInfoAndBuffers(ControllerClient* client) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(frame_info_available_); |
| + const size_t needed_size = (frame_info_.width * frame_info_.height * 3) / 2; |
| + base::AutoLock lock(lock_); |
| + for (DIBMap::iterator dit = owned_dibs_.begin(); |
| + dit != owned_dibs_.end(); dit++) { |
| + base::SharedMemory* shared_memory = dit->second; |
| + int index = dit->first; |
| + base::SharedMemoryHandle remote_handle; |
| + shared_memory->ShareToProcess(client->render_process_handle, |
| + &remote_handle); |
| + client->event_handler->OnBufferCreated(client->controller_id, |
| + remote_handle, |
| + static_cast<int>(needed_size), |
| + index); |
| } |
| + client->event_handler->OnFrameInfo(client->controller_id, |
| + frame_info_.width, frame_info_.height, |
| + frame_info_.frame_rate); |
| +} |
| - if (ready_to_delete_now) { |
| - event_handler_->OnReadyToDelete(id_); |
| +VideoCaptureController::ControllerClients::iterator |
| +VideoCaptureController::FindClient( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* handler) { |
| + for (ControllerClients::iterator cit = controller_clients_.begin(); |
| + cit != controller_clients_.end(); cit++) { |
| + if ((*cit)->controller_id == id && (*cit)->event_handler == handler) { |
| + return cit; |
| + } |
| } |
| + return controller_clients_.end(); |
| +} |
| - if (!stopped_cb.is_null()) |
| - stopped_cb.Run(); |
| +VideoCaptureController::ControllerClient::ControllerClient( |
| + const VideoCaptureControllerID& id, |
| + VideoCaptureControllerEventHandler* handler, |
| + base::ProcessHandle render_process, |
| + const media::VideoCaptureParams& params) |
| + : controller_id(id), |
|
scherkus (not reviewing)
2011/10/19 18:02:21
indent by 2 more spaces
wjia(left Chromium)
2011/10/21 00:56:13
Done.
|
| + event_handler(handler), |
| + render_process_handle(render_process), |
| + parameters(params), |
| + report_ready_to_delete(false) { |
| } |
| + |
| +VideoCaptureController::ControllerClient::~ControllerClient() {} |