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

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

Issue 801363002: Queue commands to the Os to start a video device. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Adressed comments. 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..03f0967a98a9958400f0c44bf8263f3c9847e778 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,12 +106,23 @@ 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()) {}
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(
scoped_ptr<media::VideoCaptureDeviceFactory> factory)
@@ -118,6 +133,7 @@ VideoCaptureManager::VideoCaptureManager(
VideoCaptureManager::~VideoCaptureManager() {
DCHECK(devices_.empty());
+ DCHECK(device_start_queue_.empty());
}
void VideoCaptureManager::Register(
@@ -216,22 +232,131 @@ 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.get()) {
+ // |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->video_capture_device)));
+ }
+}
+
+void VideoCaptureManager::HandleQueuedStartRequest() {
+ // 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.get());
+ (*entry_it)->video_capture_device.swap(device);
+ }
+
+ 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 +365,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 +399,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(
@@ -306,16 +432,7 @@ void VideoCaptureManager::StartCaptureForClient(
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());
@@ -392,10 +509,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 +537,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(
@@ -517,13 +623,12 @@ void VideoCaptureManager::SetDesktopCaptureWindowId(
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(
@@ -653,12 +758,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 +792,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;
}

Powered by Google App Engine
This is Rietveld 408576698