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() {} |