Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1098)

Unified Diff: content/browser/renderer_host/media/video_capture_controller.cc

Issue 8304017: enable video capture to support sharing across multiple renderer processes (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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(&params_, 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() {}

Powered by Google App Engine
This is Rietveld 408576698