| 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 07460fb6283337fd43f53c40cfff45dfd89f6c68..686e6ad74c1a0746d5aed659680b0a3ac1de4c46 100644
|
| --- a/content/renderer/media/video_capture_impl_manager.cc
|
| +++ b/content/renderer/media/video_capture_impl_manager.cc
|
| @@ -1,95 +1,155 @@
|
| // Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
| +//
|
| +// Implementation notes about interactions with VideoCaptureImpl.
|
| +//
|
| +// How is VideoCaptureImpl used:
|
| +//
|
| +// VideoCaptureImpl is an IO thread object while VideoCaptureImplManager
|
| +// lives only on the render thread. It is only possible to access an
|
| +// object of VideoCaptureImpl via a task on the IO thread.
|
| +//
|
| +// How is VideoCaptureImpl deleted:
|
| +//
|
| +// A task is posted to the IO thread to delete a VideoCaptureImpl.
|
| +// Immediately after that the pointer to it is dropped. This means no
|
| +// access to this VideoCaptureImpl object is possible on the render
|
| +// thread. Also note that VideoCaptureImpl does not post task to itself.
|
| +//
|
| +// The use of Unretained:
|
| +//
|
| +// We make sure deletion is the last task on the IO thread for a
|
| +// VideoCaptureImpl object. This allows the use of Unretained() binding.
|
|
|
| #include "content/renderer/media/video_capture_impl_manager.h"
|
|
|
| #include "base/bind.h"
|
| #include "base/bind_helpers.h"
|
| -#include "content/public/renderer/render_thread.h"
|
| +#include "content/child/child_process.h"
|
| #include "content/renderer/media/video_capture_impl.h"
|
| #include "content/renderer/media/video_capture_message_filter.h"
|
| #include "media/base/bind_to_current_loop.h"
|
|
|
| namespace content {
|
|
|
| -VideoCaptureHandle::VideoCaptureHandle(
|
| - media::VideoCapture* impl, base::Closure destruction_cb)
|
| - : impl_(impl), destruction_cb_(destruction_cb) {
|
| -}
|
| -
|
| -VideoCaptureHandle::~VideoCaptureHandle() {
|
| - destruction_cb_.Run();
|
| -}
|
| -
|
| -void VideoCaptureHandle::StartCapture(
|
| - EventHandler* handler,
|
| - const media::VideoCaptureParams& params) {
|
| - impl_->StartCapture(handler, params);
|
| -}
|
| -
|
| -void VideoCaptureHandle::StopCapture(EventHandler* handler) {
|
| - impl_->StopCapture(handler);
|
| -}
|
| -
|
| -bool VideoCaptureHandle::CaptureStarted() {
|
| - return impl_->CaptureStarted();
|
| -}
|
| -
|
| -int VideoCaptureHandle::CaptureFrameRate() {
|
| - return impl_->CaptureFrameRate();
|
| -}
|
| -
|
| -void VideoCaptureHandle::GetDeviceSupportedFormats(
|
| - const DeviceFormatsCallback& callback) {
|
| - impl_->GetDeviceSupportedFormats(callback);
|
| -}
|
| -
|
| -void VideoCaptureHandle::GetDeviceFormatsInUse(
|
| - const DeviceFormatsInUseCallback& callback) {
|
| - impl_->GetDeviceFormatsInUse(callback);
|
| -}
|
| -
|
| VideoCaptureImplManager::VideoCaptureImplManager()
|
| - : filter_(new VideoCaptureMessageFilter()),
|
| + : next_client_id_(0),
|
| + filter_(new VideoCaptureMessageFilter()),
|
| weak_factory_(this) {
|
| }
|
|
|
| VideoCaptureImplManager::~VideoCaptureImplManager() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (devices_.empty())
|
| + return;
|
| + // Forcibly release all video capture resources.
|
| + for (VideoCaptureDeviceMap::iterator it = devices_.begin();
|
| + it != devices_.end(); ++it) {
|
| + VideoCaptureImpl* impl = it->second.second;
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::DeInit,
|
| + base::Unretained(impl)));
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&base::DeletePointer<VideoCaptureImpl>,
|
| + base::Unretained(impl)));
|
| + }
|
| + devices_.clear();
|
| }
|
|
|
| -scoped_ptr<VideoCaptureHandle> VideoCaptureImplManager::UseDevice(
|
| +base::Closure VideoCaptureImplManager::UseDevice(
|
| media::VideoCaptureSessionId id) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - VideoCaptureImpl* video_capture_device = NULL;
|
| + VideoCaptureImpl* impl = NULL;
|
| VideoCaptureDeviceMap::iterator it = devices_.find(id);
|
| if (it == devices_.end()) {
|
| - video_capture_device = CreateVideoCaptureImpl(id, filter_.get());
|
| - devices_[id] =
|
| - std::make_pair(1, linked_ptr<VideoCaptureImpl>(video_capture_device));
|
| - video_capture_device->Init();
|
| + impl = CreateVideoCaptureImplForTesting(id, filter_.get());
|
| + if (!impl)
|
| + impl = new VideoCaptureImpl(id, filter_.get());
|
| + devices_[id] = std::make_pair(1, impl);
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::Init,
|
| + base::Unretained(impl)));
|
| } else {
|
| ++it->second.first;
|
| - video_capture_device = it->second.second.get();
|
| }
|
| + return base::Bind(&VideoCaptureImplManager::UnrefDevice,
|
| + weak_factory_.GetWeakPtr(), id);
|
| +}
|
|
|
| - // This callback ensures UnrefDevice() happens on the render thread.
|
| - return scoped_ptr<VideoCaptureHandle>(
|
| - new VideoCaptureHandle(
|
| - video_capture_device,
|
| - media::BindToCurrentLoop(
|
| - base::Bind(
|
| - &VideoCaptureImplManager::UnrefDevice,
|
| - weak_factory_.GetWeakPtr(),
|
| - id))));
|
| +base::Closure VideoCaptureImplManager::StartCapture(
|
| + media::VideoCaptureSessionId id,
|
| + const media::VideoCaptureParams& params,
|
| + const VideoCaptureStateUpdateCB& state_update_cb,
|
| + const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + VideoCaptureDeviceMap::iterator it = devices_.find(id);
|
| + DCHECK(it != devices_.end());
|
| + VideoCaptureImpl* impl = it->second.second;
|
| +
|
| + // This ID is used to identify a client of VideoCaptureImpl.
|
| + const int client_id = ++next_client_id_;
|
| +
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::StartCapture,
|
| + base::Unretained(impl),
|
| + client_id,
|
| + params,
|
| + state_update_cb,
|
| + deliver_frame_cb));
|
| + return base::Bind(&VideoCaptureImplManager::StopCapture,
|
| + weak_factory_.GetWeakPtr(),
|
| + client_id, id);
|
| +}
|
| +
|
| +void VideoCaptureImplManager::GetDeviceSupportedFormats(
|
| + media::VideoCaptureSessionId id,
|
| + const VideoCaptureDeviceFormatsCB& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + VideoCaptureDeviceMap::iterator it = devices_.find(id);
|
| + DCHECK(it != devices_.end());
|
| + VideoCaptureImpl* impl = it->second.second;
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::GetDeviceSupportedFormats,
|
| + base::Unretained(impl), callback));
|
| +}
|
| +
|
| +void VideoCaptureImplManager::GetDeviceFormatsInUse(
|
| + media::VideoCaptureSessionId id,
|
| + const VideoCaptureDeviceFormatsCB& callback) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + VideoCaptureDeviceMap::iterator it = devices_.find(id);
|
| + DCHECK(it != devices_.end());
|
| + VideoCaptureImpl* impl = it->second.second;
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::GetDeviceFormatsInUse,
|
| + base::Unretained(impl), callback));
|
| }
|
|
|
| -VideoCaptureImpl* VideoCaptureImplManager::CreateVideoCaptureImpl(
|
| +VideoCaptureImpl*
|
| +VideoCaptureImplManager::CreateVideoCaptureImplForTesting(
|
| media::VideoCaptureSessionId id,
|
| VideoCaptureMessageFilter* filter) const {
|
| - return new VideoCaptureImpl(id, filter);
|
| + return NULL;
|
| +}
|
| +
|
| +void VideoCaptureImplManager::StopCapture(
|
| + int client_id, media::VideoCaptureSessionId id) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + VideoCaptureDeviceMap::iterator it = devices_.find(id);
|
| + DCHECK(it != devices_.end());
|
| + VideoCaptureImpl* impl = it->second.second;
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::StopCapture,
|
| + base::Unretained(impl), client_id));
|
| }
|
|
|
| void VideoCaptureImplManager::UnrefDevice(
|
| @@ -97,21 +157,34 @@ void VideoCaptureImplManager::UnrefDevice(
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| VideoCaptureDeviceMap::iterator it = devices_.find(id);
|
| DCHECK(it != devices_.end());
|
| + VideoCaptureImpl* 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) {
|
| - VideoCaptureImpl* impl = it->second.second.release();
|
| devices_.erase(id);
|
| - impl->DeInit(base::Bind(&base::DeletePointer<VideoCaptureImpl>, impl));
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::DeInit,
|
| + base::Unretained(impl)));
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&base::DeletePointer<VideoCaptureImpl>,
|
| + base::Unretained(impl)));
|
| }
|
| }
|
|
|
| void VideoCaptureImplManager::SuspendDevices(bool suspend) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| for (VideoCaptureDeviceMap::iterator it = devices_.begin();
|
| - it != devices_.end(); ++it)
|
| - it->second.second->SuspendCapture(suspend);
|
| + it != devices_.end(); ++it) {
|
| + VideoCaptureImpl* impl = it->second.second;
|
| + ChildProcess::current()->io_message_loop_proxy()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&VideoCaptureImpl::SuspendCapture,
|
| + base::Unretained(impl), suspend));
|
| + }
|
| }
|
|
|
| } // namespace content
|
|
|