Commit 97313d5f authored by mcasas@chromium.org's avatar mcasas@chromium.org

VideoCaptureDeviceFactory: change device enumeration to callback + QTKit enumerates in UI thread.

This CL changes the Enumeration to be based on 
a callback passed to the VideoCaptureDeviceFactory.
It is used for QTKit enumeration on UI thread:
this is speculatively better than trying to run
-performSelectorOnMainThread:withObject:waitUntilDone:

-- Description --

Currently VCM::EnumerateDevices() issues an internal 
PostTaskAndReplyWithResult where the first part
is GetAvailableDevicesInfoOnDeviceThread() on 
DeviceThread and the second is 
OnDevicesInfoEnumerated() in IO thread.

This CL changes this to a simple PostTask to the 
VCDFactory::EnumerateDeviceNames() with a callback
to VCM::ConsolidateDevicesInfoOnDeviceThread().
This method has a jump at the end to 
VCM::OnDevicesInfoEnumerated() on IO thread. So
what used to be a simple back-and-forth jump is
now a 3 hop process. 

This is used for QTKit to be able to override the
VCDF::EnumerateDeviceNames and run the device
enumeration in UI thread. 

Note 1: The UI thread is currently passed in Create()
method for all implementations. This is changed to
earlier: on VCDF::CreateFactory(); injected from 
MediaStreamManager; and only used in VCDFLinux 
(for ChromeOS) and in VCDFMac for QTKit enumeration.
This approach is cleaner since we don't send UI thread
references to derived classes that don't need it.

Note 2: VideoCaptureDeviceFactoryMac::Create()
used to have a search-and-find for |device_id| that
is removed; the search was a precaution for devices
that disappeared between first enumeration and use.
However, using a |device_name| that is gone would
just cause a fail on AllocateAndStart() anyhow, and
enumerating twice is very expensive.
 For compatibility reasons, this behaviour is kept
for AVFoundation devices and blacklisted QTKit
devices (that behave as a subset of AVF-type ones).



BUG=255552, 115327

