diff options
author | mcasas@chromium.org <mcasas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 15:27:34 +0000 |
---|---|---|
committer | mcasas@chromium.org <mcasas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-09 15:27:34 +0000 |
commit | 7629a77a64629178432fe9f6a0903a2dab3cc641 (patch) | |
tree | ad1ea906f325604c9ff20a1d67c42b6d343723b8 /media | |
parent | 789822be0cb55567d4bfcc3c44d9eb33ca0ed660 (diff) | |
download | chromium_src-7629a77a64629178432fe9f6a0903a2dab3cc641.zip chromium_src-7629a77a64629178432fe9f6a0903a2dab3cc641.tar.gz chromium_src-7629a77a64629178432fe9f6a0903a2dab3cc641.tar.bz2 |
Revert of Mac Video Capture Device: split VCD into VCD and Factory. (https://codereview.chromium.org/265263004/)
Reason for revert:
Some backoffice bots broke due to |kUseFakeDeviceForMediaStream| not being correctly defined - reverting until M36 storm passes and then I'll figure those out.
Original issue's description:
> Mac Video Capture Device: split VCD into VCD and Factory.
>
> VideoCaptureDeviceMac includes factory and non-factory parts.
> This CL splits them into VideoCaptureDeviceMac and
> VideoCaptureDeviceFactoryMac. The latter inherits the previous
> class' static methods: Create(), GetDeviceNames() and
> GetDeviceSupportedFormats().
>
> All video factory code previously in MediaStreamManager is
> moved into VideoCaptureFactory. This includes the use
> of the flag |kUseFakeDeviceForMediaStream|.
> This flag is moved correspondingly into media_switches.cc --
> (but note that this flag is still used in MediaStreamManager for
> the Fake Audio parts). File media_switches.cc is
> included in several test files where the flag is used.
>
>
> VideoCaptureDeviceTest is splitted as well into:
> a) Tests that were exercising only the FakeVCD
> (FakeVideoCaptureDeviceTest).
> b) All other tests, that use the underlying OS webcam.
> This VideoCaptureDeviceTest gets a Factory and uses it
> instead of static methods.
>
> A unit test is added to VCDFMac, doing little for the moment
> but I'm planning to add support for testing at least the
> blacklisting -- req from rsesek@ in another CL.
>
> BUG=288562, 323913, 255552
>
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=269271
TBR=perkj@chromium.org,jochen@chromium.org,dalecurtis@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=288562, 323913, 255552
Review URL: https://codereview.chromium.org/273063002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269312 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r-- | media/base/media_switches.cc | 4 | ||||
-rw-r--r-- | media/base/media_switches.h | 1 | ||||
-rw-r--r-- | media/media.gyp | 10 | ||||
-rw-r--r-- | media/video/capture/fake_video_capture_device_unittest.cc | 180 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_factory_mac.h | 34 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_factory_mac.mm | 125 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_factory_mac_unittest.mm | 42 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_mac.h | 17 | ||||
-rw-r--r-- | media/video/capture/mac/video_capture_device_mac.mm | 114 | ||||
-rw-r--r-- | media/video/capture/video_capture_device_factory.cc | 38 | ||||
-rw-r--r-- | media/video/capture/video_capture_device_factory.h | 4 | ||||
-rw-r--r-- | media/video/capture/video_capture_device_unittest.cc | 142 |
12 files changed, 223 insertions, 488 deletions
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index e7982da..515c0bc 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc @@ -40,7 +40,6 @@ const char kAlsaOutputDevice[] = "alsa-output-device"; // for experimentation purposes, in particular library load time issue, the // usage of this library can be enabled by using this flag. const char kEnableAVFoundation[] = "enable-avfoundation"; - // QTKit is the media capture API predecessor to AVFoundation, available up and // until Mac OS X 10.9 (despite being deprecated in this last one). This flag // is used for troubleshooting and testing, and forces QTKit in builds and @@ -86,9 +85,6 @@ const char kWaveOutBuffers[] = "waveout-buffers"; const char kUseCras[] = "use-cras"; #endif -// Use fake device for Media Stream to replace actual camera and microphone. -const char kUseFakeDeviceForMediaStream[] = "use-fake-device-for-media-stream"; - // Use a raw video file as fake video capture device. const char kUseFileForFakeVideoCapture[] = "use-file-for-fake-video-capture"; diff --git a/media/base/media_switches.h b/media/base/media_switches.h index a225a18..90a25f4 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h @@ -46,7 +46,6 @@ MEDIA_EXPORT extern const char kWaveOutBuffers[]; MEDIA_EXPORT extern const char kUseCras[]; #endif -MEDIA_EXPORT extern const char kUseFakeDeviceForMediaStream[]; MEDIA_EXPORT extern const char kUseFileForFakeVideoCapture[]; } // namespace switches diff --git a/media/media.gyp b/media/media.gyp index ddc91fa..a799028 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -52,7 +52,7 @@ 'type': '<(component)', 'dependencies': [ '../base/base.gyp:base', - '../base/base.gyp:base_i18n', + '../base/base.gyp:base_i18n', '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '../crypto/crypto.gyp:crypto', '../gpu/gpu.gyp:command_buffer_common', @@ -475,8 +475,6 @@ 'video/capture/mac/platform_video_capturing_mac.h', 'video/capture/mac/video_capture_device_avfoundation_mac.h', 'video/capture/mac/video_capture_device_avfoundation_mac.mm', - 'video/capture/mac/video_capture_device_factory_mac.h', - 'video/capture/mac/video_capture_device_factory_mac.mm', 'video/capture/mac/video_capture_device_mac.h', 'video/capture/mac/video_capture_device_mac.mm', 'video/capture/mac/video_capture_device_qtkit_mac.h', @@ -1065,7 +1063,6 @@ 'midi/usb_midi_descriptor_parser_unittest.cc', 'midi/usb_midi_input_stream_unittest.cc', 'midi/usb_midi_output_stream_unittest.cc', - 'video/capture/fake_video_capture_device_unittest.cc', 'video/capture/video_capture_device_unittest.cc', 'formats/common/offset_byte_queue_unittest.cc', 'formats/webm/cluster_builder.cc', @@ -1196,11 +1193,6 @@ ['OS=="win" and target_arch=="x64"', { 'msvs_disabled_warnings': [ 4267, ], }], - ['OS=="mac"', { - 'sources': [ - 'video/capture/mac/video_capture_device_factory_mac_unittest.mm', - ] - }], ], }, { diff --git a/media/video/capture/fake_video_capture_device_unittest.cc b/media/video/capture/fake_video_capture_device_unittest.cc deleted file mode 100644 index 9bbbe67..0000000 --- a/media/video/capture/fake_video_capture_device_unittest.cc +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright 2014 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. - -#include "base/bind.h" -#include "base/memory/scoped_ptr.h" -#include "base/run_loop.h" -#include "base/test/test_timeouts.h" -#include "base/threading/thread.h" -#include "media/video/capture/fake_video_capture_device.h" -#include "media/video/capture/fake_video_capture_device_factory.h" -#include "media/video/capture/video_capture_device.h" -#include "media/video/capture/video_capture_types.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using ::testing::_; - -namespace media { - -class MockClient : public media::VideoCaptureDevice::Client { - public: - MOCK_METHOD2(ReserveOutputBuffer, - scoped_refptr<Buffer>(media::VideoFrame::Format format, - const gfx::Size& dimensions)); - MOCK_METHOD0(OnErr, void()); - - explicit MockClient(base::Callback<void(const VideoCaptureFormat&)> frame_cb) - : main_thread_(base::MessageLoopProxy::current()), frame_cb_(frame_cb) {} - - virtual void OnError(const std::string& error_message) OVERRIDE { - OnErr(); - } - - virtual void OnIncomingCapturedData(const uint8* data, - int length, - const VideoCaptureFormat& format, - int rotation, - base::TimeTicks timestamp) OVERRIDE { - main_thread_->PostTask(FROM_HERE, base::Bind(frame_cb_, format)); - } - - virtual void OnIncomingCapturedVideoFrame( - const scoped_refptr<Buffer>& buffer, - const media::VideoCaptureFormat& buffer_format, - const scoped_refptr<media::VideoFrame>& frame, - base::TimeTicks timestamp) OVERRIDE { - NOTREACHED(); - } - - private: - scoped_refptr<base::SingleThreadTaskRunner> main_thread_; - base::Callback<void(const VideoCaptureFormat&)> frame_cb_; -}; - -class FakeVideoCaptureDeviceTest : public testing::Test { - protected: - typedef media::VideoCaptureDevice::Client Client; - - FakeVideoCaptureDeviceTest() - : loop_(new base::MessageLoop()), - client_(new MockClient( - base::Bind(&FakeVideoCaptureDeviceTest::OnFrameCaptured, - base::Unretained(this)))), - video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {} - - virtual void SetUp() { - } - - void OnFrameCaptured(const VideoCaptureFormat& format) { - last_format_ = format; - run_loop_->QuitClosure().Run(); - } - - void WaitForCapturedFrame() { - run_loop_.reset(new base::RunLoop()); - run_loop_->Run(); - } - - const VideoCaptureFormat& last_format() const { return last_format_; } - - VideoCaptureDevice::Names names_; - scoped_ptr<base::MessageLoop> loop_; - scoped_ptr<base::RunLoop> run_loop_; - scoped_ptr<MockClient> client_; - VideoCaptureFormat last_format_; - scoped_ptr<VideoCaptureDeviceFactory> video_capture_device_factory_; -}; - -TEST_F(FakeVideoCaptureDeviceTest, Capture) { - VideoCaptureDevice::Names names; - - video_capture_device_factory_->GetDeviceNames(&names); - - ASSERT_GT(static_cast<int>(names.size()), 0); - - scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names.front())); - ASSERT_TRUE(device); - - EXPECT_CALL(*client_, OnErr()).Times(0); - - 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>()); - WaitForCapturedFrame(); - EXPECT_EQ(last_format().frame_size.width(), 640); - EXPECT_EQ(last_format().frame_size.height(), 480); - EXPECT_EQ(last_format().frame_rate, 30); - device->StopAndDeAllocate(); -} - -TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) { - VideoCaptureDevice::Names names; - video_capture_device_factory_->GetDeviceNames(&names); - - VideoCaptureFormats supported_formats; - VideoCaptureDevice::Names::iterator names_iterator; - - for (names_iterator = names.begin(); names_iterator != names.end(); - ++names_iterator) { - video_capture_device_factory_->GetDeviceSupportedFormats( - *names_iterator, &supported_formats); - EXPECT_EQ(supported_formats.size(), 3u); - EXPECT_EQ(supported_formats[0].frame_size.width(), 320); - EXPECT_EQ(supported_formats[0].frame_size.height(), 240); - EXPECT_EQ(supported_formats[0].pixel_format, media::PIXEL_FORMAT_I420); - EXPECT_GE(supported_formats[0].frame_rate, 20); - EXPECT_EQ(supported_formats[1].frame_size.width(), 640); - EXPECT_EQ(supported_formats[1].frame_size.height(), 480); - EXPECT_EQ(supported_formats[1].pixel_format, media::PIXEL_FORMAT_I420); - EXPECT_GE(supported_formats[1].frame_rate, 20); - EXPECT_EQ(supported_formats[2].frame_size.width(), 1280); - EXPECT_EQ(supported_formats[2].frame_size.height(), 720); - EXPECT_EQ(supported_formats[2].pixel_format, media::PIXEL_FORMAT_I420); - EXPECT_GE(supported_formats[2].frame_rate, 20); - } -} - -TEST_F(FakeVideoCaptureDeviceTest, CaptureVariableResolution) { - VideoCaptureDevice::Names names; - - video_capture_device_factory_->GetDeviceNames(&names); - 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 = true; - - ASSERT_GT(static_cast<int>(names.size()), 0); - - scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names.front())); - ASSERT_TRUE(device); - - // Configure the FakeVideoCaptureDevice to use all its formats as roster. - VideoCaptureFormats formats; - video_capture_device_factory_->GetDeviceSupportedFormats(names.front(), - &formats); - static_cast<FakeVideoCaptureDevice*>(device.get())-> - PopulateVariableFormatsRoster(formats); - - EXPECT_CALL(*client_, OnErr()) - .Times(0); - int action_count = 200; - - device->AllocateAndStart(capture_params, client_.PassAs<Client>()); - - // We set TimeWait to 200 action timeouts and this should be enough for at - // least action_count/kFakeCaptureCapabilityChangePeriod calls. - for (int i = 0; i < action_count; ++i) { - WaitForCapturedFrame(); - } - device->StopAndDeAllocate(); -} - -}; // namespace media diff --git a/media/video/capture/mac/video_capture_device_factory_mac.h b/media/video/capture/mac/video_capture_device_factory_mac.h deleted file mode 100644 index a581925..0000000 --- a/media/video/capture/mac/video_capture_device_factory_mac.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2014 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 of a VideoCaptureDeviceFactory class for Mac. - -#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_MAC_H_ -#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_MAC_H_ - -#include "media/video/capture/video_capture_device_factory.h" - -namespace media { - -// Extension of VideoCaptureDeviceFactory to create and manipulate Mac devices. -class MEDIA_EXPORT VideoCaptureDeviceFactoryMac : - public VideoCaptureDeviceFactory { - public: - VideoCaptureDeviceFactoryMac(); - virtual ~VideoCaptureDeviceFactoryMac() {} - - virtual scoped_ptr<VideoCaptureDevice> Create( - const VideoCaptureDevice::Name& device_name) OVERRIDE; - virtual void GetDeviceNames(VideoCaptureDevice::Names* device_names) OVERRIDE; - virtual void GetDeviceSupportedFormats( - const VideoCaptureDevice::Name& device, - VideoCaptureFormats* supported_formats) OVERRIDE; - - private: - DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryMac); -}; - -} // namespace media - -#endif // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_MAC_H_ diff --git a/media/video/capture/mac/video_capture_device_factory_mac.mm b/media/video/capture/mac/video_capture_device_factory_mac.mm deleted file mode 100644 index 0e24203..0000000 --- a/media/video/capture/mac/video_capture_device_factory_mac.mm +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2014 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. - -#include "media/video/capture/mac/video_capture_device_factory_mac.h" - -#import "media/video/capture/mac/avfoundation_glue.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_qtkit_mac.h" - -namespace media { - -// Some devices are not correctly supported in AVFoundation, f.i. Blackmagic, -// see http://crbug.com/347371. The devices are identified by USB Vendor ID and -// by a characteristic substring of the name, usually the vendor's name. -const struct NameAndVid { - const char* vid; - const char* name; -} kBlacklistedCameras[] = { { "a82c", "Blackmagic" } }; - -// In device identifiers, the USB VID and PID are stored in 4 bytes each. -const size_t kVidPidSize = 4; - -VideoCaptureDeviceFactoryMac::VideoCaptureDeviceFactoryMac() { - thread_checker_.DetachFromThread(); -} - -scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryMac::Create( - const VideoCaptureDevice::Name& device_name) { - DCHECK(thread_checker_.CalledOnValidThread()); - DCHECK_NE(device_name.capture_api_type(), - VideoCaptureDevice::Name::API_TYPE_UNKNOWN); - - VideoCaptureDevice::Names device_names; - GetDeviceNames(&device_names); - 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>(); - - scoped_ptr<VideoCaptureDeviceMac> capture_device( - new VideoCaptureDeviceMac(device_name)); - if (!capture_device->Init(device_name.capture_api_type())) { - LOG(ERROR) << "Could not initialize VideoCaptureDevice."; - capture_device.reset(); - } - return scoped_ptr<VideoCaptureDevice>(capture_device.Pass()); -} - -void VideoCaptureDeviceFactoryMac::GetDeviceNames( - VideoCaptureDevice::Names* const device_names) { - DCHECK(thread_checker_.CalledOnValidThread()); - // Loop through all available devices and add to |device_names|. - NSDictionary* capture_devices; - if (AVFoundationGlue::IsAVFoundationSupported()) { - bool is_any_device_blacklisted = false; - DVLOG(1) << "Enumerating video capture devices using AVFoundation"; - capture_devices = [VideoCaptureDeviceAVFoundation deviceNames]; - std::string device_vid; - // Enumerate all devices found by AVFoundation, translate the info for each - // to class Name and add it to |device_names|. - for (NSString* key in capture_devices) { - VideoCaptureDevice::Name name( - [[capture_devices valueForKey:key] UTF8String], - [key UTF8String], VideoCaptureDevice::Name::AVFOUNDATION); - device_names->push_back(name); - // Extract the device's Vendor ID and compare to all blacklisted ones. - device_vid = name.GetModel().substr(0, kVidPidSize); - for (size_t i = 0; i < arraysize(kBlacklistedCameras); ++i) { - is_any_device_blacklisted |= - !strcasecmp(device_vid.c_str(), kBlacklistedCameras[i].vid); - if (is_any_device_blacklisted) - break; - } - } - // If there is any device blacklisted in the system, walk the QTKit device - // list and add those devices with a blacklisted name to the |device_names|. - // AVFoundation and QTKit device lists partially overlap, so add a "QTKit" - // prefix to the latter ones to distinguish them from the AVFoundation ones. - if (is_any_device_blacklisted) { - capture_devices = [VideoCaptureDeviceQTKit deviceNames]; - for (NSString* key in capture_devices) { - NSString* device_name = [capture_devices valueForKey:key]; - for (size_t i = 0; i < arraysize(kBlacklistedCameras); ++i) { - if ([device_name rangeOfString:@(kBlacklistedCameras[i].name) - options:NSCaseInsensitiveSearch].length != 0) { - DVLOG(1) << "Enumerated blacklisted " << [device_name UTF8String]; - VideoCaptureDevice::Name name( - "QTKit " + std::string([device_name UTF8String]), - [key UTF8String], VideoCaptureDevice::Name::QTKIT); - device_names->push_back(name); - } - } - } - } - } else { - DVLOG(1) << "Enumerating video capture devices using QTKit"; - capture_devices = [VideoCaptureDeviceQTKit deviceNames]; - for (NSString* key in capture_devices) { - VideoCaptureDevice::Name name( - [[capture_devices valueForKey:key] UTF8String], - [key UTF8String], VideoCaptureDevice::Name::QTKIT); - device_names->push_back(name); - } - } -} - -void VideoCaptureDeviceFactoryMac::GetDeviceSupportedFormats( - const VideoCaptureDevice::Name& device, - VideoCaptureFormats* supported_formats) { - DCHECK(thread_checker_.CalledOnValidThread()); - if (device.capture_api_type() == VideoCaptureDevice::Name::AVFOUNDATION) { - DVLOG(1) << "Enumerating video capture capabilities, AVFoundation"; - [VideoCaptureDeviceAVFoundation getDevice:device - supportedFormats:supported_formats]; - } else { - NOTIMPLEMENTED(); - } -} - -} // namespace media diff --git a/media/video/capture/mac/video_capture_device_factory_mac_unittest.mm b/media/video/capture/mac/video_capture_device_factory_mac_unittest.mm deleted file mode 100644 index 6aa23a9..0000000 --- a/media/video/capture/mac/video_capture_device_factory_mac_unittest.mm +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2014 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. - -#include "base/command_line.h" -#include "media/base/media_switches.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_mac.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { - -class VideoCaptureDeviceFactoryMacTest : public testing::Test { - virtual void SetUp() { - CommandLine::ForCurrentProcess()->AppendSwitch( - switches::kEnableAVFoundation); - } -}; - -TEST_F(VideoCaptureDeviceFactoryMacTest, ListDevicesAVFoundation) { - if (!AVFoundationGlue::IsAVFoundationSupported()) { - DVLOG(1) << "AVFoundation not supported, skipping test."; - return; - } - VideoCaptureDeviceFactoryMac video_capture_device_factory; - - VideoCaptureDevice::Names names; - video_capture_device_factory.GetDeviceNames(&names); - if (!names.size()) { - DVLOG(1) << "No camera available. Exiting test."; - return; - } - // There should be no blacklisted devices, i.e. QTKit. - std::string device_vid; - for (VideoCaptureDevice::Names::const_iterator it = names.begin(); - it != names.end(); ++it) { - EXPECT_EQ(it->capture_api_type(), VideoCaptureDevice::Name::AVFOUNDATION); - } -} - -}; // namespace media diff --git a/media/video/capture/mac/video_capture_device_mac.h b/media/video/capture/mac/video_capture_device_mac.h index b28dacb..3b12d83 100644 --- a/media/video/capture/mac/video_capture_device_mac.h +++ b/media/video/capture/mac/video_capture_device_mac.h @@ -3,9 +3,8 @@ // found in the LICENSE file. // MacOSX implementation of generic VideoCaptureDevice, using either QTKit or -// AVFoundation as native capture API. QTKit is available in all OSX versions, -// although namely deprecated in 10.9, and AVFoundation is available in versions -// 10.7 (Lion) and later. +// AVFoundation as native capture API. QTKit is used in OSX versions 10.6 and +// previous, and AVFoundation is used in the rest. #ifndef MEDIA_VIDEO_CAPTURE_MAC_VIDEO_CAPTURE_DEVICE_MAC_H_ #define MEDIA_VIDEO_CAPTURE_MAC_VIDEO_CAPTURE_DEVICE_MAC_H_ @@ -26,20 +25,20 @@ class SingleThreadTaskRunner; namespace media { -// Called by VideoCaptureManager to open, close and start, stop Mac video -// capture devices. +// Called by VideoCaptureManager to open, close and start, stop video capture +// devices. class VideoCaptureDeviceMac : public VideoCaptureDevice { public: explicit VideoCaptureDeviceMac(const Name& device_name); virtual ~VideoCaptureDeviceMac(); // VideoCaptureDevice implementation. - virtual void AllocateAndStart( - const VideoCaptureParams& params, - scoped_ptr<VideoCaptureDevice::Client> client) OVERRIDE; + virtual void AllocateAndStart(const VideoCaptureParams& params, + scoped_ptr<VideoCaptureDevice::Client> client) + OVERRIDE; virtual void StopAndDeAllocate() OVERRIDE; - bool Init(VideoCaptureDevice::Name::CaptureApiType capture_api_type); + bool Init(); // Called to deliver captured video frames. void ReceiveFrame(const uint8* video_frame, diff --git a/media/video/capture/mac/video_capture_device_mac.mm b/media/video/capture/mac/video_capture_device_mac.mm index 5aacd26..bc3d541 100644 --- a/media/video/capture/mac/video_capture_device_mac.mm +++ b/media/video/capture/mac/video_capture_device_mac.mm @@ -22,6 +22,14 @@ const int kMaxFrameRate = 30; // In device identifiers, the USB VID and PID are stored in 4 bytes each. const size_t kVidPidSize = 4; +// Some devices are not correctly supported in AVFoundation, f.i. Blackmagic, +// see http://crbug.com/347371. The devices are identified by USB Vendor ID and +// by a characteristic substring of the name, usually the vendor's name. +const struct NameAndVid { + const char* vid; + const char* name; +} kBlacklistedCameras[] = { { "a82c", "Blackmagic" } }; + const struct Resolution { const int width; const int height; @@ -61,26 +69,70 @@ void GetBestMatchSupportedResolution(int* width, int* height) { *height = matched_height; } -// TODO(mcasas): Remove the following static methods when they are no longer -// referenced from VideoCaptureDeviceFactory, i.e. when all OS platforms have -// splitted the VideoCaptureDevice into VideoCaptureDevice and -// VideoCaptureDeviceFactory. - -// static -VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { - NOTREACHED(); - return NULL; -} -// static +//static void VideoCaptureDevice::GetDeviceNames(Names* device_names) { - NOTREACHED(); + // Loop through all available devices and add to |device_names|. + NSDictionary* capture_devices; + if (AVFoundationGlue::IsAVFoundationSupported()) { + bool is_any_device_blacklisted = false; + DVLOG(1) << "Enumerating video capture devices using AVFoundation"; + capture_devices = [VideoCaptureDeviceAVFoundation deviceNames]; + std::string device_vid; + // Enumerate all devices found by AVFoundation, translate the info for each + // to class Name and add it to |device_names|. + for (NSString* key in capture_devices) { + Name name([[capture_devices valueForKey:key] UTF8String], + [key UTF8String], Name::AVFOUNDATION); + device_names->push_back(name); + // Extract the device's Vendor ID and compare to all blacklisted ones. + device_vid = name.GetModel().substr(0, kVidPidSize); + for (size_t i = 0; i < arraysize(kBlacklistedCameras); ++i) { + is_any_device_blacklisted |= + !strcasecmp(device_vid.c_str(), kBlacklistedCameras[i].vid); + if (is_any_device_blacklisted) + break; + } + } + // If there is any device blacklisted in the system, walk the QTKit device + // list and add those devices with a blacklisted name to the |device_names|. + // AVFoundation and QTKit device lists partially overlap, so add a "QTKit" + // prefix to the latter ones to distinguish them from the AVFoundation ones. + if (is_any_device_blacklisted) { + capture_devices = [VideoCaptureDeviceQTKit deviceNames]; + for (NSString* key in capture_devices) { + NSString* device_name = [capture_devices valueForKey:key]; + for (size_t i = 0; i < arraysize(kBlacklistedCameras); ++i) { + if ([device_name rangeOfString:@(kBlacklistedCameras[i].name) + options:NSCaseInsensitiveSearch].length != 0) { + DVLOG(1) << "Enumerated blacklisted " << [device_name UTF8String]; + Name name("QTKit " + std::string([device_name UTF8String]), + [key UTF8String], Name::QTKIT); + device_names->push_back(name); + } + } + } + } + } else { + DVLOG(1) << "Enumerating video capture devices using QTKit"; + capture_devices = [VideoCaptureDeviceQTKit deviceNames]; + for (NSString* key in capture_devices) { + Name name([[capture_devices valueForKey:key] UTF8String], + [key UTF8String], Name::QTKIT); + device_names->push_back(name); + } + } } // static -void VideoCaptureDevice::GetDeviceSupportedFormats( - const Name& device, - VideoCaptureFormats* supported_formats) { - NOTREACHED(); +void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device, + VideoCaptureFormats* formats) { + if (device.capture_api_type() == Name::AVFOUNDATION) { + DVLOG(1) << "Enumerating video capture capabilities, AVFoundation"; + [VideoCaptureDeviceAVFoundation getDevice:device + supportedFormats:formats]; + } else { + NOTIMPLEMENTED(); + } } const std::string VideoCaptureDevice::Name::GetModel() const { @@ -98,6 +150,17 @@ const std::string VideoCaptureDevice::Name::GetModel() const { return id_vendor + ":" + id_product; } +VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) { + VideoCaptureDeviceMac* capture_device = + new VideoCaptureDeviceMac(device_name); + if (!capture_device->Init()) { + LOG(ERROR) << "Could not initialize VideoCaptureDevice."; + delete capture_device; + capture_device = NULL; + } + return capture_device; +} + VideoCaptureDeviceMac::VideoCaptureDeviceMac(const Name& device_name) : device_name_(device_name), tried_to_square_pixels_(false), @@ -181,12 +244,25 @@ void VideoCaptureDeviceMac::StopAndDeAllocate() { tried_to_square_pixels_ = false; } -bool VideoCaptureDeviceMac::Init( - VideoCaptureDevice::Name::CaptureApiType capture_api_type) { +bool VideoCaptureDeviceMac::Init() { DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(state_, kNotInitialized); - if (capture_api_type == Name::AVFOUNDATION) { + // TODO(mcasas): The following check might not be necessary; if the device has + // disappeared after enumeration and before coming here, opening would just + // fail but not necessarily produce a crash. + Names device_names; + GetDeviceNames(&device_names); + 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 false; + + DCHECK_NE(it->capture_api_type(), Name::API_TYPE_UNKNOWN); + if (it->capture_api_type() == Name::AVFOUNDATION) { capture_device_ = [[VideoCaptureDeviceAVFoundation alloc] initWithFrameReceiver:this]; } else { diff --git a/media/video/capture/video_capture_device_factory.cc b/media/video/capture/video_capture_device_factory.cc index 661900c..e63225d 100644 --- a/media/video/capture/video_capture_device_factory.cc +++ b/media/video/capture/video_capture_device_factory.cc @@ -4,47 +4,11 @@ #include "media/video/capture/video_capture_device_factory.h" -#include "base/command_line.h" -#include "media/base/media_switches.h" -#include "media/video/capture/fake_video_capture_device_factory.h" -#include "media/video/capture/file_video_capture_device_factory.h" - -#if defined(OS_MACOSX) -#include "media/video/capture/mac/video_capture_device_factory_mac.h" -#endif - namespace media { -// static -scoped_ptr<VideoCaptureDeviceFactory> - VideoCaptureDeviceFactory::CreateFactory() { - const CommandLine* command_line = CommandLine::ForCurrentProcess(); - // Use a Fake or File Video Device Factory if the command line flags are - // present, otherwise use the normal, platform-dependent, device factory. - if (command_line->HasSwitch(switches::kUseFakeDeviceForMediaStream)) { - if (command_line->HasSwitch(switches::kUseFileForFakeVideoCapture)) { - return scoped_ptr<VideoCaptureDeviceFactory>(new - media::FileVideoCaptureDeviceFactory()); - } else { - return scoped_ptr<VideoCaptureDeviceFactory>(new - media::FakeVideoCaptureDeviceFactory()); - } - } else { -#if defined(OS_MACOSX) - return scoped_ptr<VideoCaptureDeviceFactory>(new - VideoCaptureDeviceFactoryMac()); -#else - return scoped_ptr<VideoCaptureDeviceFactory>(new - VideoCaptureDeviceFactory()); -#endif - } -} - VideoCaptureDeviceFactory::VideoCaptureDeviceFactory() { thread_checker_.DetachFromThread(); -} - -VideoCaptureDeviceFactory::~VideoCaptureDeviceFactory() {} +}; scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactory::Create( const VideoCaptureDevice::Name& device_name) { diff --git a/media/video/capture/video_capture_device_factory.h b/media/video/capture/video_capture_device_factory.h index 4a19e83..ab58ad6 100644 --- a/media/video/capture/video_capture_device_factory.h +++ b/media/video/capture/video_capture_device_factory.h @@ -16,10 +16,8 @@ namespace media { // in Device Thread (a.k.a. Audio Thread). class MEDIA_EXPORT VideoCaptureDeviceFactory { public: - static scoped_ptr<VideoCaptureDeviceFactory> CreateFactory(); - VideoCaptureDeviceFactory(); - virtual ~VideoCaptureDeviceFactory(); + virtual ~VideoCaptureDeviceFactory() {} // Creates a VideoCaptureDevice object. Returns NULL if something goes wrong. virtual scoped_ptr<VideoCaptureDevice> Create( diff --git a/media/video/capture/video_capture_device_unittest.cc b/media/video/capture/video_capture_device_unittest.cc index e897d20..f079a1f 100644 --- a/media/video/capture/video_capture_device_unittest.cc +++ b/media/video/capture/video_capture_device_unittest.cc @@ -3,12 +3,15 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" +#include "base/synchronization/waitable_event.h" #include "base/test/test_timeouts.h" #include "base/threading/thread.h" +#include "media/video/capture/fake_video_capture_device.h" +#include "media/video/capture/fake_video_capture_device_factory.h" #include "media/video/capture/video_capture_device.h" -#include "media/video/capture/video_capture_device_factory.h" #include "media/video/capture/video_capture_types.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -50,6 +53,11 @@ #define MAYBE_CaptureMjpeg CaptureMjpeg #endif +using ::testing::_; +using ::testing::AnyNumber; +using ::testing::Return; +using ::testing::AtLeast; + namespace media { class MockClient : public media::VideoCaptureDevice::Client { @@ -96,8 +104,7 @@ class VideoCaptureDeviceTest : public testing::Test { client_( new MockClient(base::Bind(&VideoCaptureDeviceTest::OnFrameCaptured, base::Unretained(this)))), - video_capture_device_factory_( - VideoCaptureDeviceFactory::CreateFactory()) {} + video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {} virtual void SetUp() { #if defined(OS_ANDROID) @@ -125,7 +132,7 @@ class VideoCaptureDeviceTest : public testing::Test { scoped_ptr<VideoCaptureDevice::Name> GetFirstDeviceNameSupportingPixelFormat( const VideoPixelFormat& pixel_format) { - video_capture_device_factory_->GetDeviceNames(&names_); + VideoCaptureDevice::GetDeviceNames(&names_); if (!names_.size()) { DVLOG(1) << "No camera available."; return scoped_ptr<VideoCaptureDevice::Name>(); @@ -134,9 +141,8 @@ class VideoCaptureDeviceTest : public testing::Test { for (names_iterator = names_.begin(); names_iterator != names_.end(); ++names_iterator) { VideoCaptureFormats supported_formats; - video_capture_device_factory_->GetDeviceSupportedFormats( - *names_iterator, - &supported_formats); + VideoCaptureDevice::GetDeviceSupportedFormats(*names_iterator, + &supported_formats); VideoCaptureFormats::iterator formats_iterator; for (formats_iterator = supported_formats.begin(); formats_iterator != supported_formats.end(); ++formats_iterator) { @@ -168,26 +174,22 @@ TEST_F(VideoCaptureDeviceTest, OpenInvalidDevice) { ? VideoCaptureDevice::Name::MEDIA_FOUNDATION : VideoCaptureDevice::Name::DIRECT_SHOW; VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type); -#elif defined(OS_MACOSX) - VideoCaptureDevice::Name device_name("jibberish", "jibberish", - VideoCaptureDevice::Name::AVFOUNDATION); #else VideoCaptureDevice::Name device_name("jibberish", "jibberish"); #endif - scoped_ptr<VideoCaptureDevice> device = - video_capture_device_factory_->Create(device_name); + VideoCaptureDevice* device = VideoCaptureDevice::Create(device_name); EXPECT_TRUE(device == NULL); } TEST_F(VideoCaptureDeviceTest, CaptureVGA) { - video_capture_device_factory_->GetDeviceNames(&names_); + VideoCaptureDevice::GetDeviceNames(&names_); if (!names_.size()) { DVLOG(1) << "No camera available. Exiting test."; return; } scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names_.front())); + VideoCaptureDevice::Create(names_.front())); ASSERT_TRUE(device); DVLOG(1) << names_.front().id(); @@ -208,14 +210,14 @@ TEST_F(VideoCaptureDeviceTest, CaptureVGA) { } TEST_F(VideoCaptureDeviceTest, Capture720p) { - video_capture_device_factory_->GetDeviceNames(&names_); + VideoCaptureDevice::GetDeviceNames(&names_); if (!names_.size()) { DVLOG(1) << "No camera available. Exiting test."; return; } scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names_.front())); + VideoCaptureDevice::Create(names_.front())); ASSERT_TRUE(device); EXPECT_CALL(*client_, OnErr()) @@ -233,13 +235,13 @@ TEST_F(VideoCaptureDeviceTest, Capture720p) { } TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) { - video_capture_device_factory_->GetDeviceNames(&names_); + VideoCaptureDevice::GetDeviceNames(&names_); if (!names_.size()) { DVLOG(1) << "No camera available. Exiting test."; return; } scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names_.front())); + VideoCaptureDevice::Create(names_.front())); ASSERT_TRUE(device); EXPECT_CALL(*client_, OnErr()) @@ -258,7 +260,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_AllocateBadSize) { } TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { - video_capture_device_factory_->GetDeviceNames(&names_); + VideoCaptureDevice::GetDeviceNames(&names_); if (!names_.size()) { DVLOG(1) << "No camera available. Exiting test."; return; @@ -268,7 +270,7 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { for (int i = 0; i <= 5; i++) { ResetWithNewClient(); scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names_.front())); + VideoCaptureDevice::Create(names_.front())); gfx::Size resolution; if (i % 2) { resolution = gfx::Size(640, 480); @@ -293,7 +295,7 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { ResetWithNewClient(); scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names_.front())); + VideoCaptureDevice::Create(names_.front())); device->AllocateAndStart(capture_params, client_.PassAs<Client>()); WaitForCapturedFrame(); @@ -304,13 +306,13 @@ TEST_F(VideoCaptureDeviceTest, ReAllocateCamera) { } TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) { - video_capture_device_factory_->GetDeviceNames(&names_); + VideoCaptureDevice::GetDeviceNames(&names_); if (!names_.size()) { DVLOG(1) << "No camera available. Exiting test."; return; } scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(names_.front())); + VideoCaptureDevice::Create(names_.front())); ASSERT_TRUE(device); EXPECT_CALL(*client_, OnErr()) @@ -330,6 +332,33 @@ TEST_F(VideoCaptureDeviceTest, DeAllocateCameraWhileRunning) { device->StopAndDeAllocate(); } +TEST_F(VideoCaptureDeviceTest, FakeCapture) { + VideoCaptureDevice::Names names; + + video_capture_device_factory_->GetDeviceNames(&names); + + ASSERT_GT(static_cast<int>(names.size()), 0); + + scoped_ptr<VideoCaptureDevice> device( + video_capture_device_factory_->Create(names.front())); + ASSERT_TRUE(device); + + EXPECT_CALL(*client_, OnErr()) + .Times(0); + + 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>()); + WaitForCapturedFrame(); + EXPECT_EQ(last_format().frame_size.width(), 640); + EXPECT_EQ(last_format().frame_size.height(), 480); + EXPECT_EQ(last_format().frame_rate, 30); + device->StopAndDeAllocate(); +} + // Start the camera in 720p to capture MJPEG instead of a raw format. TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) { scoped_ptr<VideoCaptureDevice::Name> name = @@ -338,8 +367,7 @@ TEST_F(VideoCaptureDeviceTest, MAYBE_CaptureMjpeg) { DVLOG(1) << "No camera supports MJPEG format. Exiting test."; return; } - scoped_ptr<VideoCaptureDevice> device( - video_capture_device_factory_->Create(*name)); + scoped_ptr<VideoCaptureDevice> device(VideoCaptureDevice::Create(*name)); ASSERT_TRUE(device); EXPECT_CALL(*client_, OnErr()) @@ -369,4 +397,68 @@ TEST_F(VideoCaptureDeviceTest, GetDeviceSupportedFormats) { ASSERT_FALSE(name); } +TEST_F(VideoCaptureDeviceTest, FakeCaptureVariableResolution) { + VideoCaptureDevice::Names names; + + video_capture_device_factory_->GetDeviceNames(&names); + 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 = true; + + ASSERT_GT(static_cast<int>(names.size()), 0); + + scoped_ptr<VideoCaptureDevice> device( + video_capture_device_factory_->Create(names.front())); + ASSERT_TRUE(device); + + // Configure the FakeVideoCaptureDevice to use all its formats as roster. + VideoCaptureFormats formats; + video_capture_device_factory_->GetDeviceSupportedFormats(names.front(), + &formats); + static_cast<FakeVideoCaptureDevice*>(device.get())-> + PopulateVariableFormatsRoster(formats); + + EXPECT_CALL(*client_, OnErr()) + .Times(0); + int action_count = 200; + + device->AllocateAndStart(capture_params, client_.PassAs<Client>()); + + // We set TimeWait to 200 action timeouts and this should be enough for at + // least action_count/kFakeCaptureCapabilityChangePeriod calls. + for (int i = 0; i < action_count; ++i) { + WaitForCapturedFrame(); + } + device->StopAndDeAllocate(); +} + +TEST_F(VideoCaptureDeviceTest, FakeGetDeviceSupportedFormats) { + VideoCaptureDevice::Names names; + video_capture_device_factory_->GetDeviceNames(&names); + + VideoCaptureFormats supported_formats; + VideoCaptureDevice::Names::iterator names_iterator; + + for (names_iterator = names.begin(); names_iterator != names.end(); + ++names_iterator) { + video_capture_device_factory_->GetDeviceSupportedFormats( + *names_iterator, &supported_formats); + EXPECT_EQ(supported_formats.size(), 3u); + EXPECT_EQ(supported_formats[0].frame_size.width(), 320); + EXPECT_EQ(supported_formats[0].frame_size.height(), 240); + EXPECT_EQ(supported_formats[0].pixel_format, media::PIXEL_FORMAT_I420); + EXPECT_GE(supported_formats[0].frame_rate, 20); + EXPECT_EQ(supported_formats[1].frame_size.width(), 640); + EXPECT_EQ(supported_formats[1].frame_size.height(), 480); + EXPECT_EQ(supported_formats[1].pixel_format, media::PIXEL_FORMAT_I420); + EXPECT_GE(supported_formats[1].frame_rate, 20); + EXPECT_EQ(supported_formats[2].frame_size.width(), 1280); + EXPECT_EQ(supported_formats[2].frame_size.height(), 720); + EXPECT_EQ(supported_formats[2].pixel_format, media::PIXEL_FORMAT_I420); + EXPECT_GE(supported_formats[2].frame_rate, 20); + } +} + }; // namespace media |