summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authormcasas@chromium.org <mcasas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-21 01:49:20 +0000
committermcasas@chromium.org <mcasas@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-21 01:49:20 +0000
commitcf6c86f8d7288f0a46a9310f85101cb050d0a46d (patch)
tree5fa9e8556b181857a9b44af3e3d3b28dd44e2b19 /media
parent698d02886293c3d303e8a7b9644eb4425015f62d (diff)
downloadchromium_src-cf6c86f8d7288f0a46a9310f85101cb050d0a46d.zip
chromium_src-cf6c86f8d7288f0a46a9310f85101cb050d0a46d.tar.gz
chromium_src-cf6c86f8d7288f0a46a9310f85101cb050d0a46d.tar.bz2
VideoCaptureDeviceWin: Extract class-static method into a Factory (both MF/DS)
This CL extends the separation Factory/device initiated in the other CLs part of the bug. Aside from code cleanup, it allows for better testing (via dependency injection) of the factory parts (this is specially important for blacklisted devices, of which there are none in Win ATM). It can also be used to modify the GetDeviceNames() method to an asynchronous API. Both VideoCaptureDeviceWin and VideoCaptureDeviceMFwin (using DirectShow and MediaFoundation APIs resp.), have a number of static methods Create(), GetDeviceNames() and GetDeviceSupportedFormats(). Plus, there are overarching versions of those at the VideoCaptureDevice level, that do library initialisation and appropriate forwarding to one or the other implementation. This CL extracts all of those class-static methods and moves them to a single VideoCaptureDeviceFactoryWin. ScopedMediaType, previously file-level data type moves to the public def of VideoCaptureDeviceWin since is used in the Factory. Every file-static function and variable that could, has been moved to the Factory file. Previous file-level static functions that are used in the Factory and the VCD have been changed to VCD static methods and used in both ends. TBR= dalecurtis@chromium.org (media/media.gyp) BUG=323913 Review URL: https://codereview.chromium.org/276383002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271800 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/media.gyp2
-rw-r--r--media/video/capture/video_capture_device_factory.cc5
-rw-r--r--media/video/capture/video_capture_device_unittest.cc4
-rw-r--r--media/video/capture/win/video_capture_device_factory_win.cc437
-rw-r--r--media/video/capture/win/video_capture_device_factory_win.h40
-rw-r--r--media/video/capture/win/video_capture_device_mf_win.cc213
-rw-r--r--media/video/capture/win/video_capture_device_mf_win.h17
-rw-r--r--media/video/capture/win/video_capture_device_win.cc345
-rw-r--r--media/video/capture/win/video_capture_device_win.h34
9 files changed, 605 insertions, 492 deletions
diff --git a/media/media.gyp b/media/media.gyp
index 6513132..bfe7627 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -505,6 +505,8 @@
'video/capture/win/sink_filter_win.h',
'video/capture/win/sink_input_pin_win.cc',
'video/capture/win/sink_input_pin_win.h',
+ 'video/capture/win/video_capture_device_factory_win.cc',
+ 'video/capture/win/video_capture_device_factory_win.h',
'video/capture/win/video_capture_device_mf_win.cc',
'video/capture/win/video_capture_device_mf_win.h',
'video/capture/win/video_capture_device_win.cc',
diff --git a/media/video/capture/video_capture_device_factory.cc b/media/video/capture/video_capture_device_factory.cc
index 64cc3f8..7c39152 100644
--- a/media/video/capture/video_capture_device_factory.cc
+++ b/media/video/capture/video_capture_device_factory.cc
@@ -15,6 +15,8 @@
#include "media/video/capture/linux/video_capture_device_factory_linux.h"
#elif defined(OS_ANDROID)
#include "media/video/capture/android/video_capture_device_factory_android.h"
+#elif defined(OS_WIN)
+#include "media/video/capture/win/video_capture_device_factory_win.h"
#endif
namespace media {
@@ -46,6 +48,9 @@ scoped_ptr<VideoCaptureDeviceFactory>
#elif defined(OS_ANDROID)
return scoped_ptr<VideoCaptureDeviceFactory>(new
VideoCaptureDeviceFactoryAndroid());
+#elif defined(OS_WIN)
+ return scoped_ptr<VideoCaptureDeviceFactory>(new
+ VideoCaptureDeviceFactoryWin());
#else
return scoped_ptr<VideoCaptureDeviceFactory>(new
VideoCaptureDeviceFactory());
diff --git a/media/video/capture/video_capture_device_unittest.cc b/media/video/capture/video_capture_device_unittest.cc
index 394780d..50ef2d9 100644
--- a/media/video/capture/video_capture_device_unittest.cc
+++ b/media/video/capture/video_capture_device_unittest.cc
@@ -16,7 +16,7 @@
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
-#include "media/video/capture/win/video_capture_device_mf_win.h"
+#include "media/video/capture/win/video_capture_device_factory_win.h"
#endif
#if defined(OS_ANDROID)
@@ -165,7 +165,7 @@ class VideoCaptureDeviceTest : public testing::Test {
TEST_F(VideoCaptureDeviceTest, OpenInvalidDevice) {
#if defined(OS_WIN)
VideoCaptureDevice::Name::CaptureApiType api_type =
- VideoCaptureDeviceMFWin::PlatformSupported()
+ VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation()
? VideoCaptureDevice::Name::MEDIA_FOUNDATION
: VideoCaptureDevice::Name::DIRECT_SHOW;
VideoCaptureDevice::Name device_name("jibberish", "jibberish", api_type);
diff --git a/media/video/capture/win/video_capture_device_factory_win.cc b/media/video/capture/win/video_capture_device_factory_win.cc
new file mode 100644
index 0000000..0ce8a83
--- /dev/null
+++ b/media/video/capture/win/video_capture_device_factory_win.cc
@@ -0,0 +1,437 @@
+// 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/win/video_capture_device_factory_win.h"
+
+#include <mfapi.h>
+#include <mferror.h>
+
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/win/metro.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_variant.h"
+#include "base/win/windows_version.h"
+#include "media/base/media_switches.h"
+#include "media/video/capture/win/video_capture_device_mf_win.h"
+#include "media/video/capture/win/video_capture_device_win.h"
+
+using base::win::ScopedCoMem;
+using base::win::ScopedComPtr;
+using base::win::ScopedVariant;
+
+namespace media {
+
+// Lazy Instance to initialize the MediaFoundation Library.
+class MFInitializerSingleton {
+ public:
+ MFInitializerSingleton() { MFStartup(MF_VERSION, MFSTARTUP_LITE); }
+ ~MFInitializerSingleton() { MFShutdown(); }
+};
+
+static base::LazyInstance<MFInitializerSingleton> g_mf_initialize =
+ LAZY_INSTANCE_INITIALIZER;
+
+static void EnsureMediaFoundationInit() {
+ g_mf_initialize.Get();
+}
+
+static bool LoadMediaFoundationDlls() {
+ static const wchar_t* const kMfDLLs[] = {
+ L"%WINDIR%\\system32\\mf.dll",
+ L"%WINDIR%\\system32\\mfplat.dll",
+ L"%WINDIR%\\system32\\mfreadwrite.dll",
+ };
+
+ for (int i = 0; i < arraysize(kMfDLLs); ++i) {
+ wchar_t path[MAX_PATH] = {0};
+ ExpandEnvironmentStringsW(kMfDLLs[i], path, arraysize(path));
+ if (!LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH))
+ return false;
+ }
+ return true;
+}
+
+static bool PrepareVideoCaptureAttributesMediaFoundation(
+ IMFAttributes** attributes,
+ int count) {
+ EnsureMediaFoundationInit();
+
+ if (FAILED(MFCreateAttributes(attributes, count)))
+ return false;
+
+ return SUCCEEDED((*attributes)->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
+ MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID));
+}
+
+static bool CreateVideoCaptureDeviceMediaFoundation(const char* sym_link,
+ IMFMediaSource** source) {
+ ScopedComPtr<IMFAttributes> attributes;
+ if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 2))
+ return false;
+
+ attributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
+ base::SysUTF8ToWide(sym_link).c_str());
+
+ return SUCCEEDED(MFCreateDeviceSource(attributes, source));
+}
+
+static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices,
+ UINT32* count) {
+ ScopedComPtr<IMFAttributes> attributes;
+ if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1))
+ return false;
+
+ return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count));
+}
+
+static void GetDeviceNamesDirectShow(VideoCaptureDevice::Names* device_names) {
+ DCHECK(device_names);
+ DVLOG(1) << " GetDeviceNamesDirectShow";
+
+ ScopedComPtr<ICreateDevEnum> dev_enum;
+ HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
+ CLSCTX_INPROC);
+ if (FAILED(hr))
+ return;
+
+ ScopedComPtr<IEnumMoniker> enum_moniker;
+ hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
+ enum_moniker.Receive(), 0);
+ // CreateClassEnumerator returns S_FALSE on some Windows OS
+ // when no camera exist. Therefore the FAILED macro can't be used.
+ if (hr != S_OK)
+ return;
+
+ device_names->clear();
+
+ // Name of a fake DirectShow filter that exist on computers with
+ // GTalk installed.
+ static const char kGoogleCameraAdapter[] = "google camera adapter";
+
+ // Enumerate all video capture devices.
+ ScopedComPtr<IMoniker> moniker;
+ int index = 0;
+ while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) {
+ ScopedComPtr<IPropertyBag> prop_bag;
+ hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid());
+ if (FAILED(hr)) {
+ moniker.Release();
+ continue;
+ }
+
+ // Find the description or friendly name.
+ ScopedVariant name;
+ hr = prop_bag->Read(L"Description", name.Receive(), 0);
+ if (FAILED(hr))
+ hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0);
+
+ if (SUCCEEDED(hr) && name.type() == VT_BSTR) {
+ // Ignore all VFW drivers and the special Google Camera Adapter.
+ // Google Camera Adapter is not a real DirectShow camera device.
+ // VFW are very old Video for Windows drivers that can not be used.
+ const wchar_t* str_ptr = V_BSTR(&name);
+ const int name_length = arraysize(kGoogleCameraAdapter) - 1;
+
+ if ((wcsstr(str_ptr, L"(VFW)") == NULL) &&
+ lstrlenW(str_ptr) < name_length ||
+ (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length,
+ kGoogleCameraAdapter)))) {
+ std::string id;
+ std::string device_name(base::SysWideToUTF8(str_ptr));
+ name.Reset();
+ hr = prop_bag->Read(L"DevicePath", name.Receive(), 0);
+ if (FAILED(hr) || name.type() != VT_BSTR) {
+ id = device_name;
+ } else {
+ DCHECK_EQ(name.type(), VT_BSTR);
+ id = base::SysWideToUTF8(V_BSTR(&name));
+ }
+
+ device_names->push_back(VideoCaptureDevice::Name(device_name, id,
+ VideoCaptureDevice::Name::DIRECT_SHOW));
+ }
+ }
+ moniker.Release();
+ }
+}
+
+static void GetDeviceNamesMediaFoundation(
+ VideoCaptureDevice::Names* device_names) {
+ DVLOG(1) << " GetDeviceNamesMediaFoundation";
+ ScopedCoMem<IMFActivate*> devices;
+ UINT32 count;
+ if (!EnumerateVideoDevicesMediaFoundation(&devices, &count))
+ return;
+
+ HRESULT hr;
+ for (UINT32 i = 0; i < count; ++i) {
+ UINT32 name_size, id_size;
+ ScopedCoMem<wchar_t> name, id;
+ if (SUCCEEDED(hr = devices[i]->GetAllocatedString(
+ MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_size)) &&
+ SUCCEEDED(hr = devices[i]->GetAllocatedString(
+ MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &id,
+ &id_size))) {
+ std::wstring name_w(name, name_size), id_w(id, id_size);
+ VideoCaptureDevice::Name device(base::SysWideToUTF8(name_w),
+ base::SysWideToUTF8(id_w),
+ VideoCaptureDevice::Name::MEDIA_FOUNDATION);
+ device_names->push_back(device);
+ } else {
+ DLOG(WARNING) << "GetAllocatedString failed: " << std::hex << hr;
+ }
+ devices[i]->Release();
+ }
+}
+
+static void GetDeviceSupportedFormatsDirectShow(
+ const VideoCaptureDevice::Name& device,
+ VideoCaptureFormats* formats) {
+ DVLOG(1) << "GetDeviceSupportedFormatsDirectShow for " << device.name();
+ ScopedComPtr<ICreateDevEnum> dev_enum;
+ HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
+ CLSCTX_INPROC);
+ if (FAILED(hr))
+ return;
+
+ ScopedComPtr<IEnumMoniker> enum_moniker;
+ hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
+ enum_moniker.Receive(), 0);
+ // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera
+ // exists. Therefore the FAILED macro can't be used.
+ if (hr != S_OK)
+ return;
+
+ // Walk the capture devices. No need to check for "google camera adapter",
+ // since this is already skipped in the enumeration of GetDeviceNames().
+ ScopedComPtr<IMoniker> moniker;
+ int index = 0;
+ ScopedVariant device_id;
+ while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) {
+ ScopedComPtr<IPropertyBag> prop_bag;
+ hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid());
+ if (FAILED(hr)) {
+ moniker.Release();
+ continue;
+ }
+
+ device_id.Reset();
+ hr = prop_bag->Read(L"DevicePath", device_id.Receive(), 0);
+ if (FAILED(hr)) {
+ DVLOG(1) << "Couldn't read a device's DevicePath.";
+ return;
+ }
+ if (device.id() == base::SysWideToUTF8(V_BSTR(&device_id)))
+ break;
+ moniker.Release();
+ }
+
+ if (moniker.get()) {
+ base::win::ScopedComPtr<IBaseFilter> capture_filter;
+ hr = VideoCaptureDeviceWin::GetDeviceFilter(device,
+ capture_filter.Receive());
+ if (!capture_filter) {
+ DVLOG(2) << "Failed to create capture filter.";
+ return;
+ }
+
+ base::win::ScopedComPtr<IPin> output_capture_pin(
+ VideoCaptureDeviceWin::GetPin(capture_filter,
+ PINDIR_OUTPUT,
+ PIN_CATEGORY_CAPTURE));
+ if (!output_capture_pin) {
+ DVLOG(2) << "Failed to get capture output pin";
+ return;
+ }
+
+ ScopedComPtr<IAMStreamConfig> stream_config;
+ hr = output_capture_pin.QueryInterface(stream_config.Receive());
+ if (FAILED(hr)) {
+ DVLOG(2) << "Failed to get IAMStreamConfig interface from "
+ "capture device";
+ return;
+ }
+
+ int count = 0, size = 0;
+ hr = stream_config->GetNumberOfCapabilities(&count, &size);
+ if (FAILED(hr)) {
+ DVLOG(2) << "Failed to GetNumberOfCapabilities";
+ return;
+ }
+
+ scoped_ptr<BYTE[]> caps(new BYTE[size]);
+ for (int i = 0; i < count; ++i) {
+ VideoCaptureDeviceWin::ScopedMediaType media_type;
+ hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get());
+ // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED()
+ // macros here since they'll trigger incorrectly.
+ if (hr != S_OK) {
+ DVLOG(2) << "Failed to GetStreamCaps";
+ return;
+ }
+
+ if (media_type->majortype == MEDIATYPE_Video &&
+ media_type->formattype == FORMAT_VideoInfo) {
+ VideoCaptureFormat format;
+ format.pixel_format =
+ VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
+ media_type->subtype);
+ if (format.pixel_format == PIXEL_FORMAT_UNKNOWN)
+ continue;
+ VIDEOINFOHEADER* h =
+ reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat);
+ format.frame_size.SetSize(h->bmiHeader.biWidth,
+ h->bmiHeader.biHeight);
+ // Trust the frame rate from the VIDEOINFOHEADER.
+ format.frame_rate = (h->AvgTimePerFrame > 0) ?
+ static_cast<int>(kSecondsToReferenceTime / h->AvgTimePerFrame) :
+ 0;
+ formats->push_back(format);
+ DVLOG(1) << device.name() << " resolution: "
+ << format.frame_size.ToString() << ", fps: " << format.frame_rate
+ << ", pixel format: " << format.pixel_format;
+ }
+ }
+ }
+}
+
+static void GetDeviceSupportedFormatsMediaFoundation(
+ const VideoCaptureDevice::Name& device,
+ VideoCaptureFormats* formats) {
+ DVLOG(1) << "GetDeviceSupportedFormatsMediaFoundation for " << device.name();
+ ScopedComPtr<IMFMediaSource> source;
+ if (!CreateVideoCaptureDeviceMediaFoundation(device.id().c_str(),
+ source.Receive())) {
+ return;
+ }
+
+ HRESULT hr;
+ base::win::ScopedComPtr<IMFSourceReader> reader;
+ if (FAILED(hr = MFCreateSourceReaderFromMediaSource(source, NULL,
+ reader.Receive()))) {
+ DLOG(ERROR) << "MFCreateSourceReaderFromMediaSource: " << std::hex << hr;
+ return;
+ }
+
+ DWORD stream_index = 0;
+ ScopedComPtr<IMFMediaType> type;
+ while (SUCCEEDED(hr = reader->GetNativeMediaType(
+ MF_SOURCE_READER_FIRST_VIDEO_STREAM, stream_index, type.Receive()))) {
+ UINT32 width, height;
+ hr = MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width, &height);
+ if (FAILED(hr)) {
+ DLOG(ERROR) << "MFGetAttributeSize: " << std::hex << hr;
+ return;
+ }
+ VideoCaptureFormat capture_format;
+ capture_format.frame_size.SetSize(width, height);
+
+ UINT32 numerator, denominator;
+ hr = MFGetAttributeRatio(type, MF_MT_FRAME_RATE, &numerator, &denominator);
+ if (FAILED(hr)) {
+ DLOG(ERROR) << "MFGetAttributeSize: " << std::hex << hr;
+ return;
+ }
+ capture_format.frame_rate = denominator ? numerator / denominator : 0;
+
+ GUID type_guid;
+ hr = type->GetGUID(MF_MT_SUBTYPE, &type_guid);
+ if (FAILED(hr)) {
+ DLOG(ERROR) << "GetGUID: " << std::hex << hr;
+ return;
+ }
+ VideoCaptureDeviceMFWin::FormatFromGuid(type_guid,
+ &capture_format.pixel_format);
+ type.Release();
+ formats->push_back(capture_format);
+ ++stream_index;
+
+ DVLOG(1) << device.name() << " resolution: "
+ << capture_format.frame_size.ToString() << ", fps: "
+ << capture_format.frame_rate << ", pixel format: "
+ << capture_format.pixel_format;
+ }
+}
+
+// Returns true iff the current platform supports the Media Foundation API
+// and that the DLLs are available. On Vista this API is an optional download
+// but the API is advertised as a part of Windows 7 and onwards. However,
+// we've seen that the required DLLs are not available in some Win7
+// distributions such as Windows 7 N and Windows 7 KN.
+// static
+bool VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation() {
+ // Even though the DLLs might be available on Vista, we get crashes
+ // when running our tests on the build bots.
+ if (base::win::GetVersion() < base::win::VERSION_WIN7)
+ return false;
+
+ static bool g_dlls_available = LoadMediaFoundationDlls();
+ return g_dlls_available;
+}
+
+VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() {
+ // Use Media Foundation for Metro processes (after and including Win8) and
+ // DirectShow for any other versions, unless forced via flag. Media Foundation
+ // can also be forced if appropriate flag is set and we are in Windows 7 or
+ // 8 in non-Metro mode.
+ const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ use_media_foundation_ = (base::win::IsMetroProcess() &&
+ !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) ||
+ (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
+ cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture));
+}
+
+
+scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const VideoCaptureDevice::Name& device_name) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ scoped_ptr<VideoCaptureDevice> device;
+ if (device_name.capture_api_type() ==
+ VideoCaptureDevice::Name::MEDIA_FOUNDATION) {
+ DCHECK(PlatformSupportsMediaFoundation());
+ device.reset(new VideoCaptureDeviceMFWin(device_name));
+ DVLOG(1) << " MediaFoundation Device: " << device_name.name();
+ ScopedComPtr<IMFMediaSource> source;
+ if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(),
+ source.Receive())) {
+ return scoped_ptr<VideoCaptureDevice>();
+ }
+ if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source))
+ device.reset();
+ } else if (device_name.capture_api_type() ==
+ VideoCaptureDevice::Name::DIRECT_SHOW) {
+ device.reset(new VideoCaptureDeviceWin(device_name));
+ DVLOG(1) << " DirectShow Device: " << device_name.name();
+ if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init())
+ device.reset();
+ } else {
+ NOTREACHED() << " Couldn't recognize VideoCaptureDevice type";
+ }
+ return device.Pass();
+}
+
+void VideoCaptureDeviceFactoryWin::GetDeviceNames(
+ VideoCaptureDevice::Names* device_names) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (use_media_foundation_)
+ GetDeviceNamesMediaFoundation(device_names);
+ else
+ GetDeviceNamesDirectShow(device_names);
+}
+
+void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats(
+ const VideoCaptureDevice::Name& device,
+ VideoCaptureFormats* formats) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ if (use_media_foundation_)
+ GetDeviceSupportedFormatsMediaFoundation(device, formats);
+ else
+ GetDeviceSupportedFormatsDirectShow(device, formats);
+}
+
+} // namespace media
diff --git a/media/video/capture/win/video_capture_device_factory_win.h b/media/video/capture/win/video_capture_device_factory_win.h
new file mode 100644
index 0000000..187850f
--- /dev/null
+++ b/media/video/capture/win/video_capture_device_factory_win.h
@@ -0,0 +1,40 @@
+// 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 Windows platforms.
+
+#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_
+
+#include "media/video/capture/video_capture_device_factory.h"
+
+namespace media {
+
+// Extension of VideoCaptureDeviceFactory to create and manipulate Windows
+// devices, via either DirectShow or MediaFoundation APIs.
+class MEDIA_EXPORT VideoCaptureDeviceFactoryWin :
+ public VideoCaptureDeviceFactory {
+ public:
+ static bool PlatformSupportsMediaFoundation();
+
+ VideoCaptureDeviceFactoryWin();
+ virtual ~VideoCaptureDeviceFactoryWin() {}
+
+ virtual scoped_ptr<VideoCaptureDevice> Create(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ 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:
+ bool use_media_foundation_;
+
+ DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryWin);
+};
+
+} // namespace media
+
+#endif // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_
diff --git a/media/video/capture/win/video_capture_device_mf_win.cc b/media/video/capture/win/video_capture_device_mf_win.cc
index cb10a86..47184d9 100644
--- a/media/video/capture/win/video_capture_device_mf_win.cc
+++ b/media/video/capture/win/video_capture_device_mf_win.cc
@@ -7,7 +7,6 @@
#include <mfapi.h>
#include <mferror.h>
-#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
#include "base/strings/sys_string_conversions.h"
@@ -20,7 +19,6 @@ using base::win::ScopedCoMem;
using base::win::ScopedComPtr;
namespace media {
-namespace {
// In Windows device identifiers, the USB VID and PID are preceded by the string
// "vid_" or "pid_". The identifiers are each 4 bytes long.
@@ -28,74 +26,7 @@ const char kVidPrefix[] = "vid_"; // Also contains '\0'.
const char kPidPrefix[] = "pid_"; // Also contains '\0'.
const size_t kVidPidSize = 4;
-class MFInitializerSingleton {
- public:
- MFInitializerSingleton() { MFStartup(MF_VERSION, MFSTARTUP_LITE); }
- ~MFInitializerSingleton() { MFShutdown(); }
-};
-
-static base::LazyInstance<MFInitializerSingleton> g_mf_initialize =
- LAZY_INSTANCE_INITIALIZER;
-
-void EnsureMFInit() {
- g_mf_initialize.Get();
-}
-
-bool PrepareVideoCaptureAttributes(IMFAttributes** attributes, int count) {
- EnsureMFInit();
-
- if (FAILED(MFCreateAttributes(attributes, count)))
- return false;
-
- return SUCCEEDED((*attributes)->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
- MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID));
-}
-
-bool EnumerateVideoDevices(IMFActivate*** devices,
- UINT32* count) {
- ScopedComPtr<IMFAttributes> attributes;
- if (!PrepareVideoCaptureAttributes(attributes.Receive(), 1))
- return false;
-
- return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count));
-}
-
-bool CreateVideoCaptureDevice(const char* sym_link, IMFMediaSource** source) {
- ScopedComPtr<IMFAttributes> attributes;
- if (!PrepareVideoCaptureAttributes(attributes.Receive(), 2))
- return false;
-
- attributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
- base::SysUTF8ToWide(sym_link).c_str());
-
- return SUCCEEDED(MFCreateDeviceSource(attributes, source));
-}
-
-bool FormatFromGuid(const GUID& guid, VideoPixelFormat* format) {
- struct {
- const GUID& guid;
- const VideoPixelFormat format;
- } static const kFormatMap[] = {
- { MFVideoFormat_I420, PIXEL_FORMAT_I420 },
- { MFVideoFormat_YUY2, PIXEL_FORMAT_YUY2 },
- { MFVideoFormat_UYVY, PIXEL_FORMAT_UYVY },
- { MFVideoFormat_RGB24, PIXEL_FORMAT_RGB24 },
- { MFVideoFormat_ARGB32, PIXEL_FORMAT_ARGB },
- { MFVideoFormat_MJPG, PIXEL_FORMAT_MJPEG },
- { MFVideoFormat_YV12, PIXEL_FORMAT_YV12 },
- };
-
- for (int i = 0; i < arraysize(kFormatMap); ++i) {
- if (kFormatMap[i].guid == guid) {
- *format = kFormatMap[i].format;
- return true;
- }
- }
-
- return false;
-}
-
-bool GetFrameSize(IMFMediaType* type, gfx::Size* frame_size) {
+static bool GetFrameSize(IMFMediaType* type, gfx::Size* frame_size) {
UINT32 width32, height32;
if (FAILED(MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width32, &height32)))
return false;
@@ -103,9 +34,9 @@ bool GetFrameSize(IMFMediaType* type, gfx::Size* frame_size) {
return true;
}
-bool GetFrameRate(IMFMediaType* type,
- int* frame_rate_numerator,
- int* frame_rate_denominator) {
+static bool GetFrameRate(IMFMediaType* type,
+ int* frame_rate_numerator,
+ int* frame_rate_denominator) {
UINT32 numerator, denominator;
if (FAILED(MFGetAttributeRatio(type, MF_MT_FRAME_RATE, &numerator,
&denominator))||
@@ -117,15 +48,16 @@ bool GetFrameRate(IMFMediaType* type,
return true;
}
-bool FillCapabilitiesFromType(IMFMediaType* type,
- VideoCaptureCapabilityWin* capability) {
+static bool FillCapabilitiesFromType(IMFMediaType* type,
+ VideoCaptureCapabilityWin* capability) {
GUID type_guid;
if (FAILED(type->GetGUID(MF_MT_SUBTYPE, &type_guid)) ||
!GetFrameSize(type, &capability->supported_format.frame_size) ||
!GetFrameRate(type,
&capability->frame_rate_numerator,
&capability->frame_rate_denominator) ||
- !FormatFromGuid(type_guid, &capability->supported_format.pixel_format)) {
+ !VideoCaptureDeviceMFWin::FormatFromGuid(type_guid,
+ &capability->supported_format.pixel_format)) {
return false;
}
// Keep the integer version of the frame_rate for (potential) returns.
@@ -154,24 +86,6 @@ HRESULT FillCapabilities(IMFSourceReader* source,
return (hr == MF_E_NO_MORE_TYPES) ? S_OK : hr;
}
-bool LoadMediaFoundationDlls() {
- static const wchar_t* const kMfDLLs[] = {
- L"%WINDIR%\\system32\\mf.dll",
- L"%WINDIR%\\system32\\mfplat.dll",
- L"%WINDIR%\\system32\\mfreadwrite.dll",
- };
-
- for (int i = 0; i < arraysize(kMfDLLs); ++i) {
- wchar_t path[MAX_PATH] = {0};
- ExpandEnvironmentStringsW(kMfDLLs[i], path, arraysize(path));
- if (!LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH))
- return false;
- }
-
- return true;
-}
-
-} // namespace
class MFReaderCallback FINAL
: public base::RefCountedThreadSafe<MFReaderCallback>,
@@ -250,95 +164,29 @@ class MFReaderCallback FINAL
};
// static
-bool VideoCaptureDeviceMFWin::PlatformSupported() {
- // Even though the DLLs might be available on Vista, we get crashes
- // when running our tests on the build bots.
- if (base::win::GetVersion() < base::win::VERSION_WIN7)
- return false;
-
- static bool g_dlls_available = LoadMediaFoundationDlls();
- return g_dlls_available;
-}
-
-// static
-void VideoCaptureDeviceMFWin::GetDeviceNames(Names* device_names) {
- ScopedCoMem<IMFActivate*> devices;
- UINT32 count;
- if (!EnumerateVideoDevices(&devices, &count))
- return;
+bool VideoCaptureDeviceMFWin::FormatFromGuid(const GUID& guid,
+ VideoPixelFormat* format) {
+ struct {
+ const GUID& guid;
+ const VideoPixelFormat format;
+ } static const kFormatMap[] = {
+ { MFVideoFormat_I420, PIXEL_FORMAT_I420 },
+ { MFVideoFormat_YUY2, PIXEL_FORMAT_YUY2 },
+ { MFVideoFormat_UYVY, PIXEL_FORMAT_UYVY },
+ { MFVideoFormat_RGB24, PIXEL_FORMAT_RGB24 },
+ { MFVideoFormat_ARGB32, PIXEL_FORMAT_ARGB },
+ { MFVideoFormat_MJPG, PIXEL_FORMAT_MJPEG },
+ { MFVideoFormat_YV12, PIXEL_FORMAT_YV12 },
+ };
- HRESULT hr;
- for (UINT32 i = 0; i < count; ++i) {
- UINT32 name_size, id_size;
- ScopedCoMem<wchar_t> name, id;
- if (SUCCEEDED(hr = devices[i]->GetAllocatedString(
- MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_size)) &&
- SUCCEEDED(hr = devices[i]->GetAllocatedString(
- MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &id,
- &id_size))) {
- std::wstring name_w(name, name_size), id_w(id, id_size);
- Name device(base::SysWideToUTF8(name_w), base::SysWideToUTF8(id_w),
- Name::MEDIA_FOUNDATION);
- device_names->push_back(device);
- } else {
- DLOG(WARNING) << "GetAllocatedString failed: " << std::hex << hr;
+ for (int i = 0; i < arraysize(kFormatMap); ++i) {
+ if (kFormatMap[i].guid == guid) {
+ *format = kFormatMap[i].format;
+ return true;
}
- devices[i]->Release();
}
-}
-
-// static
-void VideoCaptureDeviceMFWin::GetDeviceSupportedFormats(const Name& device,
- VideoCaptureFormats* formats) {
- ScopedComPtr<IMFMediaSource> source;
- if (!CreateVideoCaptureDevice(device.id().c_str(), source.Receive()))
- return;
-
- HRESULT hr;
- base::win::ScopedComPtr<IMFSourceReader> reader;
- if (FAILED(hr = MFCreateSourceReaderFromMediaSource(source, NULL,
- reader.Receive()))) {
- DLOG(ERROR) << "MFCreateSourceReaderFromMediaSource: " << std::hex << hr;
- return;
- }
-
- DWORD stream_index = 0;
- ScopedComPtr<IMFMediaType> type;
- while (SUCCEEDED(hr = reader->GetNativeMediaType(
- MF_SOURCE_READER_FIRST_VIDEO_STREAM, stream_index, type.Receive()))) {
- UINT32 width, height;
- hr = MFGetAttributeSize(type, MF_MT_FRAME_SIZE, &width, &height);
- if (FAILED(hr)) {
- DLOG(ERROR) << "MFGetAttributeSize: " << std::hex << hr;
- return;
- }
- VideoCaptureFormat capture_format;
- capture_format.frame_size.SetSize(width, height);
-
- UINT32 numerator, denominator;
- hr = MFGetAttributeRatio(type, MF_MT_FRAME_RATE, &numerator, &denominator);
- if (FAILED(hr)) {
- DLOG(ERROR) << "MFGetAttributeSize: " << std::hex << hr;
- return;
- }
- capture_format.frame_rate = denominator ? numerator / denominator : 0;
-
- GUID type_guid;
- hr = type->GetGUID(MF_MT_SUBTYPE, &type_guid);
- if (FAILED(hr)) {
- DLOG(ERROR) << "GetGUID: " << std::hex << hr;
- return;
- }
- FormatFromGuid(type_guid, &capture_format.pixel_format);
- type.Release();
- formats->push_back(capture_format);
- ++stream_index;
- DVLOG(1) << device.name() << " resolution: "
- << capture_format.frame_size.ToString() << ", fps: "
- << capture_format.frame_rate << ", pixel format: "
- << capture_format.pixel_format;
- }
+ return false;
}
const std::string VideoCaptureDevice::Name::GetModel() const {
@@ -370,14 +218,11 @@ VideoCaptureDeviceMFWin::~VideoCaptureDeviceMFWin() {
DCHECK(CalledOnValidThread());
}
-bool VideoCaptureDeviceMFWin::Init() {
+bool VideoCaptureDeviceMFWin::Init(
+ const base::win::ScopedComPtr<IMFMediaSource>& source) {
DCHECK(CalledOnValidThread());
DCHECK(!reader_);
- ScopedComPtr<IMFMediaSource> source;
- if (!CreateVideoCaptureDevice(name_.id().c_str(), source.Receive()))
- return false;
-
ScopedComPtr<IMFAttributes> attributes;
MFCreateAttributes(attributes.Receive(), 1);
DCHECK(attributes);
diff --git a/media/video/capture/win/video_capture_device_mf_win.h b/media/video/capture/win/video_capture_device_mf_win.h
index a1bda9f..476a455 100644
--- a/media/video/capture/win/video_capture_device_mf_win.h
+++ b/media/video/capture/win/video_capture_device_mf_win.h
@@ -30,12 +30,13 @@ class MEDIA_EXPORT VideoCaptureDeviceMFWin
: public base::NonThreadSafe,
public VideoCaptureDevice {
public:
+ static bool FormatFromGuid(const GUID& guid, VideoPixelFormat* format);
+
explicit VideoCaptureDeviceMFWin(const Name& device_name);
virtual ~VideoCaptureDeviceMFWin();
// Opens the device driver for this device.
- // This function is used by the static VideoCaptureDevice::Create function.
- bool Init();
+ bool Init(const base::win::ScopedComPtr<IMFMediaSource>& source);
// VideoCaptureDevice implementation.
virtual void AllocateAndStart(const VideoCaptureParams& params,
@@ -43,18 +44,6 @@ class MEDIA_EXPORT VideoCaptureDeviceMFWin
OVERRIDE;
virtual void StopAndDeAllocate() OVERRIDE;
- // Returns true iff the current platform supports the Media Foundation API
- // and that the DLLs are available. On Vista this API is an optional download
- // but the API is advertised as a part of Windows 7 and onwards. However,
- // we've seen that the required DLLs are not available in some Win7
- // distributions such as Windows 7 N and Windows 7 KN.
- static bool PlatformSupported();
-
- static void GetDeviceNames(Names* device_names);
-
- static void GetDeviceSupportedFormats(const Name& device,
- VideoCaptureFormats* formats);
-
// Captured new video data.
void OnIncomingCapturedData(const uint8* data,
int length,
diff --git a/media/video/capture/win/video_capture_device_win.cc b/media/video/capture/win/video_capture_device_win.cc
index 76c4c60..24d916a 100644
--- a/media/video/capture/win/video_capture_device_win.cc
+++ b/media/video/capture/win/video_capture_device_win.cc
@@ -10,14 +10,9 @@
#include <algorithm>
#include <list>
-#include "base/command_line.h"
-#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
-#include "base/win/metro.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_variant.h"
-#include "base/win/windows_version.h"
-#include "media/base/media_switches.h"
#include "media/video/capture/win/video_capture_device_mf_win.h"
using base::win::ScopedCoMem;
@@ -25,11 +20,12 @@ using base::win::ScopedComPtr;
using base::win::ScopedVariant;
namespace media {
-namespace {
// Finds and creates a DirectShow Video Capture filter matching the device_name.
-HRESULT GetDeviceFilter(const VideoCaptureDevice::Name& device_name,
- IBaseFilter** filter) {
+// static
+HRESULT VideoCaptureDeviceWin::GetDeviceFilter(
+ const VideoCaptureDevice::Name& device_name,
+ IBaseFilter** filter) {
DCHECK(filter);
ScopedComPtr<ICreateDevEnum> dev_enum;
@@ -87,7 +83,8 @@ HRESULT GetDeviceFilter(const VideoCaptureDevice::Name& device_name,
}
// Check if a Pin matches a category.
-bool PinMatchesCategory(IPin* pin, REFGUID category) {
+// static
+bool VideoCaptureDeviceWin::PinMatchesCategory(IPin* pin, REFGUID category) {
DCHECK(pin);
bool found = false;
ScopedComPtr<IKsPropertySet> ks_property;
@@ -105,8 +102,10 @@ bool PinMatchesCategory(IPin* pin, REFGUID category) {
}
// Finds a IPin on a IBaseFilter given the direction an category.
-ScopedComPtr<IPin> GetPin(IBaseFilter* filter, PIN_DIRECTION pin_dir,
- REFGUID category) {
+// static
+ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter,
+ PIN_DIRECTION pin_dir,
+ REFGUID category) {
ScopedComPtr<IPin> pin;
ScopedComPtr<IEnumPins> pin_emum;
HRESULT hr = filter->EnumPins(pin_emum.Receive());
@@ -129,60 +128,9 @@ ScopedComPtr<IPin> GetPin(IBaseFilter* filter, PIN_DIRECTION pin_dir,
return pin;
}
-// Release the format block for a media type.
-// http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx
-void FreeMediaType(AM_MEDIA_TYPE* mt) {
- if (mt->cbFormat != 0) {
- CoTaskMemFree(mt->pbFormat);
- mt->cbFormat = 0;
- mt->pbFormat = NULL;
- }
- if (mt->pUnk != NULL) {
- NOTREACHED();
- // pUnk should not be used.
- mt->pUnk->Release();
- mt->pUnk = NULL;
- }
-}
-
-// Delete a media type structure that was allocated on the heap.
-// http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx
-void DeleteMediaType(AM_MEDIA_TYPE* mt) {
- if (mt != NULL) {
- FreeMediaType(mt);
- CoTaskMemFree(mt);
- }
-}
-
-// A utility class that wraps the AM_MEDIA_TYPE type and guarantees that
-// we free the structure when exiting the scope. DCHECKing is also done to
-// avoid memory leaks.
-class ScopedMediaType {
- public:
- ScopedMediaType() : media_type_(NULL) {}
- ~ScopedMediaType() { Free(); }
-
- AM_MEDIA_TYPE* operator->() { return media_type_; }
- AM_MEDIA_TYPE* get() { return media_type_; }
-
- void Free() {
- if (!media_type_)
- return;
-
- DeleteMediaType(media_type_);
- media_type_= NULL;
- }
-
- AM_MEDIA_TYPE** Receive() {
- DCHECK(!media_type_);
- return &media_type_;
- }
-
- private:
- AM_MEDIA_TYPE* media_type_;
-};
-
-VideoPixelFormat TranslateMediaSubtypeToPixelFormat(const GUID& sub_type) {
+// static
+VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
+ const GUID& sub_type) {
static struct {
const GUID& sub_type;
VideoPixelFormat format;
@@ -207,243 +155,66 @@ VideoPixelFormat TranslateMediaSubtypeToPixelFormat(const GUID& sub_type) {
return PIXEL_FORMAT_UNKNOWN;
}
-} // namespace
+void VideoCaptureDeviceWin::ScopedMediaType::Free() {
+ if (!media_type_)
+ return;
-// static
-void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- // Use Media Foundation for Metro processes (after and including Win8) and
- // DirectShow for any other versions, unless forced via flag. Media Foundation
- // can also be forced if appropriate flag is set and we are in Windows 7 or
- // 8 in non-Metro mode.
- if ((base::win::IsMetroProcess() &&
- !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) ||
- (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
- cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture))) {
- VideoCaptureDeviceMFWin::GetDeviceNames(device_names);
- } else {
- VideoCaptureDeviceWin::GetDeviceNames(device_names);
- }
+ DeleteMediaType(media_type_);
+ media_type_= NULL;
}
-// static
-void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device,
- VideoCaptureFormats* formats) {
- const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
- // Use Media Foundation for Metro processes (after and including Win8) and
- // DirectShow for any other versions, unless forced via flag. Media Foundation
- // can also be forced if appropriate flag is set and we are in Windows 7 or
- // 8 in non-Metro mode.
- if ((base::win::IsMetroProcess() &&
- !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) ||
- (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
- cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture))) {
- VideoCaptureDeviceMFWin::GetDeviceSupportedFormats(device, formats);
- } else {
- VideoCaptureDeviceWin::GetDeviceSupportedFormats(device, formats);
- }
+AM_MEDIA_TYPE** VideoCaptureDeviceWin::ScopedMediaType::Receive() {
+ DCHECK(!media_type_);
+ return &media_type_;
}
-// static
-VideoCaptureDevice* VideoCaptureDevice::Create(
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
- const Name& device_name) {
- VideoCaptureDevice* ret = NULL;
- if (device_name.capture_api_type() == Name::MEDIA_FOUNDATION) {
- DCHECK(VideoCaptureDeviceMFWin::PlatformSupported());
- scoped_ptr<VideoCaptureDeviceMFWin> device(
- new VideoCaptureDeviceMFWin(device_name));
- DVLOG(1) << " MediaFoundation Device: " << device_name.name();
- if (device->Init())
- ret = device.release();
- } else if (device_name.capture_api_type() == Name::DIRECT_SHOW) {
- scoped_ptr<VideoCaptureDeviceWin> device(
- new VideoCaptureDeviceWin(device_name));
- DVLOG(1) << " DirectShow Device: " << device_name.name();
- if (device->Init())
- ret = device.release();
- } else{
- NOTREACHED() << " Couldn't recognize VideoCaptureDevice type";
+// Release the format block for a media type.
+// http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx
+void VideoCaptureDeviceWin::ScopedMediaType::FreeMediaType(AM_MEDIA_TYPE* mt) {
+ if (mt->cbFormat != 0) {
+ CoTaskMemFree(mt->pbFormat);
+ mt->cbFormat = 0;
+ mt->pbFormat = NULL;
}
+ if (mt->pUnk != NULL) {
+ NOTREACHED();
+ // pUnk should not be used.
+ mt->pUnk->Release();
+ mt->pUnk = NULL;
+ }
+}
- return ret;
+// Delete a media type structure that was allocated on the heap.
+// http://msdn.microsoft.com/en-us/library/dd375432(VS.85).aspx
+void VideoCaptureDeviceWin::ScopedMediaType::DeleteMediaType(
+ AM_MEDIA_TYPE* mt) {
+ if (mt != NULL) {
+ FreeMediaType(mt);
+ CoTaskMemFree(mt);
+ }
}
+// 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
-void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) {
- DCHECK(device_names);
-
- ScopedComPtr<ICreateDevEnum> dev_enum;
- HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
- CLSCTX_INPROC);
- if (FAILED(hr))
- return;
-
- ScopedComPtr<IEnumMoniker> enum_moniker;
- hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
- enum_moniker.Receive(), 0);
- // CreateClassEnumerator returns S_FALSE on some Windows OS
- // when no camera exist. Therefore the FAILED macro can't be used.
- if (hr != S_OK)
- return;
-
- device_names->clear();
-
- // Name of a fake DirectShow filter that exist on computers with
- // GTalk installed.
- static const char kGoogleCameraAdapter[] = "google camera adapter";
-
- // Enumerate all video capture devices.
- ScopedComPtr<IMoniker> moniker;
- int index = 0;
- while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) {
- ScopedComPtr<IPropertyBag> prop_bag;
- hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid());
- if (FAILED(hr)) {
- moniker.Release();
- continue;
- }
-
- // Find the description or friendly name.
- ScopedVariant name;
- hr = prop_bag->Read(L"Description", name.Receive(), 0);
- if (FAILED(hr))
- hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0);
-
- if (SUCCEEDED(hr) && name.type() == VT_BSTR) {
- // Ignore all VFW drivers and the special Google Camera Adapter.
- // Google Camera Adapter is not a real DirectShow camera device.
- // VFW are very old Video for Windows drivers that can not be used.
- const wchar_t* str_ptr = V_BSTR(&name);
- const int name_length = arraysize(kGoogleCameraAdapter) - 1;
-
- if ((wcsstr(str_ptr, L"(VFW)") == NULL) &&
- lstrlenW(str_ptr) < name_length ||
- (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length,
- kGoogleCameraAdapter)))) {
- std::string id;
- std::string device_name(base::SysWideToUTF8(str_ptr));
- name.Reset();
- hr = prop_bag->Read(L"DevicePath", name.Receive(), 0);
- if (FAILED(hr) || name.type() != VT_BSTR) {
- id = device_name;
- } else {
- DCHECK_EQ(name.type(), VT_BSTR);
- id = base::SysWideToUTF8(V_BSTR(&name));
- }
-
- device_names->push_back(Name(device_name, id, Name::DIRECT_SHOW));
- }
- }
- moniker.Release();
- }
+void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
+ NOTIMPLEMENTED();
}
// static
-void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device,
+void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device,
VideoCaptureFormats* formats) {
- DVLOG(1) << "GetDeviceSupportedFormats for " << device.name();
- ScopedComPtr<ICreateDevEnum> dev_enum;
- HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
- CLSCTX_INPROC);
- if (FAILED(hr))
- return;
-
- ScopedComPtr<IEnumMoniker> enum_moniker;
- hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
- enum_moniker.Receive(), 0);
- // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera
- // exists. Therefore the FAILED macro can't be used.
- if (hr != S_OK)
- return;
-
- // Walk the capture devices. No need to check for "google camera adapter",
- // since this is already skipped in the enumeration of GetDeviceNames().
- ScopedComPtr<IMoniker> moniker;
- int index = 0;
- ScopedVariant device_id;
- while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) {
- ScopedComPtr<IPropertyBag> prop_bag;
- hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid());
- if (FAILED(hr)) {
- moniker.Release();
- continue;
- }
-
- device_id.Reset();
- hr = prop_bag->Read(L"DevicePath", device_id.Receive(), 0);
- if (FAILED(hr)) {
- DVLOG(1) << "Couldn't read a device's DevicePath.";
- return;
- }
- if (device.id() == base::SysWideToUTF8(V_BSTR(&device_id)))
- break;
- moniker.Release();
- }
-
- if (moniker.get()) {
- base::win::ScopedComPtr<IBaseFilter> capture_filter;
- hr = GetDeviceFilter(device, capture_filter.Receive());
- if (!capture_filter) {
- DVLOG(2) << "Failed to create capture filter.";
- return;
- }
-
- base::win::ScopedComPtr<IPin> output_capture_pin(
- GetPin(capture_filter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE));
- if (!output_capture_pin) {
- DVLOG(2) << "Failed to get capture output pin";
- return;
- }
-
- ScopedComPtr<IAMStreamConfig> stream_config;
- hr = output_capture_pin.QueryInterface(stream_config.Receive());
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to get IAMStreamConfig interface from "
- "capture device";
- return;
- }
-
- int count = 0, size = 0;
- hr = stream_config->GetNumberOfCapabilities(&count, &size);
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to GetNumberOfCapabilities";
- return;
- }
-
- scoped_ptr<BYTE[]> caps(new BYTE[size]);
- for (int i = 0; i < count; ++i) {
- ScopedMediaType media_type;
- hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get());
- // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED()
- // macros here since they'll trigger incorrectly.
- if (hr != S_OK) {
- DVLOG(2) << "Failed to GetStreamCaps";
- return;
- }
+ NOTIMPLEMENTED();
+}
- if (media_type->majortype == MEDIATYPE_Video &&
- media_type->formattype == FORMAT_VideoInfo) {
- VideoCaptureFormat format;
- format.pixel_format =
- TranslateMediaSubtypeToPixelFormat(media_type->subtype);
- if (format.pixel_format == PIXEL_FORMAT_UNKNOWN)
- continue;
- VIDEOINFOHEADER* h =
- reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat);
- format.frame_size.SetSize(h->bmiHeader.biWidth,
- h->bmiHeader.biHeight);
- // Trust the frame rate from the VIDEOINFOHEADER.
- format.frame_rate = (h->AvgTimePerFrame > 0) ?
- static_cast<int>(kSecondsToReferenceTime / h->AvgTimePerFrame) :
- 0;
- formats->push_back(format);
- DVLOG(1) << device.name() << " resolution: "
- << format.frame_size.ToString() << ", fps: " << format.frame_rate
- << ", pixel format: " << format.pixel_format;
- }
- }
- }
+// static
+VideoCaptureDevice* VideoCaptureDevice::Create(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const Name& device_name) {
+ NOTIMPLEMENTED();
+ return NULL;
}
VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name)
diff --git a/media/video/capture/win/video_capture_device_win.h b/media/video/capture/win/video_capture_device_win.h
index ac4b704..5ab9faa 100644
--- a/media/video/capture/win/video_capture_device_win.h
+++ b/media/video/capture/win/video_capture_device_win.h
@@ -33,10 +33,38 @@ class VideoCaptureDeviceWin
public VideoCaptureDevice,
public SinkFilterObserver {
public:
+ // A utility class that wraps the AM_MEDIA_TYPE type and guarantees that
+ // we free the structure when exiting the scope. DCHECKing is also done to
+ // avoid memory leaks.
+ class ScopedMediaType {
+ public:
+ ScopedMediaType() : media_type_(NULL) {}
+ ~ScopedMediaType() { Free(); }
+
+ AM_MEDIA_TYPE* operator->() { return media_type_; }
+ AM_MEDIA_TYPE* get() { return media_type_; }
+ void Free();
+ AM_MEDIA_TYPE** Receive();
+
+ private:
+ void FreeMediaType(AM_MEDIA_TYPE* mt);
+ void DeleteMediaType(AM_MEDIA_TYPE* mt);
+
+ AM_MEDIA_TYPE* media_type_;
+ };
+
+ static HRESULT GetDeviceFilter(const Name& device_name,
+ IBaseFilter** filter);
+ static bool PinMatchesCategory(IPin* pin, REFGUID category);
+ static base::win::ScopedComPtr<IPin> GetPin(IBaseFilter* filter,
+ PIN_DIRECTION pin_dir,
+ REFGUID category);
+ static VideoPixelFormat TranslateMediaSubtypeToPixelFormat(
+ const GUID& sub_type);
+
explicit VideoCaptureDeviceWin(const Name& device_name);
virtual ~VideoCaptureDeviceWin();
// Opens the device driver for this device.
- // This function is used by the static VideoCaptureDevice::Create function.
bool Init();
// VideoCaptureDevice implementation.
@@ -45,10 +73,6 @@ class VideoCaptureDeviceWin
scoped_ptr<VideoCaptureDevice::Client> client) OVERRIDE;
virtual void StopAndDeAllocate() OVERRIDE;
- static void GetDeviceNames(Names* device_names);
- static void GetDeviceSupportedFormats(const Name& device,
- VideoCaptureFormats* formats);
-
private:
enum InternalState {
kIdle, // The device driver is opened but camera is not in use.