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

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

Issue 862063002: Reland Queue commands to the Os to start a video device. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Removed valgrind suppression. crbug/450226 Created 5 years, 11 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_manager.cc
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 617a8696deeacb2c2f8d0ef5e8ceb1b24416b5f7..26b3a701105330ccc00046b00f6848a880ba5e8e 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -4,6 +4,7 @@
#include "content/browser/renderer_host/media/video_capture_manager.h"
+#include <algorithm>
#include <set>
#include "base/bind.h"
@@ -94,6 +95,9 @@ void LogVideoCaptureEvent(VideoCaptureEvent event) {
NUM_VIDEO_CAPTURE_EVENT);
}
+// Counter used for identifying a DeviceRequest to start a capture device.
+static int g_device_start_id = 0;
+
} // namespace
namespace content {
@@ -102,11 +106,48 @@ VideoCaptureManager::DeviceEntry::DeviceEntry(
MediaStreamType stream_type,
const std::string& id,
scoped_ptr<VideoCaptureController> controller)
- : stream_type(stream_type),
+ : serial_id(g_device_start_id++),
+ stream_type(stream_type),
id(id),
- video_capture_controller(controller.Pass()) {}
+ video_capture_controller_(controller.Pass()) {}
+
+VideoCaptureManager::DeviceEntry::~DeviceEntry() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void VideoCaptureManager::DeviceEntry::SetVideoCaptureDevice(
+ scoped_ptr<media::VideoCaptureDevice> device) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ video_capture_device_.swap(device);
+}
+
+scoped_ptr<media::VideoCaptureDevice>
+VideoCaptureManager::DeviceEntry::ReleaseVideoCaptureDevice() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return video_capture_device_.Pass();
+}
+
+VideoCaptureController*
+VideoCaptureManager::DeviceEntry::video_capture_controller() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return video_capture_controller_.get();
+}
+
+media::VideoCaptureDevice*
+VideoCaptureManager::DeviceEntry::video_capture_device() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ return video_capture_device_.get();
+}
-VideoCaptureManager::DeviceEntry::~DeviceEntry() {}
+VideoCaptureManager::CaptureDeviceStartRequest::CaptureDeviceStartRequest(
+ int serial_id,
+ media::VideoCaptureSessionId session_id,
+ const media::VideoCaptureParams& params)
+ : serial_id_(serial_id),
+ session_id_(session_id),
+ params_(params),
+ abort_start_(false) {
+}
VideoCaptureManager::VideoCaptureManager(
@@ -118,6 +159,7 @@ VideoCaptureManager::VideoCaptureManager(
VideoCaptureManager::~VideoCaptureManager() {
DCHECK(devices_.empty());
+ DCHECK(device_start_queue_.empty());
}
void VideoCaptureManager::Register(
@@ -202,7 +244,8 @@ void VideoCaptureManager::Close(int capture_session_id) {
if (existing_device) {
// Remove any client that is still using the session. This is safe to call
// even if there are no clients using the session.
- existing_device->video_capture_controller->StopSession(capture_session_id);
+ existing_device->video_capture_controller()
+ ->StopSession(capture_session_id);
// StopSession() may have removed the last client, so we might need to
// close the device.
@@ -216,22 +259,132 @@ void VideoCaptureManager::Close(int capture_session_id) {
sessions_.erase(session_it);
}
-void VideoCaptureManager::DoStartDeviceOnDeviceThread(
+void VideoCaptureManager::QueueStartDevice(
media::VideoCaptureSessionId session_id,
DeviceEntry* entry,
+ const media::VideoCaptureParams& params) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ device_start_queue_.push_back(
+ CaptureDeviceStartRequest(entry->serial_id, session_id, params));
+ if (device_start_queue_.size() == 1)
+ HandleQueuedStartRequest();
+}
+
+void VideoCaptureManager::DoStopDevice(DeviceEntry* entry) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(std::find(devices_.begin(), devices_.end(), entry) != devices_.end());
+
+ // Find the matching start request.
+ for (DeviceStartQueue::reverse_iterator request =
+ device_start_queue_.rbegin();
+ request != device_start_queue_.rend(); ++request) {
+ if (request->serial_id() == entry->serial_id) {
+ request->set_abort_start();
+ DVLOG(3) << "DoStopDevice, aborting start request for device "
+ << entry->id << " serial_id = " << entry->serial_id;
+ return;
+ }
+ }
+
+ DVLOG(3) << "DoStopDevice. Send stop request for device = " << entry->id
+ << " serial_id = " << entry->serial_id << ".";
+ if (entry->video_capture_device()) {
+ // |entry->video_capture_device| can be null if creating the device fails.
+ device_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
+ base::Passed(entry->ReleaseVideoCaptureDevice())));
+ }
+}
+
+void VideoCaptureManager::HandleQueuedStartRequest() {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ // Remove all start requests that have been aborted.
+ while (device_start_queue_.begin() != device_start_queue_.end() &&
+ device_start_queue_.begin()->abort_start()) {
+ device_start_queue_.pop_front();
+ }
+ DeviceStartQueue::iterator request = device_start_queue_.begin();
+ if (request == device_start_queue_.end())
+ return;
+
+ const int serial_id = request->serial_id();
+ DeviceEntries::iterator entry_it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [serial_id] (const DeviceEntry* e) {
+ return e->serial_id == serial_id;
+ });
+ DCHECK(entry_it != devices_.end());
+ DeviceEntry* entry = (*entry_it);
+
+ DVLOG(3) << "HandleQueuedStartRequest, Post start to device thread, device = "
+ << entry->id << " start id = " << entry->serial_id;
+ base::PostTaskAndReplyWithResult(
+ device_task_runner_.get(),
+ FROM_HERE,
+ base::Bind(
+ &VideoCaptureManager::DoStartDeviceOnDeviceThread,
+ this,
+ request->session_id(),
+ entry->id,
+ entry->stream_type,
+ request->params(),
+ base::Passed(entry->video_capture_controller()->NewDeviceClient())),
+ base::Bind(&VideoCaptureManager::OnDeviceStarted, this,
+ request->serial_id()));
+}
+
+void VideoCaptureManager::OnDeviceStarted(
+ int serial_id,
+ scoped_ptr<media::VideoCaptureDevice> device) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(serial_id == device_start_queue_.begin()->serial_id());
+ DVLOG(3) << "OnDeviceStarted";
+ if (device_start_queue_.front().abort_start()) {
+ // |device| can be null if creation failed in DoStartDeviceOnDeviceThread.
+ // The device is no longer wanted. Stop the device again.
+ DVLOG(3) << "OnDeviceStarted but start request have been aborted.";
+ media::VideoCaptureDevice* device_ptr = device.get();
+ base::Closure closure =
+ base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
+ base::Passed(&device));
+ if (device_ptr && !device_task_runner_->PostTask(FROM_HERE, closure)) {
+ // PostTask failed. The device must be stopped anyway.
+ device_ptr->StopAndDeAllocate();
+ }
+ } else {
+ DeviceEntries::iterator entry_it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [serial_id] (const DeviceEntry* e) {
+ return e->serial_id == serial_id;
+ });
+ DCHECK(entry_it != devices_.end());
+ DCHECK(!(*entry_it)->video_capture_device());
+ (*entry_it)->SetVideoCaptureDevice(device.Pass());
+ }
+
+ device_start_queue_.pop_front();
+ HandleQueuedStartRequest();
+}
+
+scoped_ptr<media::VideoCaptureDevice>
+VideoCaptureManager::DoStartDeviceOnDeviceThread(
+ media::VideoCaptureSessionId session_id,
+ const std::string& id,
+ MediaStreamType stream_type,
const media::VideoCaptureParams& params,
scoped_ptr<media::VideoCaptureDevice::Client> device_client) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
DCHECK(IsOnDeviceThread());
scoped_ptr<media::VideoCaptureDevice> video_capture_device;
- switch (entry->stream_type) {
+ switch (stream_type) {
case MEDIA_DEVICE_VIDEO_CAPTURE: {
// We look up the device id from the renderer in our local enumeration
// since the renderer does not have all the information that might be
// held in the browser-side VideoCaptureDevice::Name structure.
media::VideoCaptureDeviceInfo* found =
- FindDeviceInfoById(entry->id, devices_info_cache_);
+ FindDeviceInfoById(id, devices_info_cache_);
if (found) {
video_capture_device =
video_capture_device_factory_->Create(found->name);
@@ -240,20 +393,21 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
}
case MEDIA_TAB_VIDEO_CAPTURE: {
video_capture_device.reset(
- WebContentsVideoCaptureDevice::Create(entry->id));
+ WebContentsVideoCaptureDevice::Create(id));
break;
}
case MEDIA_DESKTOP_VIDEO_CAPTURE: {
#if defined(ENABLE_SCREEN_CAPTURE)
- DesktopMediaID id = DesktopMediaID::Parse(entry->id);
+ DesktopMediaID desktop_id = DesktopMediaID::Parse(id);
#if defined(USE_AURA)
- if (id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
- video_capture_device.reset(DesktopCaptureDeviceAura::Create(id));
+ if (desktop_id.type == DesktopMediaID::TYPE_AURA_WINDOW) {
+ video_capture_device.reset(
+ DesktopCaptureDeviceAura::Create(desktop_id));
} else
#endif
- if (id.type != DesktopMediaID::TYPE_NONE &&
- id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
- video_capture_device = DesktopCaptureDevice::Create(id);
+ if (desktop_id.type != DesktopMediaID::TYPE_NONE &&
+ desktop_id.type != DesktopMediaID::TYPE_AURA_WINDOW) {
+ video_capture_device = DesktopCaptureDevice::Create(desktop_id);
if (notification_window_ids_.find(session_id) !=
notification_window_ids_.end()) {
static_cast<DesktopCaptureDevice*>(video_capture_device.get())
@@ -273,11 +427,11 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
if (!video_capture_device) {
device_client->OnError("Could not create capture device");
- return;
+ return nullptr;
}
video_capture_device->AllocateAndStart(params, device_client.Pass());
- entry->video_capture_device = video_capture_device.Pass();
+ return video_capture_device.Pass();
}
void VideoCaptureManager::StartCaptureForClient(
@@ -298,28 +452,19 @@ void VideoCaptureManager::StartCaptureForClient(
return;
}
- DCHECK(entry->video_capture_controller);
+ DCHECK(entry->video_capture_controller());
LogVideoCaptureEvent(VIDEO_CAPTURE_START_CAPTURE);
// First client starts the device.
- if (entry->video_capture_controller->GetActiveClientCount() == 0) {
+ if (entry->video_capture_controller()->GetActiveClientCount() == 0) {
DVLOG(1) << "VideoCaptureManager starting device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
-
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &VideoCaptureManager::DoStartDeviceOnDeviceThread,
- this,
- session_id,
- entry,
- params,
- base::Passed(entry->video_capture_controller->NewDeviceClient())));
+ QueueStartDevice(session_id, entry, params);
}
// Run the callback first, as AddClient() may trigger OnFrameInfo().
- done_cb.Run(entry->video_capture_controller->GetWeakPtr());
- entry->video_capture_controller->AddClient(
+ done_cb.Run(entry->video_capture_controller()->GetWeakPtr());
+ entry->video_capture_controller()->AddClient(
client_id, client_handler, client_render_process, session_id, params);
}
@@ -392,10 +537,7 @@ void VideoCaptureManager::PauseCaptureForClient(
return;
// There is no more client, release the camera.
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
- base::Unretained(entry)));
+ DoStopDevice(entry);
}
void VideoCaptureManager::ResumeCaptureForClient(
@@ -423,15 +565,7 @@ void VideoCaptureManager::ResumeCaptureForClient(
return;
// This is first active client, allocate the camera.
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(
- &VideoCaptureManager::DoStartDeviceOnDeviceThread,
- this,
- session_id,
- entry,
- params,
- base::Passed(entry->video_capture_controller->NewDeviceClient())));
+ QueueStartDevice(session_id, entry, params);
}
bool VideoCaptureManager::GetDeviceSupportedFormats(
@@ -470,7 +604,7 @@ bool VideoCaptureManager::GetDeviceFormatsInUse(
if (device_in_use) {
// Currently only one format-in-use is supported at the VCC level.
formats_in_use->push_back(
- device_in_use->video_capture_controller->GetVideoCaptureFormat());
+ device_in_use->video_capture_controller()->GetVideoCaptureFormat());
}
return true;
}
@@ -509,21 +643,23 @@ void VideoCaptureManager::SetDesktopCaptureWindowId(
return;
}
+ // Post |existing_device->video_capture_device| to the VideoCaptureDevice to
+ // the device_task_runner_. This is safe since the device is destroyed on the
+ // device_task_runner_.
device_task_runner_->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread,
this,
- existing_device,
+ existing_device->video_capture_device(),
window_id));
}
-void VideoCaptureManager::DoStopDeviceOnDeviceThread(DeviceEntry* entry) {
+void VideoCaptureManager::DoStopDeviceOnDeviceThread(
+ scoped_ptr<media::VideoCaptureDevice> device) {
SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
DCHECK(IsOnDeviceThread());
- if (entry->video_capture_device) {
- entry->video_capture_device->StopAndDeAllocate();
- }
- entry->video_capture_device.reset();
+ device->StopAndDeAllocate();
+ DVLOG(3) << "DoStopDeviceOnDeviceThread";
}
void VideoCaptureManager::OnOpened(
@@ -635,7 +771,7 @@ VideoCaptureManager::GetDeviceEntryForController(
// Look up |controller| in |devices_|.
for (DeviceEntries::const_iterator it = devices_.begin();
it != devices_.end(); ++it) {
- if ((*it)->video_capture_controller.get() == controller) {
+ if ((*it)->video_capture_controller() == controller) {
return *it;
}
}
@@ -645,7 +781,7 @@ VideoCaptureManager::GetDeviceEntryForController(
void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Removal of the last client stops the device.
- if (entry->video_capture_controller->GetClientCount() == 0) {
+ if (entry->video_capture_controller()->GetClientCount() == 0) {
DVLOG(1) << "VideoCaptureManager stopping device (type = "
<< entry->stream_type << ", id = " << entry->id << ")";
@@ -653,12 +789,11 @@ void VideoCaptureManager::DestroyDeviceEntryIfNoClients(DeviceEntry* entry) {
// deleted immediately, and the device is freed asynchronously. After this
// point, subsequent requests to open this same device ID will create a new
// DeviceEntry, VideoCaptureController, and VideoCaptureDevice.
- devices_.erase(entry);
- entry->video_capture_controller.reset();
- device_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureManager::DoStopDeviceOnDeviceThread, this,
- base::Owned(entry)));
+ DoStopDevice(entry);
+ DeviceEntries::iterator device_it = std::find(devices_.begin(),
+ devices_.end(),
+ entry);
+ devices_.erase(device_it);
}
}
@@ -688,7 +823,7 @@ VideoCaptureManager::DeviceEntry* VideoCaptureManager::GetOrCreateDeviceEntry(
DeviceEntry* new_device = new DeviceEntry(device_info.type,
device_info.id,
video_capture_controller.Pass());
- devices_.insert(new_device);
+ devices_.push_back(new_device);
return new_device;
}
@@ -703,14 +838,13 @@ media::VideoCaptureDeviceInfo* VideoCaptureManager::FindDeviceInfoById(
}
void VideoCaptureManager::SetDesktopCaptureWindowIdOnDeviceThread(
- DeviceEntry* entry,
+ media::VideoCaptureDevice* device,
gfx::NativeViewId window_id) {
DCHECK(IsOnDeviceThread());
- DCHECK(entry->stream_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
#if defined(ENABLE_SCREEN_CAPTURE)
- DesktopCaptureDevice* device =
- static_cast<DesktopCaptureDevice*>(entry->video_capture_device.get());
- device->SetNotificationWindowId(window_id);
+ DesktopCaptureDevice* desktop_device =
+ static_cast<DesktopCaptureDevice*>(device);
+ desktop_device->SetNotificationWindowId(window_id);
VLOG(2) << "Screen capture notification window passed on device thread.";
#endif
}

Powered by Google App Engine
This is Rietveld 408576698