Review URL: https://codereview.chromium.org/294893006

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@274518 0039d316-1c4b-4281-b951-d872f2087c98
parent f67a45da
...@@ -1442,8 +1442,9 @@ void MediaStreamManager::InitializeDeviceManagersOnIOThread() { ...@@ -1442,8 +1442,9 @@ void MediaStreamManager::InitializeDeviceManagersOnIOThread() {
audio_input_device_manager()->UseFakeDevice(); audio_input_device_manager()->UseFakeDevice();
} }
video_capture_manager_ = new VideoCaptureManager( video_capture_manager_ =
media::VideoCaptureDeviceFactory::CreateFactory()); new VideoCaptureManager(media::VideoCaptureDeviceFactory::CreateFactory(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)));
video_capture_manager_->Register(this, device_task_runner_); video_capture_manager_->Register(this, device_task_runner_);
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <set> #include <set>
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/stl_util.h" #include "base/stl_util.h"
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
#include "content/public/browser/desktop_media_id.h" #include "content/public/browser/desktop_media_id.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "content/public/common/media_stream_request.h" #include "content/public/common/media_stream_request.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/scoped_histogram_timer.h" #include "media/base/scoped_histogram_timer.h"
#include "media/video/capture/video_capture_device.h" #include "media/video/capture/video_capture_device.h"
#include "media/video/capture/video_capture_device_factory.h" #include "media/video/capture/video_capture_device_factory.h"
...@@ -122,12 +124,28 @@ void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) { ...@@ -122,12 +124,28 @@ void VideoCaptureManager::EnumerateDevices(MediaStreamType stream_type) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type; DVLOG(1) << "VideoCaptureManager::EnumerateDevices, type " << stream_type;
DCHECK(listener_); DCHECK(listener_);
base::PostTaskAndReplyWithResult( DCHECK_EQ(stream_type, MEDIA_DEVICE_VIDEO_CAPTURE);
device_task_runner_, FROM_HERE,
base::Bind(&VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread, // Bind a callback to ConsolidateDevicesInfoOnDeviceThread() with an argument
this, stream_type, devices_info_cache_), // for another callback to OnDevicesInfoEnumerated() to be run in the current
base::Bind(&VideoCaptureManager::OnDevicesInfoEnumerated, this, // loop, i.e. IO loop. Pass a timer for UMA histogram collection.
stream_type)); base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>
devices_enumerated_callback =
base::Bind(&VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread,
this,
media::BindToCurrentLoop(base::Bind(
&VideoCaptureManager::OnDevicesInfoEnumerated,
this,
stream_type,
base::Owned(new base::ElapsedTimer()))),
stream_type,
devices_info_cache_);
// OK to use base::Unretained() since we own the VCDFactory and |this| is
// bound in |devices_enumerated_callback|.
device_task_runner_->PostTask(FROM_HERE,
base::Bind(&media::VideoCaptureDeviceFactory::EnumerateDeviceNames,
base::Unretained(video_capture_device_factory_.get()),
devices_enumerated_callback));
} }
int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) { int VideoCaptureManager::Open(const StreamDeviceInfo& device_info) {
...@@ -200,9 +218,7 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread( ...@@ -200,9 +218,7 @@ void VideoCaptureManager::DoStartDeviceOnDeviceThread(
DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_); DeviceInfo* found = FindDeviceInfoById(entry->id, devices_info_cache_);
if (found) { if (found) {
video_capture_device = video_capture_device =
video_capture_device_factory_->Create( video_capture_device_factory_->Create(found->name);
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
found->name);
} }
break; break;
} }
...@@ -432,9 +448,12 @@ void VideoCaptureManager::OnClosed( ...@@ -432,9 +448,12 @@ void VideoCaptureManager::OnClosed(
void VideoCaptureManager::OnDevicesInfoEnumerated( void VideoCaptureManager::OnDevicesInfoEnumerated(
MediaStreamType stream_type, MediaStreamType stream_type,
base::ElapsedTimer* timer,
const DeviceInfos& new_devices_info_cache) { const DeviceInfos& new_devices_info_cache) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
UMA_HISTOGRAM_TIMES(
"Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime",
timer->Elapsed());
if (!listener_) { if (!listener_) {
// Listener has been removed. // Listener has been removed.
return; return;
...@@ -456,29 +475,12 @@ bool VideoCaptureManager::IsOnDeviceThread() const { ...@@ -456,29 +475,12 @@ bool VideoCaptureManager::IsOnDeviceThread() const {
return device_task_runner_->BelongsToCurrentThread(); return device_task_runner_->BelongsToCurrentThread();
} }
VideoCaptureManager::DeviceInfos void VideoCaptureManager::ConsolidateDevicesInfoOnDeviceThread(
VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread( base::Callback<void(const DeviceInfos&)> on_devices_enumerated_callback,
MediaStreamType stream_type, MediaStreamType stream_type,
const DeviceInfos& old_device_info_cache) { const DeviceInfos& old_device_info_cache,
SCOPED_UMA_HISTOGRAM_TIMER( scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot) {
"Media.VideoCaptureManager.GetAvailableDevicesInfoOnDeviceThreadTime");
DCHECK(IsOnDeviceThread()); DCHECK(IsOnDeviceThread());
media::VideoCaptureDevice::Names names_snapshot;
switch (stream_type) {
case MEDIA_DEVICE_VIDEO_CAPTURE:
// Cache the latest enumeration of video capture devices.
// We'll refer to this list again in OnOpen to avoid having to
// enumerate the devices again.
video_capture_device_factory_->GetDeviceNames(&names_snapshot);
break;
case MEDIA_DESKTOP_VIDEO_CAPTURE:
// Do nothing.
break;
default:
NOTREACHED();
break;
}
// Construct |new_devices_info_cache| with the cached devices that are still // Construct |new_devices_info_cache| with the cached devices that are still
// present in the system, and remove their names from |names_snapshot|, so we // present in the system, and remove their names from |names_snapshot|, so we
// keep there the truly new devices. // keep there the truly new devices.
...@@ -487,11 +489,11 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread( ...@@ -487,11 +489,11 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
old_device_info_cache.begin(); old_device_info_cache.begin();
it_device_info != old_device_info_cache.end(); ++it_device_info) { it_device_info != old_device_info_cache.end(); ++it_device_info) {
for (media::VideoCaptureDevice::Names::iterator it = for (media::VideoCaptureDevice::Names::iterator it =
names_snapshot.begin(); names_snapshot->begin();
it != names_snapshot.end(); ++it) { it != names_snapshot->end(); ++it) {
if (it_device_info->name.id() == it->id()) { if (it_device_info->name.id() == it->id()) {
new_devices_info_cache.push_back(*it_device_info); new_devices_info_cache.push_back(*it_device_info);
names_snapshot.erase(it); names_snapshot->erase(it);
break; break;
} }
} }
...@@ -499,8 +501,8 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread( ...@@ -499,8 +501,8 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
// Get the supported capture formats for the new devices in |names_snapshot|. // Get the supported capture formats for the new devices in |names_snapshot|.
for (media::VideoCaptureDevice::Names::const_iterator it = for (media::VideoCaptureDevice::Names::const_iterator it =
names_snapshot.begin(); names_snapshot->begin();
it != names_snapshot.end(); ++it) { it != names_snapshot->end(); ++it) {
media::VideoCaptureFormats supported_formats; media::VideoCaptureFormats supported_formats;
DeviceInfo device_info(*it, media::VideoCaptureFormats()); DeviceInfo device_info(*it, media::VideoCaptureFormats());
video_capture_device_factory_->GetDeviceSupportedFormats( video_capture_device_factory_->GetDeviceSupportedFormats(
...@@ -508,7 +510,8 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread( ...@@ -508,7 +510,8 @@ VideoCaptureManager::GetAvailableDevicesInfoOnDeviceThread(
ConsolidateCaptureFormats(&device_info.supported_formats); ConsolidateCaptureFormats(&device_info.supported_formats);
new_devices_info_cache.push_back(device_info); new_devices_info_cache.push_back(device_info);
} }
return new_devices_info_cache;
on_devices_enumerated_callback.Run(new_devices_info_cache);
} }
VideoCaptureManager::DeviceEntry* VideoCaptureManager::DeviceEntry*
......
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process_handle.h" #include "base/process/process_handle.h"
#include "base/timer/elapsed_timer.h"
#include "content/browser/renderer_host/media/media_stream_provider.h" #include "content/browser/renderer_host/media/media_stream_provider.h"
#include "content/browser/renderer_host/media/video_capture_controller_event_handler.h" #include "content/browser/renderer_host/media/video_capture_controller_event_handler.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
...@@ -123,7 +125,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider { ...@@ -123,7 +125,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
}; };
typedef std::vector<DeviceInfo> DeviceInfos; typedef std::vector<DeviceInfo> DeviceInfos;
// Check to see if |entry| has no clients left on its controller. If so, // Checks to see if |entry| has no clients left on its controller. If so,
// remove it from the list of devices, and delete it asynchronously. |entry| // remove it from the list of devices, and delete it asynchronously. |entry|
// may be freed by this function. // may be freed by this function.
void DestroyDeviceEntryIfNoClients(DeviceEntry* entry); void DestroyDeviceEntryIfNoClients(DeviceEntry* entry);
...@@ -133,34 +135,35 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider { ...@@ -133,34 +135,35 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
media::VideoCaptureSessionId capture_session_id); media::VideoCaptureSessionId capture_session_id);
void OnClosed(MediaStreamType type, void OnClosed(MediaStreamType type,
media::VideoCaptureSessionId capture_session_id); media::VideoCaptureSessionId capture_session_id);
void OnDevicesInfoEnumerated( void OnDevicesInfoEnumerated(MediaStreamType stream_type,
MediaStreamType stream_type, base::ElapsedTimer* timer,
const DeviceInfos& new_devices_info_cache); const DeviceInfos& new_devices_info_cache);
// Find a DeviceEntry by its device ID and type, if it is already opened. // Finds a DeviceEntry by its device ID and type, if it is already opened.
DeviceEntry* GetDeviceEntryForMediaStreamDevice( DeviceEntry* GetDeviceEntryForMediaStreamDevice(
const MediaStreamDevice& device_info); const MediaStreamDevice& device_info);
// Find a DeviceEntry entry for the indicated session, creating a fresh one // Finds a DeviceEntry entry for the indicated session, creating a fresh one
// if necessary. Returns NULL if the session id is invalid. // if necessary. Returns NULL if the session id is invalid.
DeviceEntry* GetOrCreateDeviceEntry( DeviceEntry* GetOrCreateDeviceEntry(
media::VideoCaptureSessionId capture_session_id); media::VideoCaptureSessionId capture_session_id);
// Find the DeviceEntry that owns a particular controller pointer. // Finds the DeviceEntry that owns a particular controller pointer.
DeviceEntry* GetDeviceEntryForController( DeviceEntry* GetDeviceEntryForController(
const VideoCaptureController* controller) const; const VideoCaptureController* controller) const;
bool IsOnDeviceThread() const; bool IsOnDeviceThread() const;
// Queries the Names of the devices in the system; the formats supported by // Consolidates the cached devices list with the list of currently connected
// the new devices are also queried, and consolidated with the copy of the // devices in the system |names_snapshot|. Retrieves the supported formats of
// local device info cache passed. The consolidated list of devices and // the new devices and sends the new cache to OnDevicesInfoEnumerated().
// supported formats is returned. void ConsolidateDevicesInfoOnDeviceThread(
DeviceInfos GetAvailableDevicesInfoOnDeviceThread( base::Callback<void(const DeviceInfos&)> on_devices_enumerated_callback,
MediaStreamType stream_type, MediaStreamType stream_type,
const DeviceInfos& old_device_info_cache); const DeviceInfos& old_device_info_cache,
scoped_ptr<media::VideoCaptureDevice::Names> names_snapshot);
// Create and Start a new VideoCaptureDevice, storing the result in // Creates and Starts a new VideoCaptureDevice, storing the result in
// |entry->video_capture_device|. Ownership of |client| passes to // |entry->video_capture_device|. Ownership of |client| passes to
// the device. // the device.
void DoStartDeviceOnDeviceThread( void DoStartDeviceOnDeviceThread(
...@@ -169,7 +172,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider { ...@@ -169,7 +172,7 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
const media::VideoCaptureParams& params, const media::VideoCaptureParams& params,
scoped_ptr<media::VideoCaptureDevice::Client> client); scoped_ptr<media::VideoCaptureDevice::Client> client);
// Stop and destroy the VideoCaptureDevice held in // Stops and destroys the VideoCaptureDevice held in
// |entry->video_capture_device|. // |entry->video_capture_device|.
void DoStopDeviceOnDeviceThread(DeviceEntry* entry); void DoStopDeviceOnDeviceThread(DeviceEntry* entry);
...@@ -230,9 +233,9 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider { ...@@ -230,9 +233,9 @@ class CONTENT_EXPORT VideoCaptureManager : public MediaStreamProvider {
// Local cache of the enumerated video capture devices' names and capture // Local cache of the enumerated video capture devices' names and capture
// supported formats. A snapshot of the current devices and their capabilities // supported formats. A snapshot of the current devices and their capabilities
// is composed in GetAvailableDevicesInfoOnDeviceThread() --coming // is composed in VideoCaptureDeviceFactory::EnumerateDeviceNames() and
// from EnumerateDevices()--, and this snapshot is used to update this list in // ConsolidateDevicesInfoOnDeviceThread(), and this snapshot is used to update
// OnDevicesInfoEnumerated(). GetDeviceSupportedFormats() will // this list in OnDevicesInfoEnumerated(). GetDeviceSupportedFormats() will
// use this list if the device is not started, otherwise it will retrieve the // use this list if the device is not started, otherwise it will retrieve the
// active device capture format from the VideoCaptureController associated. // active device capture format from the VideoCaptureController associated.
DeviceInfos devices_info_cache_; DeviceInfos devices_info_cache_;
......
...@@ -35,7 +35,6 @@ VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid( ...@@ -35,7 +35,6 @@ VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
} }
scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryAndroid::Create( scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryAndroid::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) { const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
int id; int id;
......
...@@ -34,7 +34,6 @@ class MEDIA_EXPORT VideoCaptureDeviceFactoryAndroid : ...@@ -34,7 +34,6 @@ class MEDIA_EXPORT VideoCaptureDeviceFactoryAndroid :
virtual ~VideoCaptureDeviceFactoryAndroid() {} virtual ~VideoCaptureDeviceFactoryAndroid() {}
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) OVERRIDE; const VideoCaptureDevice::Name& device_name) OVERRIDE;
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE;
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
......
...@@ -14,8 +14,8 @@ FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory() ...@@ -14,8 +14,8 @@ FakeVideoCaptureDeviceFactory::FakeVideoCaptureDeviceFactory()
} }
scoped_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::Create( scoped_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) { const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread());
for (int n = 0; n < number_of_devices_; ++n) { for (int n = 0; n < number_of_devices_; ++n) {
std::string possible_id = base::StringPrintf("/dev/video%d", n); std::string possible_id = base::StringPrintf("/dev/video%d", n);
if (device_name.id().compare(possible_id) == 0) if (device_name.id().compare(possible_id) == 0)
...@@ -26,6 +26,7 @@ scoped_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::Create( ...@@ -26,6 +26,7 @@ scoped_ptr<VideoCaptureDevice> FakeVideoCaptureDeviceFactory::Create(
void FakeVideoCaptureDeviceFactory::GetDeviceNames( void FakeVideoCaptureDeviceFactory::GetDeviceNames(
VideoCaptureDevice::Names* const device_names) { VideoCaptureDevice::Names* const device_names) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(device_names->empty()); DCHECK(device_names->empty());
for (int n = 0; n < number_of_devices_; ++n) { for (int n = 0; n < number_of_devices_; ++n) {
VideoCaptureDevice::Name name(base::StringPrintf("fake_device_%d", n), VideoCaptureDevice::Name name(base::StringPrintf("fake_device_%d", n),
...@@ -37,6 +38,7 @@ void FakeVideoCaptureDeviceFactory::GetDeviceNames( ...@@ -37,6 +38,7 @@ void FakeVideoCaptureDeviceFactory::GetDeviceNames(
void FakeVideoCaptureDeviceFactory::GetDeviceSupportedFormats( void FakeVideoCaptureDeviceFactory::GetDeviceSupportedFormats(
const VideoCaptureDevice::Name& device, const VideoCaptureDevice::Name& device,
VideoCaptureFormats* supported_formats) { VideoCaptureFormats* supported_formats) {
DCHECK(thread_checker_.CalledOnValidThread());
const int frame_rate = 1000 / FakeVideoCaptureDevice::kFakeCaptureTimeoutMs; const int frame_rate = 1000 / FakeVideoCaptureDevice::kFakeCaptureTimeoutMs;
const gfx::Size supported_sizes[] = {gfx::Size(320, 240), const gfx::Size supported_sizes[] = {gfx::Size(320, 240),
gfx::Size(640, 480), gfx::Size(640, 480),
......
...@@ -20,7 +20,6 @@ class MEDIA_EXPORT FakeVideoCaptureDeviceFactory : ...@@ -20,7 +20,6 @@ class MEDIA_EXPORT FakeVideoCaptureDeviceFactory :
virtual ~FakeVideoCaptureDeviceFactory() {} virtual ~FakeVideoCaptureDeviceFactory() {}
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) OVERRIDE; const VideoCaptureDevice::Name& device_name) OVERRIDE;
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE;
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using ::testing::_; using ::testing::_;
using ::testing::SaveArg;
namespace media { namespace media {
...@@ -53,6 +54,22 @@ class MockClient : public media::VideoCaptureDevice::Client { ...@@ -53,6 +54,22 @@ class MockClient : public media::VideoCaptureDevice::Client {
base::Callback<void(const VideoCaptureFormat&)> frame_cb_; base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
}; };
class DeviceEnumerationListener :
public base::RefCounted<DeviceEnumerationListener> {
public:
MOCK_METHOD1(OnEnumeratedDevicesCallbackPtr,
void(media::VideoCaptureDevice::Names* names));
// GMock doesn't support move-only arguments, so we use this forward method.
void OnEnumeratedDevicesCallback(
scoped_ptr<media::VideoCaptureDevice::Names> names) {
OnEnumeratedDevicesCallbackPtr(names.release());
}
private:
friend class base::RefCounted<DeviceEnumerationListener>;
virtual ~DeviceEnumerationListener() {}
};
class FakeVideoCaptureDeviceTest : public testing::Test { class FakeVideoCaptureDeviceTest : public testing::Test {
protected: protected:
typedef media::VideoCaptureDevice::Client Client; typedef media::VideoCaptureDevice::Client Client;
...@@ -62,7 +79,9 @@ class FakeVideoCaptureDeviceTest : public testing::Test { ...@@ -62,7 +79,9 @@ class FakeVideoCaptureDeviceTest : public testing::Test {
client_(new MockClient( client_(new MockClient(
base::Bind(&FakeVideoCaptureDeviceTest::OnFrameCaptured, base::Bind(&FakeVideoCaptureDeviceTest::OnFrameCaptured,
base::Unretained(this)))), base::Unretained(this)))),
video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {} video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {
device_enumeration_listener_ = new DeviceEnumerationListener();
}
virtual void SetUp() { virtual void SetUp() {
} }
...@@ -77,26 +96,36 @@ class FakeVideoCaptureDeviceTest : public testing::Test { ...@@ -77,26 +96,36 @@ class FakeVideoCaptureDeviceTest : public testing::Test {
run_loop_->Run(); run_loop_->Run();
} }
scoped_ptr<media::VideoCaptureDevice::Names> EnumerateDevices() {
media::VideoCaptureDevice::Names* names;
EXPECT_CALL(*device_enumeration_listener_,
OnEnumeratedDevicesCallbackPtr(_)).WillOnce(SaveArg<0>(&names));
video_capture_device_factory_->EnumerateDeviceNames(
base::Bind(&DeviceEnumerationListener::OnEnumeratedDevicesCallback,
device_enumeration_listener_));
base::MessageLoop::current()->RunUntilIdle();
return scoped_ptr<media::VideoCaptureDevice::Names>(names);
}
const VideoCaptureFormat& last_format() const { return last_format_; } const VideoCaptureFormat& last_format() const { return last_format_; }
VideoCaptureDevice::Names names_; VideoCaptureDevice::Names names_;
scoped_ptr<base::MessageLoop> loop_; scoped_ptr<base::MessageLoop> loop_;
scoped_ptr<base::RunLoop> run_loop_; scoped_ptr<base::RunLoop> run_loop_;
scoped_ptr<MockClient> client_; scoped_ptr<MockClient> client_;
scoped_refptr<DeviceEnumerationListener> device_enumeration_listener_;
VideoCaptureFormat last_format_; VideoCaptureFormat last_format_;
scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_; scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_;
}; };
TEST_F(FakeVideoCaptureDeviceTest, Capture) { TEST_F(FakeVideoCaptureDeviceTest, Capture) {
VideoCaptureDevice::Names names; scoped_ptr<media::VideoCaptureDevice::Names> names(EnumerateDevices());
video_capture_device_factory_->GetDeviceNames(&names);
ASSERT_GT(static_cast<int>(names.size()), 0); ASSERT_GT(static_cast<int>(names->size()), 0);
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create( video_capture_device_factory_->Create(names->front()));
base::MessageLoopProxy::current(), names.front()));
ASSERT_TRUE(device); ASSERT_TRUE(device);
EXPECT_CALL(*client_, OnErr()).Times(0); EXPECT_CALL(*client_, OnErr()).Times(0);
...@@ -115,13 +144,12 @@ TEST_F(FakeVideoCaptureDeviceTest, Capture) { ...@@ -115,13 +144,12 @@ TEST_F(FakeVideoCaptureDeviceTest, Capture) {
} }
TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) { TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) {
VideoCaptureDevice::Names names; scoped_ptr<VideoCaptureDevice::Names> names(EnumerateDevices());
video_capture_device_factory_->GetDeviceNames(&names);
VideoCaptureFormats supported_formats; VideoCaptureFormats supported_formats;
VideoCaptureDevice::Names::iterator names_iterator; VideoCaptureDevice::Names::iterator names_iterator;
for (names_iterator = names.begin(); names_iterator != names.end(); for (names_iterator = names->begin(); names_iterator != names->end();
++names_iterator) { ++names_iterator) {
video_capture_device_factory_->GetDeviceSupportedFormats( video_capture_device_factory_->GetDeviceSupportedFormats(
*names_iterator, &supported_formats); *names_iterator, &supported_formats);
...@@ -142,25 +170,23 @@ TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) { ...@@ -142,25 +170,23 @@ TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) {
} }
TEST_F(FakeVideoCaptureDeviceTest, CaptureVariableResolution) { TEST_F(FakeVideoCaptureDeviceTest, CaptureVariableResolution) {
VideoCaptureDevice::Names names; scoped_ptr<VideoCaptureDevice::Names> names(EnumerateDevices());
video_capture_device_factory_->GetDeviceNames(&names);
VideoCaptureParams capture_params; VideoCaptureParams capture_params;
capture_params.requested_format.frame_size.SetSize(640, 480); capture_params.requested_format.frame_size.SetSize(640, 480);
capture_params.requested_format.frame_rate = 30; capture_params.requested_format.frame_rate = 30;
capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420; capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
capture_params.allow_resolution_change = true; capture_params.allow_resolution_change = true;
ASSERT_GT(static_cast<int>(names.size()), 0); ASSERT_GT(static_cast<int>(names->size()), 0);
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create( video_capture_device_factory_->Create(names->front()));
base::MessageLoopProxy::current(), names.front()));
ASSERT_TRUE(device); ASSERT_TRUE(device);
// Configure the FakeVideoCaptureDevice to use all its formats as roster. // Configure the FakeVideoCaptureDevice to use all its formats as roster.
VideoCaptureFormats formats; VideoCaptureFormats formats;
video_capture_device_factory_->GetDeviceSupportedFormats(names.front(), video_capture_device_factory_->GetDeviceSupportedFormats(names->front(),
&formats); &formats);
static_cast<FakeVideoCaptureDevice*>(device.get())-> static_cast<FakeVideoCaptureDevice*>(device.get())->
PopulateVariableFormatsRoster(formats); PopulateVariableFormatsRoster(formats);
......
...@@ -25,8 +25,8 @@ base::FilePath GetFilePathFromCommandLine() { ...@@ -25,8 +25,8 @@ base::FilePath GetFilePathFromCommandLine() {
} }
scoped_ptr<VideoCaptureDevice> FileVideoCaptureDeviceFactory::Create( scoped_ptr<VideoCaptureDevice> FileVideoCaptureDeviceFactory::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) { const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread());
#if defined(OS_WIN) #if defined(OS_WIN)
return scoped_ptr<VideoCaptureDevice>(new FileVideoCaptureDevice( return scoped_ptr<VideoCaptureDevice>(new FileVideoCaptureDevice(
base::FilePath(base::SysUTF8ToWide(device_name.name())))); base::FilePath(base::SysUTF8ToWide(device_name.name()))));
...@@ -38,6 +38,7 @@ scoped_ptr<VideoCaptureDevice> FileVideoCaptureDeviceFactory::Create( ...@@ -38,6 +38,7 @@ scoped_ptr<VideoCaptureDevice> FileVideoCaptureDeviceFactory::Create(
void FileVideoCaptureDeviceFactory::GetDeviceNames( void FileVideoCaptureDeviceFactory::GetDeviceNames(
VideoCaptureDevice::Names* const device_names) { VideoCaptureDevice::Names* const device_names) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(device_names->empty()); DCHECK(device_names->empty());
base::FilePath command_line_file_path = GetFilePathFromCommandLine(); base::FilePath command_line_file_path = GetFilePathFromCommandLine();
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -54,6 +55,7 @@ void FileVideoCaptureDeviceFactory::GetDeviceNames( ...@@ -54,6 +55,7 @@ void FileVideoCaptureDeviceFactory::GetDeviceNames(
void FileVideoCaptureDeviceFactory::GetDeviceSupportedFormats( void FileVideoCaptureDeviceFactory::GetDeviceSupportedFormats(
const VideoCaptureDevice::Name& device, const VideoCaptureDevice::Name& device,
VideoCaptureFormats* supported_formats) { VideoCaptureFormats* supported_formats) {
DCHECK(thread_checker_.CalledOnValidThread());
base::File file = base::File file =
FileVideoCaptureDevice::OpenFileForRead(GetFilePathFromCommandLine()); FileVideoCaptureDevice::OpenFileForRead(GetFilePathFromCommandLine());
VideoCaptureFormat capture_format; VideoCaptureFormat capture_format;
......
...@@ -19,7 +19,6 @@ class MEDIA_EXPORT FileVideoCaptureDeviceFactory : ...@@ -19,7 +19,6 @@ class MEDIA_EXPORT FileVideoCaptureDeviceFactory :
virtual ~FileVideoCaptureDeviceFactory() {} virtual ~FileVideoCaptureDeviceFactory() {}
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) OVERRIDE; const VideoCaptureDevice::Name& device_name) OVERRIDE;
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE;
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
......
...@@ -44,13 +44,20 @@ static bool HasUsableFormats(int fd) { ...@@ -44,13 +44,20 @@ static bool HasUsableFormats(int fd) {
return false; return false;
} }
VideoCaptureDeviceFactoryLinux::VideoCaptureDeviceFactoryLinux(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
: ui_task_runner_(ui_task_runner) {
}
VideoCaptureDeviceFactoryLinux::~VideoCaptureDeviceFactoryLinux() {
}
scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::Create( scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryLinux::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) { const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
VideoCaptureDeviceChromeOS* self = VideoCaptureDeviceChromeOS* self =
new VideoCaptureDeviceChromeOS(ui_task_runner, device_name); new VideoCaptureDeviceChromeOS(ui_task_runner_, device_name);
#else #else
VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name); VideoCaptureDeviceLinux* self = new VideoCaptureDeviceLinux(device_name);
#endif #endif
......
...@@ -18,11 +18,11 @@ namespace media { ...@@ -18,11 +18,11 @@ namespace media {
class MEDIA_EXPORT VideoCaptureDeviceFactoryLinux class MEDIA_EXPORT VideoCaptureDeviceFactoryLinux
: public VideoCaptureDeviceFactory { : public VideoCaptureDeviceFactory {
public: public:
VideoCaptureDeviceFactoryLinux() {} explicit VideoCaptureDeviceFactoryLinux(
virtual ~VideoCaptureDeviceFactoryLinux() {} scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
virtual ~VideoCaptureDeviceFactoryLinux();
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) OVERRIDE; const VideoCaptureDevice::Name& device_name) OVERRIDE;
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE;
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
...@@ -30,7 +30,7 @@ class MEDIA_EXPORT VideoCaptureDeviceFactoryLinux ...@@ -30,7 +30,7 @@ class MEDIA_EXPORT VideoCaptureDeviceFactoryLinux
VideoCaptureFormats* supported_formats) OVERRIDE; VideoCaptureFormats* supported_formats) OVERRIDE;
private: private:
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryLinux); DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryLinux);
}; };
......
...@@ -15,18 +15,25 @@ namespace media { ...@@ -15,18 +15,25 @@ namespace media {
class MEDIA_EXPORT VideoCaptureDeviceFactoryMac : class MEDIA_EXPORT VideoCaptureDeviceFactoryMac :
public VideoCaptureDeviceFactory { public VideoCaptureDeviceFactory {
public: public:
VideoCaptureDeviceFactoryMac(); static bool PlatformSupportsAVFoundation();
virtual ~VideoCaptureDeviceFactoryMac() {}
explicit VideoCaptureDeviceFactoryMac(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
virtual ~VideoCaptureDeviceFactoryMac();
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) OVERRIDE; const VideoCaptureDevice::Name& device_name) OVERRIDE;
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE;
virtual void EnumerateDeviceNames(const base::Callback<
void(scoped_ptr<media::VideoCaptureDevice::Names>)>& callback) OVERRIDE;
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
const VideoCaptureDevice::Name& device, const VideoCaptureDevice::Name& device,
VideoCaptureFormats* supported_formats) OVERRIDE; VideoCaptureFormats* supported_formats) OVERRIDE;
private: private:
// Cache of |ui_task_runner| for enumerating devices there for QTKit.
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryMac); DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryMac);
}; };
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#include "media/video/capture/mac/video_capture_device_factory_mac.h" #include "media/video/capture/mac/video_capture_device_factory_mac.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/task_runner_util.h"
#import "media/video/capture/mac/avfoundation_glue.h" #import "media/video/capture/mac/avfoundation_glue.h"
#include "media/video/capture/mac/video_capture_device_mac.h" #include "media/video/capture/mac/video_capture_device_mac.h"
#import "media/video/capture/mac/video_capture_device_avfoundation_mac.h" #import "media/video/capture/mac/video_capture_device_avfoundation_mac.h"
...@@ -22,26 +25,64 @@ const struct NameAndVid { ...@@ -22,26 +25,64 @@ const struct NameAndVid {
// In device identifiers, the USB VID and PID are stored in 4 bytes each. // In device identifiers, the USB VID and PID are stored in 4 bytes each.
const size_t kVidPidSize = 4; const size_t kVidPidSize = 4;
VideoCaptureDeviceFactoryMac::VideoCaptureDeviceFactoryMac() { static scoped_ptr<media::VideoCaptureDevice::Names>
EnumerateDevicesUsingQTKit() {
scoped_ptr<VideoCaptureDevice::Names> device_names(
new VideoCaptureDevice::Names());
NSMutableDictionary* capture_devices =
[[[NSMutableDictionary alloc] init] autorelease];
[VideoCaptureDeviceQTKit getDeviceNames:capture_devices];
for (NSString* key in capture_devices) {
VideoCaptureDevice::Name name(
[[capture_devices valueForKey:key] UTF8String],
[key UTF8String], VideoCaptureDevice::Name::QTKIT);
device_names->push_back(name);
}
return device_names.Pass();
}
static void RunDevicesEnumeratedCallback(
const base::Callback<void(scoped_ptr<media::VideoCaptureDevice::Names>)>&
callback,
scoped_ptr<media::VideoCaptureDevice::Names> device_names) {
callback.Run(device_names.Pass());
}
// static
bool VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation() {
return AVFoundationGlue::IsAVFoundationSupported();
}
VideoCaptureDeviceFactoryMac::VideoCaptureDeviceFactoryMac(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
: ui_task_runner_(ui_task_runner) {
thread_checker_.DetachFromThread(); thread_checker_.DetachFromThread();
} }
VideoCaptureDeviceFactoryMac::~VideoCaptureDeviceFactoryMac() {}
scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create( scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) { const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(device_name.capture_api_type(), DCHECK_NE(device_name.capture_api_type(),
VideoCaptureDevice::Name::API_TYPE_UNKNOWN); VideoCaptureDevice::Name::API_TYPE_UNKNOWN);
VideoCaptureDevice::Names device_names; // Check device presence only for AVFoundation API, since it is too expensive
GetDeviceNames(&device_names); // and brittle for QTKit. The actual initialization at device level will fail
VideoCaptureDevice::Names::iterator it = device_names.begin(); // subsequently if the device is not present.
for (; it != device_names.end(); ++it) { if (AVFoundationGlue::IsAVFoundationSupported()) {
if (it->id() == device_name.id()) scoped_ptr<VideoCaptureDevice::Names> device_names(
break; new VideoCaptureDevice::Names());
GetDeviceNames(device_names.get());
VideoCaptureDevice::Names::iterator it = device_names->begin();
for (; it != device_names->end(); ++it) {
if (it->id() == device_name.id())
break;
}
if (it == device_names->end())
return scoped_ptr<VideoCaptureDevice>();
} }
if (it == device_names.end())
return scoped_ptr<VideoCaptureDevice>();
scoped_ptr<VideoCaptureDeviceMac> capture_device( scoped_ptr<VideoCaptureDeviceMac> capture_device(
new VideoCaptureDeviceMac(device_name)); new VideoCaptureDeviceMac(device_name));
...@@ -53,7 +94,7 @@ scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create( ...@@ -53,7 +94,7 @@ scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create(
} }
void VideoCaptureDeviceFactoryMac::GetDeviceNames( void VideoCaptureDeviceFactoryMac::GetDeviceNames(
VideoCaptureDevice::Names* const device_names) { VideoCaptureDevice::Names* device_names) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
// Loop through all available devices and add to |device_names|. // Loop through all available devices and add to |device_names|.
NSDictionary* capture_devices; NSDictionary* capture_devices;
...@@ -98,15 +139,25 @@ void VideoCaptureDeviceFactoryMac::GetDeviceNames( ...@@ -98,15 +139,25 @@ void VideoCaptureDeviceFactoryMac::GetDeviceNames(
} }
} }
} }
} else {
// We should not enumerate QTKit devices in Device Thread;
NOTREACHED();
}
}
void VideoCaptureDeviceFactoryMac::EnumerateDeviceNames(const base::Callback<
void(scoped_ptr<media::VideoCaptureDevice::Names>)>& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
if (AVFoundationGlue::IsAVFoundationSupported()) {
scoped_ptr<VideoCaptureDevice::Names> device_names(
new VideoCaptureDevice::Names());
GetDeviceNames(device_names.get());
callback.Run(device_names.Pass());
} else { } else {
DVLOG(1) << "Enumerating video capture devices using QTKit"; DVLOG(1) << "Enumerating video capture devices using QTKit";
capture_devices = [VideoCaptureDeviceQTKit deviceNames]; base::PostTaskAndReplyWithResult(ui_task_runner_, FROM_HERE,
for (NSString* key in capture_devices) { base::Bind(&EnumerateDevicesUsingQTKit),
VideoCaptureDevice::Name name( base::Bind(&RunDevicesEnumeratedCallback, callback));
[[capture_devices valueForKey:key] UTF8String],
[key UTF8String], VideoCaptureDevice::Name::QTKIT);
device_names->push_back(name);
}
} }
} }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/command_line.h" #include "base/command_line.h"
#include "base/message_loop/message_loop_proxy.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#import "media/video/capture/mac/avfoundation_glue.h" #import "media/video/capture/mac/avfoundation_glue.h"
#include "media/video/capture/mac/video_capture_device_factory_mac.h" #include "media/video/capture/mac/video_capture_device_factory_mac.h"
...@@ -23,7 +24,8 @@ TEST_F(VideoCaptureDeviceFactoryMacTest, ListDevicesAVFoundation) { ...@@ -23,7 +24,8 @@ TEST_F(VideoCaptureDeviceFactoryMacTest, ListDevicesAVFoundation) {
DVLOG(1) << "AVFoundation not supported, skipping test."; DVLOG(1) << "AVFoundation not supported, skipping test.";
return; return;
} }
VideoCaptureDeviceFactoryMac video_capture_device_factory; VideoCaptureDeviceFactoryMac video_capture_device_factory(
base::MessageLoopProxy::current());
VideoCaptureDevice::Names names; VideoCaptureDevice::Names names;
video_capture_device_factory.GetDeviceNames(&names); video_capture_device_factory.GetDeviceNames(&names);
......
...@@ -39,7 +39,13 @@ class VideoCaptureDeviceMac; ...@@ -39,7 +39,13 @@ class VideoCaptureDeviceMac;
std::vector<UInt8> adjustedFrame_; std::vector<UInt8> adjustedFrame_;
} }
// Returns a dictionary of capture devices with friendly name and unique id. // Fills up the |deviceNames| dictionary of capture devices with friendly name
// and unique id. No thread assumptions, but this method should run in UI
// thread, see http://crbug.com/139164
+ (void)getDeviceNames:(NSMutableDictionary*)deviceNames;
// Returns a dictionary of capture devices with friendly name and unique id, via
// runing +getDeviceNames: on Main Thread.
+ (NSDictionary*)deviceNames; + (NSDictionary*)deviceNames;
// Initializes the instance and registers the frame receiver. // Initializes the instance and registers the frame receiver.
......
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
namespace media { namespace media {
// static // static
scoped_ptr<VideoCaptureDeviceFactory> scoped_ptr<VideoCaptureDeviceFactory> VideoCaptureDeviceFactory::CreateFactory(
VideoCaptureDeviceFactory::CreateFactory() { scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) {
const CommandLine* command_line = CommandLine::ForCurrentProcess(); const CommandLine* command_line = CommandLine::ForCurrentProcess();
// Use a Fake or File Video Device Factory if the command line flags are // Use a Fake or File Video Device Factory if the command line flags are
// present, otherwise use the normal, platform-dependent, device factory. // present, otherwise use the normal, platform-dependent, device factory.
...@@ -36,15 +36,14 @@ scoped_ptr<VideoCaptureDeviceFactory> ...@@ -36,15 +36,14 @@ scoped_ptr<VideoCaptureDeviceFactory>
media::FakeVideoCaptureDeviceFactory()); media::FakeVideoCaptureDeviceFactory());
} }
} else { } else {
// |ui_task_runner| is needed for the Linux ChromeOS factory to retrieve
// screen rotations and for the Mac factory to run QTKit device enumeration.
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
return scoped_ptr<VideoCaptureDeviceFactory>(new return scoped_ptr<VideoCaptureDeviceFactory>(new
VideoCaptureDeviceFactoryMac()); VideoCaptureDeviceFactoryMac(ui_task_runner));
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
return scoped_ptr<VideoCaptureDeviceFactory>(new return scoped_ptr<VideoCaptureDeviceFactory>(new
VideoCaptureDeviceFactoryLinux()); VideoCaptureDeviceFactoryLinux(ui_task_runner));
#elif defined(OS_LINUX)
return scoped_ptr<VideoCaptureDeviceFactory>(new
VideoCaptureDeviceFactoryLinux());
#elif defined(OS_ANDROID) #elif defined(OS_ANDROID)
return scoped_ptr<VideoCaptureDeviceFactory>(new return scoped_ptr<VideoCaptureDeviceFactory>(new
VideoCaptureDeviceFactoryAndroid()); VideoCaptureDeviceFactoryAndroid());
...@@ -64,25 +63,14 @@ VideoCaptureDeviceFactory::VideoCaptureDeviceFactory() { ...@@ -64,25 +63,14 @@ VideoCaptureDeviceFactory::VideoCaptureDeviceFactory() {
VideoCaptureDeviceFactory::~VideoCaptureDeviceFactory() {} VideoCaptureDeviceFactory::~VideoCaptureDeviceFactory() {}
scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactory::Create( void VideoCaptureDeviceFactory::EnumerateDeviceNames(const base::Callback<
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, void(scoped_ptr<media::VideoCaptureDevice::Names>)>& callback) {
const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread());
return scoped_ptr<VideoCaptureDevice>(
VideoCaptureDevice::Create(ui_task_runner, device_name));
}
void VideoCaptureDeviceFactory::GetDeviceNames(
VideoCaptureDevice::Names* device_names) {
DCHECK(thread_checker_.CalledOnValidThread());
VideoCaptureDevice::GetDeviceNames(device_names);
}
void VideoCaptureDeviceFactory::GetDeviceSupportedFormats(
const VideoCaptureDevice::Name& device,
VideoCaptureFormats* supported_formats) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
VideoCaptureDevice::GetDeviceSupportedFormats(device, supported_formats); DCHECK(!callback.is_null());
scoped_ptr<VideoCaptureDevice::Names> device_names(
new VideoCaptureDevice::Names());
GetDeviceNames(device_names.get());
callback.Run(device_names.Pass());
} }
} // namespace media } // namespace media
...@@ -16,18 +16,19 @@ namespace media { ...@@ -16,18 +16,19 @@ namespace media {
// in Device Thread (a.k.a. Audio Thread). // in Device Thread (a.k.a. Audio Thread).
class MEDIA_EXPORT VideoCaptureDeviceFactory { class MEDIA_EXPORT VideoCaptureDeviceFactory {
public: public:
static scoped_ptr<VideoCaptureDeviceFactory> CreateFactory(); static scoped_ptr<VideoCaptureDeviceFactory> CreateFactory(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner);
VideoCaptureDeviceFactory(); VideoCaptureDeviceFactory();
virtual ~VideoCaptureDeviceFactory(); virtual ~VideoCaptureDeviceFactory();
// Creates a VideoCaptureDevice object. Returns NULL if something goes wrong. // Creates a VideoCaptureDevice object. Returns NULL if something goes wrong.
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, const VideoCaptureDevice::Name& device_name) = 0;
const VideoCaptureDevice::Name& device_name);
// Gets the names of all video capture devices connected to this computer. // Asynchronous version of GetDeviceNames calling back to |callback|.
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names); virtual void EnumerateDeviceNames(const base::Callback<
void(scoped_ptr<media::VideoCaptureDevice::Names>)>& callback);
// Gets the supported formats of a particular device attached to the system. // Gets the supported formats of a particular device attached to the system.
// This method should be called before allocating or starting a device. In // This method should be called before allocating or starting a device. In
...@@ -35,9 +36,13 @@ class MEDIA_EXPORT VideoCaptureDeviceFactory { ...@@ -35,9 +36,13 @@ class MEDIA_EXPORT VideoCaptureDeviceFactory {
// formats array will be empty. // formats array will be empty.
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
const VideoCaptureDevice::Name& device, const VideoCaptureDevice::Name& device,
VideoCaptureFormats* supported_formats); VideoCaptureFormats* supported_formats) = 0;
protected: protected:
// Gets the names of all video capture devices connected to this computer.
// Used by the default implementation of EnumerateDeviceNames().
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) = 0;
base::ThreadChecker thread_checker_; base::ThreadChecker thread_checker_;
private: private:
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop_proxy.h" #include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h" #include "base/run_loop.h"
...@@ -19,6 +21,10 @@ ...@@ -19,6 +21,10 @@
#include "media/video/capture/win/video_capture_device_factory_win.h" #include "media/video/capture/win/video_capture_device_factory_win.h"
#endif #endif
#if defined(OS_MACOSX)
#include "media/video/capture/mac/video_capture_device_factory_mac.h"
#endif
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "media/video/capture/android/video_capture_device_android.h" #include "media/video/capture/android/video_capture_device_android.h"
...@@ -51,6 +57,9 @@ ...@@ -51,6 +57,9 @@
#define MAYBE_CaptureMjpeg CaptureMjpeg #define MAYBE_CaptureMjpeg CaptureMjpeg
#endif #endif
using ::testing::_;
using ::testing::SaveArg;
namespace media { namespace media {
class MockClient : public media::VideoCaptureDevice::Client { class MockClient : public media::VideoCaptureDevice::Client {
...@@ -88,6 +97,21 @@ class MockClient : public media::VideoCaptureDevice::Client { ...@@ -88,6 +97,21 @@ class MockClient : public media::VideoCaptureDevice::Client {
base::Callback<void(const VideoCaptureFormat&)> frame_cb_; base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
}; };
class DeviceEnumerationListener :
public base::RefCounted<DeviceEnumerationListener>{
public:
MOCK_METHOD1(OnEnumeratedDevicesCallbackPtr,
void(media::VideoCaptureDevice::Names* names));
// GMock doesn't support move-only arguments, so we use this forward method.
void OnEnumeratedDevicesCallback(
scoped_ptr<media::VideoCaptureDevice::Names> names) {
OnEnumeratedDevicesCallbackPtr(names.release());
}
private:
friend class base::RefCounted<DeviceEnumerationListener>;
virtual ~DeviceEnumerationListener() {}
};
class VideoCaptureDeviceTest : public testing::Test { class VideoCaptureDeviceTest : public testing::Test {
protected: protected:
typedef media::VideoCaptureDevice::Client Client; typedef media::VideoCaptureDevice::Client Client;
...@@ -97,8 +121,10 @@ class VideoCaptureDeviceTest : public testing::Test { ...@@ -97,8 +121,10 @@ class VideoCaptureDeviceTest : public testing::Test {
client_( client_(
new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured, new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured,
base::Unretained(this)))), base::Unretained(this)))),
video_capture_device_factory_( video_capture_device_factory_(VideoCaptureDeviceFactory::CreateFactory(
VideoCaptureDeviceFactory::CreateFactory()) {} base::MessageLoopProxy::current())) {
device_enumeration_listener_ = new DeviceEnumerationListener();
}
virtual void SetUp() { virtual void SetUp() {
#if defined(OS_ANDROID) #if defined(OS_ANDROID)
...@@ -122,17 +148,29 @@ class VideoCaptureDeviceTest : public testing::Test { ...@@ -122,17 +148,29 @@ class VideoCaptureDeviceTest : public testing::Test {
run_loop_->Run(); run_loop_->Run();
} }
scoped_ptr<media::VideoCaptureDevice::Names> EnumerateDevices() {
media::VideoCaptureDevice::Names* names;
EXPECT_CALL(*device_enumeration_listener_,
OnEnumeratedDevicesCallbackPtr(_)).WillOnce(SaveArg<0>(&names));
video_capture_device_factory_->EnumerateDeviceNames(
base::Bind(&DeviceEnumerationListener::OnEnumeratedDevicesCallback,
device_enumeration_listener_));
base::MessageLoop::current()->RunUntilIdle();
return scoped_ptr<media::VideoCaptureDevice::Names>(names);
}
const VideoCaptureFormat& last_format() const { return last_format_; } const VideoCaptureFormat& last_format() const { return last_format_; }
scoped_ptr<VideoCaptureDevice::Name> GetFirstDeviceNameSupportingPixelFormat( scoped_ptr<VideoCaptureDevice::Name> GetFirstDeviceNameSupportingPixelFormat(
const VideoPixelFormat& pixel_format) { const VideoPixelFormat& pixel_format) {
video_capture_device_factory_->GetDeviceNames(&names_); names_ = EnumerateDevices();
if (!names_.size()) { if (!names_->size()) {
DVLOG(1) << "No camera available."; DVLOG(1) << "No camera available.";
return scoped_ptr<VideoCaptureDevice::Name>(); return scoped_ptr<VideoCaptureDevice::Name>();
} }
VideoCaptureDevice::Names::iterator names_iterator; VideoCaptureDevice::Names::iterator names_iterator;
for (names_iterator = names_.begin(); names_iterator != names_.end(); for (names_iterator = names_->begin(); names_iterator != names_->end();
++names_iterator) { ++names_iterator) {
VideoCaptureFormats supported_formats; VideoCaptureFormats supported_formats;
video_capture_device_factory_->GetDeviceSupportedFormats( video_capture_device_factory_->GetDeviceSupportedFormats(
...@@ -154,10 +192,11 @@ class VideoCaptureDeviceTest : public testing::Test { ...@@ -154,10 +192,11 @@ class VideoCaptureDeviceTest : public testing::Test {
#if defined(OS_WIN) #if defined(OS_WIN)
base::win::ScopedCOMInitializer initialize_com_; base::win::ScopedCOMInitializer initialize_com_;
#endif #endif
VideoCaptureDevice::Names names_; scoped_ptr<VideoCaptureDevice::Names> names_;
scoped_ptr<base::MessageLoop> loop_; scoped_ptr<base::MessageLoop> loop_;
scoped_ptr<base::RunLoop> run_loop_; scoped_ptr<base::RunLoop> run_loop_;
scoped_ptr<MockClient> client_; scoped_ptr<MockClient> client_;
scoped_refptr<DeviceEnumerationListener> device_enumeration_listener_;
VideoCaptureFormat last_format_; VideoCaptureFormat last_format_;
scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_; scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_;
}; };
...@@ -171,29 +210,45 @@ TEST_F(VideoCaptureDeviceTest, OpenInvalidDevice) { ...@@ -171,29 +210,45 @@ TEST_F(VideoCaptureDeviceTest, OpenInvalidDevice) {
VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type); VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type);
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
VideoCaptureDevice::Name device_name("jibberish", "jibberish", VideoCaptureDevice::Name device_name("jibberish", "jibberish",
VideoCaptureDevice::Name::AVFOUNDATION); VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation()
? VideoCaptureDevice::Name::AVFOUNDATION
: VideoCaptureDevice::Name::QTKIT);
#else #else
VideoCaptureDevice::Name device_name("jibberish", "jibberish"); VideoCaptureDevice::Name device_name("jibberish", "jibberish");
#endif #endif
scoped_ptr<VideoCaptureDevice> device = scoped_ptr<VideoCaptureDevice> device =
video_capture_device_factory_->Create( video_capture_device_factory_->Create(device_name);
base::MessageLoopProxy::current(), #if !defined(OS_MACOSX)
device_name);
EXPECT_TRUE(device == NULL); EXPECT_TRUE(device == NULL);
#else
if (VideoCaptureDeviceFactoryMac::PlatformSupportsAVFoundation()) {
EXPECT_TRUE(device == NULL);
} else {
// The presence of the actual device is only checked on AllocateAndStart()
// and not on creation for QTKit API in Mac OS X platform.
EXPECT_CALL(*client_, OnErr()).Times(1);
VideoCaptureParams capture_params;
capture_params.requested_format.frame_size.SetSize(640, 480);
capture_params.requested_format.frame_rate = 30;
capture_params.requested_format.pixel_format = PIXEL_FORMAT_I420;
capture_params.allow_resolution_change = false;
device->AllocateAndStart(capture_params, client_.PassAs<Client>());
}
#endif
} }
TEST_F(VideoCaptureDeviceTest, CaptureVGA) { TEST_F(VideoCaptureDeviceTest, CaptureVGA) {
video_capture_device_factory_->GetDeviceNames(&names_); names_ = EnumerateDevices();
if (!names_.size()) { if (!names_->size()) {
DVLOG(1) << "No camera available. Exiting test."; DVLOG(1) << "No camera available. Exiting test.";
return; return;
} }
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(names_->front()));
names_.front()));
ASSERT_TRUE(device); ASSERT_TRUE(device);
DVLOG(1) << names_.front().id(); DVLOG(1) << names_->front().id();
EXPECT_CALL(*client_, OnErr()) EXPECT_CALL(*client_, OnErr())
.Times(0); .Times(0);
...@@ -212,15 +267,14 @@ TEST_F(VideoCaptureDeviceTest, CaptureVGA) { ...@@ -212,15 +267,14 @@ TEST_F(VideoCaptureDeviceTest, CaptureVGA) {
} }
TEST_F(VideoCaptureDeviceTest, Capture720p) { TEST_F(VideoCaptureDeviceTest, Capture720p) {
video_capture_device_factory_->GetDeviceNames(&names_); names_ = EnumerateDevices();
if (!names_.size()) { if (!names_->size()) {
DVLOG(1) << "No camera available. Exiting test."; DVLOG(1) << "No camera available. Exiting test.";
return; return;
} }
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(names_->front()));
names_.front()));
ASSERT_TRUE(device); ASSERT_TRUE(device);
EXPECT_CALL(*client_, OnErr()) EXPECT_CALL(*client_, OnErr())
...@@ -238,14 +292,13 @@ TEST_F(VideoCaptureDeviceTest, Capture720p) { ...@@ -238,14 +292,13 @@ TEST_F(VideoCaptureDeviceTest, Capture720p) {
} }
TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) { TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
video_capture_device_factory_->GetDeviceNames(&names_); names_ = EnumerateDevices();
if (!names_.size()) { if (!names_->size()) {
DVLOG(1) << "No camera available. Exiting test."; DVLOG(1) << "No camera available. Exiting test.";
return; return;
} }
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(names_->front()));
names_.front()));
ASSERT_TRUE(device); ASSERT_TRUE(device);
EXPECT_CALL(*client_, OnErr()) EXPECT_CALL(*client_, OnErr())
...@@ -264,8 +317,8 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) { ...@@ -264,8 +317,8 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) {
} }
TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) {
video_capture_device_factory_->GetDeviceNames(&names_); names_ = EnumerateDevices();
if (!names_.size()) { if (!names_->size()) {
DVLOG(1) << "No camera available. Exiting test."; DVLOG(1) << "No camera available. Exiting test.";
return; return;
} }
...@@ -274,8 +327,7 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { ...@@ -274,8 +327,7 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) {
for (int i = 0; i <= 5; i++) { for (int i = 0; i <= 5; i++) {
ResetWithNewClient(); ResetWithNewClient();
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(names_->front()));
names_.front()));
gfx::Size resolution; gfx::Size resolution;
if (i % 2) { if (i % 2) {
resolution = gfx::Size(640, 480); resolution = gfx::Size(640, 480);
...@@ -300,8 +352,7 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { ...@@ -300,8 +352,7 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) {
ResetWithNewClient(); ResetWithNewClient();
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(names_->front()));
names_.front()));
device->AllocateAndStart(capture_params, client_.PassAs<Client>()); device->AllocateAndStart(capture_params, client_.PassAs<Client>());
WaitForCapturedFrame(); WaitForCapturedFrame();
...@@ -312,14 +363,13 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { ...@@ -312,14 +363,13 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) {
} }
TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) { TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) {
video_capture_device_factory_->GetDeviceNames(&names_); names_ = EnumerateDevices();
if (!names_.size()) { if (!names_->size()) {
DVLOG(1) << "No camera available. Exiting test."; DVLOG(1) << "No camera available. Exiting test.";
return; return;
} }
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(names_->front()));
names_.front()));
ASSERT_TRUE(device); ASSERT_TRUE(device);
EXPECT_CALL(*client_, OnErr()) EXPECT_CALL(*client_, OnErr())
...@@ -348,8 +398,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) { ...@@ -348,8 +398,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) {
return; return;
} }
scoped_ptr<VideoCaptureDevice> device( scoped_ptr<VideoCaptureDevice> device(
video_capture_device_factory_->Create(base::MessageLoopProxy::current(), video_capture_device_factory_->Create(*name));
*name));
ASSERT_TRUE(device); ASSERT_TRUE(device);
EXPECT_CALL(*client_, OnErr()) EXPECT_CALL(*client_, OnErr())
......
...@@ -387,7 +387,6 @@ VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() { ...@@ -387,7 +387,6 @@ VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() {
scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create( scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) { const VideoCaptureDevice::Name& device_name) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
scoped_ptr<VideoCaptureDevice> device; scoped_ptr<VideoCaptureDevice> device;
......
...@@ -22,7 +22,6 @@ class MEDIA_EXPORT VideoCaptureDeviceFactoryWin : ...@@ -22,7 +22,6 @@ class MEDIA_EXPORT VideoCaptureDeviceFactoryWin :
virtual ~VideoCaptureDeviceFactoryWin() {} virtual ~VideoCaptureDeviceFactoryWin() {}
virtual scoped_ptr<VideoCaptureDevice> Create( virtual scoped_ptr<VideoCaptureDevice> Create(
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
const VideoCaptureDevice::Name& device_name) OVERRIDE; const VideoCaptureDevice::Name& device_name) OVERRIDE;
virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE;
virtual void GetDeviceSupportedFormats( virtual void GetDeviceSupportedFormats(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment