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

Unified Diff: content/renderer/media/video_capture_impl_manager.cc

Issue 2365223002: Video Capture: Allow suspension of individual devices. (Closed)
Patch Set: Style tweaks, per mcasas's comments. Created 4 years, 3 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/renderer/media/video_capture_impl_manager.cc
diff --git a/content/renderer/media/video_capture_impl_manager.cc b/content/renderer/media/video_capture_impl_manager.cc
index 1c052d70415517084a8a689cf3e868421d39d8fe..39ba85a0dcd0628402e28242b8c3c4680374eff0 100644
--- a/content/renderer/media/video_capture_impl_manager.cc
+++ b/content/renderer/media/video_capture_impl_manager.cc
@@ -24,6 +24,8 @@
#include "content/renderer/media/video_capture_impl_manager.h"
+#include <algorithm>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
@@ -35,10 +37,32 @@
namespace content {
+struct VideoCaptureImplManager::DeviceEntry {
+ media::VideoCaptureSessionId session_id;
+
+ // To be used and destroyed only on the IO thread.
+ std::unique_ptr<VideoCaptureImpl> impl;
+
+ // Number of clients using |impl|.
+ int client_count;
+
+ // This is set to true if this device is being suspended, via
+ // VideoCaptureImplManager::Suspend().
+ // See also: VideoCaptureImplManager::is_suspending_all_.
+ bool is_individually_suspended;
+
+ DeviceEntry()
+ : session_id(0), client_count(0), is_individually_suspended(false) {}
+ DeviceEntry(DeviceEntry&& other) = default;
+ DeviceEntry& operator=(DeviceEntry&& other) = default;
+ ~DeviceEntry() = default;
+};
+
VideoCaptureImplManager::VideoCaptureImplManager()
: next_client_id_(0),
filter_(new VideoCaptureMessageFilter()),
render_main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ is_suspending_all_(false),
weak_factory_(this) {}
VideoCaptureImplManager::~VideoCaptureImplManager() {
@@ -46,12 +70,12 @@ VideoCaptureImplManager::~VideoCaptureImplManager() {
if (devices_.empty())
return;
// Forcibly release all video capture resources.
- for (const auto& device : devices_) {
- VideoCaptureImpl* const impl = device.second.second;
+ for (auto& entry : devices_) {
ChildProcess::current()->io_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureImpl::DeInit, base::Unretained(impl)));
- ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE, impl);
+ FROM_HERE, base::Bind(&VideoCaptureImpl::DeInit,
+ base::Unretained(entry.impl.get())));
+ ChildProcess::current()->io_task_runner()->DeleteSoon(
+ FROM_HERE, entry.impl.release());
}
devices_.clear();
}
@@ -59,18 +83,31 @@ VideoCaptureImplManager::~VideoCaptureImplManager() {
base::Closure VideoCaptureImplManager::UseDevice(
media::VideoCaptureSessionId id) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- VideoCaptureImpl* impl = NULL;
- const VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
if (it == devices_.end()) {
- impl = CreateVideoCaptureImplForTesting(id, filter_.get());
- if (!impl)
- impl = new VideoCaptureImpl(id, filter_.get());
- devices_[id] = std::make_pair(1, impl);
+ devices_.push_back(DeviceEntry());
+ it = devices_.end() - 1;
+ it->session_id = id;
+ it->impl = CreateVideoCaptureImplForTesting(id, filter_.get());
+ if (!it->impl)
+ it->impl.reset(new VideoCaptureImpl(id, filter_.get()));
ChildProcess::current()->io_task_runner()->PostTask(
- FROM_HERE, base::Bind(&VideoCaptureImpl::Init, base::Unretained(impl)));
- } else {
- ++it->second.first;
+ FROM_HERE, base::Bind(&VideoCaptureImpl::Init,
+ base::Unretained(it->impl.get())));
}
+ ++it->client_count;
+
+ // Design limit: When there are multiple clients, VideoCaptureImplManager
+ // would have to individually track which ones requested suspending/resuming,
+ // in order to determine whether the whole device should be suspended.
+ // Instead, handle the non-common use case of multiple clients by just
+ // resuming the suspended device, and disable suspend functionality while
+ // there are multiple clients.
+ if (it->is_individually_suspended)
+ Resume(id);
+
return base::Bind(&VideoCaptureImplManager::UnrefDevice,
weak_factory_.GetWeakPtr(), id);
}
@@ -81,17 +118,19 @@ base::Closure VideoCaptureImplManager::StartCapture(
const VideoCaptureStateUpdateCB& state_update_cb,
const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
DCHECK(it != devices_.end());
- VideoCaptureImpl* const impl = it->second.second;
// This ID is used to identify a client of VideoCaptureImpl.
const int client_id = ++next_client_id_;
ChildProcess::current()->io_task_runner()->PostTask(
FROM_HERE,
- base::Bind(&VideoCaptureImpl::StartCapture, base::Unretained(impl),
- client_id, params, state_update_cb, deliver_frame_cb));
+ base::Bind(&VideoCaptureImpl::StartCapture,
+ base::Unretained(it->impl.get()), client_id, params,
+ state_update_cb, deliver_frame_cb));
return base::Bind(&VideoCaptureImplManager::StopCapture,
weak_factory_.GetWeakPtr(), client_id, id);
}
@@ -99,83 +138,125 @@ base::Closure VideoCaptureImplManager::StartCapture(
void VideoCaptureImplManager::RequestRefreshFrame(
media::VideoCaptureSessionId id) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
DCHECK(it != devices_.end());
- VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_task_runner()->PostTask(
FROM_HERE,
base::Bind(&VideoCaptureImpl::RequestRefreshFrame,
- base::Unretained(impl)));
+ base::Unretained(it->impl.get())));
+}
+
+void VideoCaptureImplManager::Suspend(media::VideoCaptureSessionId id) {
+ DCHECK(render_main_task_runner_->BelongsToCurrentThread());
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
+ DCHECK(it != devices_.end());
+ if (it->is_individually_suspended)
+ return; // Device has already been individually suspended.
+ if (it->client_count > 1)
+ return; // Punt when there is >1 client (see comments in UseDevice()).
+ it->is_individually_suspended = true;
+ if (is_suspending_all_)
+ return; // Device should already be suspended.
+ ChildProcess::current()->io_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
+ base::Unretained(it->impl.get()), true));
+}
+
+void VideoCaptureImplManager::Resume(media::VideoCaptureSessionId id) {
+ DCHECK(render_main_task_runner_->BelongsToCurrentThread());
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
+ DCHECK(it != devices_.end());
+ if (!it->is_individually_suspended)
+ return; // Device was not individually suspended.
+ it->is_individually_suspended = false;
+ if (is_suspending_all_)
+ return; // Device must remain suspended until all are resumed.
+ ChildProcess::current()->io_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
+ base::Unretained(it->impl.get()), false));
}
void VideoCaptureImplManager::GetDeviceSupportedFormats(
media::VideoCaptureSessionId id,
const VideoCaptureDeviceFormatsCB& callback) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
DCHECK(it != devices_.end());
- VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_task_runner()->PostTask(
FROM_HERE, base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats,
- base::Unretained(impl), callback));
+ base::Unretained(it->impl.get()), callback));
}
void VideoCaptureImplManager::GetDeviceFormatsInUse(
media::VideoCaptureSessionId id,
const VideoCaptureDeviceFormatsCB& callback) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
DCHECK(it != devices_.end());
- VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_task_runner()->PostTask(
FROM_HERE, base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
- base::Unretained(impl), callback));
+ base::Unretained(it->impl.get()), callback));
}
-VideoCaptureImpl*
+std::unique_ptr<VideoCaptureImpl>
VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
media::VideoCaptureSessionId id,
VideoCaptureMessageFilter* filter) const {
- return NULL;
+ return std::unique_ptr<VideoCaptureImpl>();
}
void VideoCaptureImplManager::StopCapture(int client_id,
media::VideoCaptureSessionId id) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- const VideoCaptureDeviceMap::const_iterator it = devices_.find(id);
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
DCHECK(it != devices_.end());
- VideoCaptureImpl* const impl = it->second.second;
ChildProcess::current()->io_task_runner()->PostTask(
FROM_HERE, base::Bind(&VideoCaptureImpl::StopCapture,
- base::Unretained(impl), client_id));
+ base::Unretained(it->impl.get()), client_id));
}
void VideoCaptureImplManager::UnrefDevice(
media::VideoCaptureSessionId id) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- const VideoCaptureDeviceMap::iterator it = devices_.find(id);
+ const auto it = std::find_if(
+ devices_.begin(), devices_.end(),
+ [id] (const DeviceEntry& entry) { return entry.session_id == id; });
DCHECK(it != devices_.end());
- VideoCaptureImpl* const impl = it->second.second;
-
- // Unref and destroy on the IO thread if there's no more client.
- DCHECK(it->second.first);
- --it->second.first;
- if (!it->second.first) {
- devices_.erase(id);
- ChildProcess::current()->io_task_runner()->PostTask(
- FROM_HERE,
- base::Bind(&VideoCaptureImpl::DeInit, base::Unretained(impl)));
- ChildProcess::current()->io_task_runner()->DeleteSoon(FROM_HERE, impl);
- }
+ DCHECK_GT(it->client_count, 0);
+ --it->client_count;
+ if (it->client_count > 0)
+ return;
+ ChildProcess::current()->io_task_runner()->PostTask(
+ FROM_HERE, base::Bind(&VideoCaptureImpl::DeInit,
+ base::Unretained(it->impl.get())));
+ ChildProcess::current()->io_task_runner()->DeleteSoon(
+ FROM_HERE, it->impl.release());
+ devices_.erase(it);
}
void VideoCaptureImplManager::SuspendDevices(bool suspend) {
DCHECK(render_main_task_runner_->BelongsToCurrentThread());
- for (const auto& device : devices_) {
- VideoCaptureImpl* const impl = device.second.second;
+ if (is_suspending_all_ == suspend)
+ return;
+ is_suspending_all_ = suspend;
+ for (auto& entry : devices_) {
+ if (entry.is_individually_suspended)
+ continue; // Either: 1) Already suspended; or 2) Should not be resumed.
ChildProcess::current()->io_task_runner()->PostTask(
FROM_HERE, base::Bind(&VideoCaptureImpl::SuspendCapture,
- base::Unretained(impl), suspend));
+ base::Unretained(entry.impl.get()), suspend));
}
}
« no previous file with comments | « content/renderer/media/video_capture_impl_manager.h ('k') | content/renderer/media/video_capture_impl_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698