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

Unified Diff: media/video/capture/win/video_capture_device_factory_win.cc

Issue 276383002: VideoCaptureDeviceWin: Extract class-static method into a Factory (both MF/DS) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: tommi@s comments. Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/video/capture/win/video_capture_device_factory_win.cc
diff --git a/media/video/capture/win/video_capture_device_win.cc b/media/video/capture/win/video_capture_device_factory_win.cc
similarity index 29%
copy from media/video/capture/win/video_capture_device_win.cc
copy to media/video/capture/win/video_capture_device_factory_win.cc
index e78c60450dd9bd7e2f9dba5135121109e8527dbf..36e618e4a4dcbe412054c10d62ea920023a4a269 100644
--- a/media/video/capture/win/video_capture_device_win.cc
+++ b/media/video/capture/win/video_capture_device_factory_win.cc
@@ -1,16 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_win.h"
-
-#include <ks.h>
-#include <ksmedia.h>
+#include "media/video/capture/win/video_capture_device_factory_win.h"
-#include <algorithm>
-#include <list>
+#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"
@@ -19,257 +17,80 @@
#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 {
-namespace {
-
-// Finds and creates a DirectShow Video Capture filter matching the device_name.
-HRESULT GetDeviceFilter(const VideoCaptureDevice::Name& device_name,
- IBaseFilter** filter) {
- DCHECK(filter);
-
- ScopedComPtr<ICreateDevEnum> dev_enum;
- HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
- CLSCTX_INPROC);
- if (FAILED(hr))
- return hr;
- 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 NULL;
-
- ScopedComPtr<IMoniker> moniker;
- ScopedComPtr<IBaseFilter> capture_filter;
- DWORD fetched = 0;
- while (enum_moniker->Next(1, moniker.Receive(), &fetched) == 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.
- static const wchar_t* kPropertyNames[] = {
- L"DevicePath", L"Description", L"FriendlyName"
- };
- ScopedVariant name;
- for (size_t i = 0;
- i < arraysize(kPropertyNames) && name.type() != VT_BSTR; ++i) {
- prop_bag->Read(kPropertyNames[i], name.Receive(), 0);
- }
- if (name.type() == VT_BSTR) {
- std::string device_path(base::SysWideToUTF8(V_BSTR(&name)));
- if (device_path.compare(device_name.id()) == 0) {
- // We have found the requested device
- hr = moniker->BindToObject(0, 0, IID_IBaseFilter,
- capture_filter.ReceiveVoid());
- DVPLOG_IF(2, FAILED(hr)) << "Failed to bind camera filter.";
- break;
- }
- }
- moniker.Release();
- }
-
- *filter = capture_filter.Detach();
- if (!*filter && SUCCEEDED(hr))
- hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
-
- return hr;
-}
-
-// Check if a Pin matches a category.
-bool PinMatchesCategory(IPin* pin, REFGUID category) {
- DCHECK(pin);
- bool found = false;
- ScopedComPtr<IKsPropertySet> ks_property;
- HRESULT hr = ks_property.QueryFrom(pin);
- if (SUCCEEDED(hr)) {
- GUID pin_category;
- DWORD return_value;
- hr = ks_property->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
- &pin_category, sizeof(pin_category), &return_value);
- if (SUCCEEDED(hr) && (return_value == sizeof(pin_category))) {
- found = (pin_category == category);
- }
- }
- return found;
-}
+// Lazy Instance to initialize the MediaFoundation Library.
+class MFInitializerSingleton {
+ public:
+ MFInitializerSingleton() { MFStartup(MF_VERSION, MFSTARTUP_LITE); }
+ ~MFInitializerSingleton() { MFShutdown(); }
+};
-// Finds a IPin on a IBaseFilter given the direction an category.
-ScopedComPtr<IPin> GetPin(IBaseFilter* filter, PIN_DIRECTION pin_dir,
- REFGUID category) {
- ScopedComPtr<IPin> pin;
- ScopedComPtr<IEnumPins> pin_emum;
- HRESULT hr = filter->EnumPins(pin_emum.Receive());
- if (pin_emum == NULL)
- return pin;
-
- // Get first unconnected pin.
- hr = pin_emum->Reset(); // set to first pin
- while ((hr = pin_emum->Next(1, pin.Receive(), NULL)) == S_OK) {
- PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1);
- hr = pin->QueryDirection(&this_pin_dir);
- if (pin_dir == this_pin_dir) {
- if (category == GUID_NULL || PinMatchesCategory(pin, category))
- return pin;
- }
- pin.Release();
- }
+static base::LazyInstance<MFInitializerSingleton> g_mf_initialize =
+ LAZY_INSTANCE_INITIALIZER;
- DCHECK(!pin);
- return pin;
+static void EnsureMediaFoundationInit() {
+ g_mf_initialize.Get();
}
-// 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;
- }
-}
+static bool LoadMediaFoundationDlls() {
+ static const wchar_t* const kMfDLLs[] = {
+ L"%WINDIR%\\system32\\mf.dll",
+ L"%WINDIR%\\system32\\mfplat.dll",
+ L"%WINDIR%\\system32\\mfreadwrite.dll",
+ };
-// 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);
+ 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;
}
-// 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_;
- }
+static bool PrepareVideoCaptureAttributesMediaFoundation(
+ IMFAttributes** attributes,
+ int count) {
+ EnsureMediaFoundationInit();
- private:
- AM_MEDIA_TYPE* media_type_;
-};
+ if (FAILED(MFCreateAttributes(attributes, count)))
+ return false;
-VideoPixelFormat TranslateMediaSubtypeToPixelFormat(const GUID& sub_type) {
- static struct {
- const GUID& sub_type;
- VideoPixelFormat format;
- } pixel_formats[] = {
- { kMediaSubTypeI420, PIXEL_FORMAT_I420 },
- { MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420 },
- { MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24 },
- { MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2 },
- { MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG },
- { MEDIASUBTYPE_UYVY, PIXEL_FORMAT_UYVY },
- { MEDIASUBTYPE_ARGB32, PIXEL_FORMAT_ARGB },
- };
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(pixel_formats); ++i) {
- if (sub_type == pixel_formats[i].sub_type)
- return pixel_formats[i].format;
- }
-#ifndef NDEBUG
- WCHAR guid_str[128];
- StringFromGUID2(sub_type, guid_str, arraysize(guid_str));
- DVLOG(2) << "Device (also) supports an unknown media type " << guid_str;
-#endif
- return PIXEL_FORMAT_UNKNOWN;
+ return SUCCEEDED((*attributes)->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
+ MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID));
}
-} // namespace
+static bool CreateVideoCaptureDeviceMediaFoundation(const char* sym_link,
+ IMFMediaSource** source) {
+ ScopedComPtr<IMFAttributes> attributes;
+ if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 2))
+ return false;
-// 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);
- }
-}
+ attributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
+ base::SysUTF8ToWide(sym_link).c_str());
-// 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);
- }
+ return SUCCEEDED(MFCreateDeviceSource(attributes, source));
}
-// static
-VideoCaptureDevice* VideoCaptureDevice::Create(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";
- }
+static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices,
+ UINT32* count) {
+ ScopedComPtr<IMFAttributes> attributes;
+ if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1))
+ return false;
- return ret;
+ return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count));
}
-// static
-void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) {
+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,
@@ -330,17 +151,47 @@ void VideoCaptureDeviceWin::GetDeviceNames(Names* device_names) {
id = base::SysWideToUTF8(V_BSTR(&name));
}
- device_names->push_back(Name(device_name, id, Name::DIRECT_SHOW));
+ device_names->push_back(VideoCaptureDevice::Name(device_name, id,
+ VideoCaptureDevice::Name::DIRECT_SHOW));
}
}
moniker.Release();
}
}
-// static
-void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device,
+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) << "GetDeviceSupportedFormats for " << device.name();
+ DVLOG(1) << "GetDeviceSupportedFormatsDirectShow for " << device.name();
ScopedComPtr<ICreateDevEnum> dev_enum;
HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
CLSCTX_INPROC);
@@ -381,14 +232,17 @@ void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device,
if (moniker.get()) {
base::win::ScopedComPtr<IBaseFilter> capture_filter;
- hr = GetDeviceFilter(device, capture_filter.Receive());
+ 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(
- GetPin(capture_filter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE));
+ VideoCaptureDeviceWin::GetPin(capture_filter,
+ PINDIR_OUTPUT,
+ PIN_CATEGORY_CAPTURE));
if (!output_capture_pin) {
DVLOG(2) << "Failed to get capture output pin";
return;
@@ -411,7 +265,7 @@ void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device,
scoped_ptr<BYTE[]> caps(new BYTE[size]);
for (int i = 0; i < count; ++i) {
- ScopedMediaType media_type;
+ 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.
@@ -424,7 +278,8 @@ void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device,
media_type->formattype == FORMAT_VideoInfo) {
VideoCaptureFormat format;
format.pixel_format =
- TranslateMediaSubtypeToPixelFormat(media_type->subtype);
+ VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
+ media_type->subtype);
if (format.pixel_format == PIXEL_FORMAT_UNKNOWN)
continue;
VIDEOINFOHEADER* h =
@@ -444,355 +299,143 @@ void VideoCaptureDeviceWin::GetDeviceSupportedFormats(const Name& device,
}
}
-VideoCaptureDeviceWin::VideoCaptureDeviceWin(const Name& device_name)
- : device_name_(device_name),
- state_(kIdle) {
- DetachFromThread();
-}
-
-VideoCaptureDeviceWin::~VideoCaptureDeviceWin() {
- DCHECK(CalledOnValidThread());
- if (media_control_)
- media_control_->Stop();
-
- if (graph_builder_) {
- if (sink_filter_) {
- graph_builder_->RemoveFilter(sink_filter_);
- sink_filter_ = NULL;
- }
-
- if (capture_filter_)
- graph_builder_->RemoveFilter(capture_filter_);
-
- if (mjpg_filter_)
- graph_builder_->RemoveFilter(mjpg_filter_);
- }
-}
-
-bool VideoCaptureDeviceWin::Init() {
- DCHECK(CalledOnValidThread());
- HRESULT hr = GetDeviceFilter(device_name_, capture_filter_.Receive());
- if (!capture_filter_) {
- DVLOG(2) << "Failed to create capture filter.";
- return false;
- }
-
- output_capture_pin_ =
- GetPin(capture_filter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE);
- if (!output_capture_pin_) {
- DVLOG(2) << "Failed to get capture output pin";
- return false;
- }
-
- // Create the sink filter used for receiving Captured frames.
- sink_filter_ = new SinkFilter(this);
- if (sink_filter_ == NULL) {
- DVLOG(2) << "Failed to create send filter";
- return false;
- }
-
- input_sink_pin_ = sink_filter_->GetPin(0);
-
- hr = graph_builder_.CreateInstance(CLSID_FilterGraph, NULL,
- CLSCTX_INPROC_SERVER);
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to create graph builder.";
- return false;
- }
-
- hr = graph_builder_.QueryInterface(media_control_.Receive());
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to create media control builder.";
- return false;
- }
-
- hr = graph_builder_->AddFilter(capture_filter_, NULL);
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to add the capture device to the graph.";
- return false;
- }
-
- hr = graph_builder_->AddFilter(sink_filter_, NULL);
- if (FAILED(hr)) {
- DVLOG(2)<< "Failed to add the send filter to the graph.";
- return false;
- }
-
- return CreateCapabilityMap();
-}
-
-void VideoCaptureDeviceWin::AllocateAndStart(
- const VideoCaptureParams& params,
- scoped_ptr<VideoCaptureDevice::Client> client) {
- DCHECK(CalledOnValidThread());
- if (state_ != kIdle)
- return;
-
- client_ = client.Pass();
-
- // Get the camera capability that best match the requested resolution.
- const VideoCaptureCapabilityWin& found_capability =
- capabilities_.GetBestMatchedFormat(
- params.requested_format.frame_size.width(),
- params.requested_format.frame_size.height(),
- params.requested_format.frame_rate);
- VideoCaptureFormat format = found_capability.supported_format;
-
- // Reduce the frame rate if the requested frame rate is lower
- // than the capability.
- if (format.frame_rate > params.requested_format.frame_rate)
- format.frame_rate = params.requested_format.frame_rate;
-
- ScopedComPtr<IAMStreamConfig> stream_config;
- HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive());
- if (FAILED(hr)) {
- SetErrorState("Can't get the Capture format settings");
+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;
}
- int count = 0, size = 0;
- hr = stream_config->GetNumberOfCapabilities(&count, &size);
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to GetNumberOfCapabilities";
+ HRESULT hr;
+ base::win::ScopedComPtr<IMFSourceReader> reader;
+ if (FAILED(hr = MFCreateSourceReaderFromMediaSource(source, NULL,
+ reader.Receive()))) {
+ DLOG(ERROR) << "MFCreateSourceReaderFromMediaSource: " << std::hex << hr;
return;
}
- scoped_ptr<BYTE[]> caps(new BYTE[size]);
- ScopedMediaType media_type;
-
- // Get the windows capability from the capture device.
- hr = stream_config->GetStreamCaps(
- found_capability.stream_index, media_type.Receive(), caps.get());
- if (SUCCEEDED(hr)) {
- if (media_type->formattype == FORMAT_VideoInfo) {
- VIDEOINFOHEADER* h =
- reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat);
- if (format.frame_rate > 0)
- h->AvgTimePerFrame = kSecondsToReferenceTime / format.frame_rate;
+ 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;
}
- // Set the sink filter to request this format.
- sink_filter_->SetRequestedMediaFormat(format);
- // Order the capture device to use this format.
- hr = stream_config->SetFormat(media_type.get());
- }
-
- if (FAILED(hr))
- SetErrorState("Failed to set capture device output format");
-
- if (format.pixel_format == PIXEL_FORMAT_MJPEG && !mjpg_filter_.get()) {
- // Create MJPG filter if we need it.
- hr = mjpg_filter_.CreateInstance(CLSID_MjpegDec, NULL, CLSCTX_INPROC);
+ VideoCaptureFormat capture_format;
+ capture_format.frame_size.SetSize(width, height);
- if (SUCCEEDED(hr)) {
- input_mjpg_pin_ = GetPin(mjpg_filter_, PINDIR_INPUT, GUID_NULL);
- output_mjpg_pin_ = GetPin(mjpg_filter_, PINDIR_OUTPUT, GUID_NULL);
- hr = graph_builder_->AddFilter(mjpg_filter_, NULL);
+ 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)) {
- mjpg_filter_.Release();
- input_mjpg_pin_.Release();
- output_mjpg_pin_.Release();
+ DLOG(ERROR) << "GetGUID: " << std::hex << hr;
+ return;
}
- }
-
- SetAntiFlickerInCaptureFilter();
-
- if (format.pixel_format == PIXEL_FORMAT_MJPEG && mjpg_filter_.get()) {
- // Connect the camera to the MJPEG decoder.
- hr = graph_builder_->ConnectDirect(output_capture_pin_, input_mjpg_pin_,
- NULL);
- // Connect the MJPEG filter to the Capture filter.
- hr += graph_builder_->ConnectDirect(output_mjpg_pin_, input_sink_pin_,
- NULL);
- } else {
- hr = graph_builder_->ConnectDirect(output_capture_pin_, input_sink_pin_,
- NULL);
- }
+ VideoCaptureDeviceMFWin::FormatFromGuid(type_guid,
+ &capture_format.pixel_format);
+ type.Release();
+ formats->push_back(capture_format);
+ ++stream_index;
- if (FAILED(hr)) {
- SetErrorState("Failed to connect the Capture graph.");
- return;
+ DVLOG(1) << device.name() << " resolution: "
+ << capture_format.frame_size.ToString() << ", fps: "
+ << capture_format.frame_rate << ", pixel format: "
+ << capture_format.pixel_format;
}
-
- hr = media_control_->Pause();
- if (FAILED(hr)) {
- SetErrorState("Failed to Pause the Capture device. "
- "Is it already occupied?");
- return;
- }
-
- // Get the format back from the sink filter after the filter have been
- // connected.
- capture_format_ = sink_filter_->ResultingFormat();
-
- // Start capturing.
- hr = media_control_->Run();
- if (FAILED(hr)) {
- SetErrorState("Failed to start the Capture device.");
- return;
- }
-
- state_ = kCapturing;
}
-void VideoCaptureDeviceWin::StopAndDeAllocate() {
- DCHECK(CalledOnValidThread());
- if (state_ != kCapturing)
- return;
-
- HRESULT hr = media_control_->Stop();
- if (FAILED(hr)) {
- SetErrorState("Failed to stop the capture graph.");
- return;
- }
-
- graph_builder_->Disconnect(output_capture_pin_);
- graph_builder_->Disconnect(input_sink_pin_);
-
- // If the _mjpg filter exist disconnect it even if it has not been used.
- if (mjpg_filter_) {
- graph_builder_->Disconnect(input_mjpg_pin_);
- graph_builder_->Disconnect(output_mjpg_pin_);
- }
-
- if (FAILED(hr)) {
- SetErrorState("Failed to Stop the Capture device");
- return;
- }
- client_.reset();
- state_ = kIdle;
-}
-
-// Implements SinkFilterObserver::SinkFilterObserver.
-void VideoCaptureDeviceWin::FrameReceived(const uint8* buffer,
- int length) {
- client_->OnIncomingCapturedData(
- buffer, length, capture_format_, 0, base::TimeTicks::Now());
-}
-
-bool VideoCaptureDeviceWin::CreateCapabilityMap() {
- DCHECK(CalledOnValidThread());
- ScopedComPtr<IAMStreamConfig> stream_config;
- HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive());
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to get IAMStreamConfig interface from "
- "capture device";
- return false;
- }
-
- // Get interface used for getting the frame rate.
- ScopedComPtr<IAMVideoControl> video_control;
- hr = capture_filter_.QueryInterface(video_control.Receive());
- DVLOG_IF(2, FAILED(hr)) << "IAMVideoControl Interface NOT SUPPORTED";
-
- int count = 0, size = 0;
- hr = stream_config->GetNumberOfCapabilities(&count, &size);
- if (FAILED(hr)) {
- DVLOG(2) << "Failed to GetNumberOfCapabilities";
+// 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;
- }
- 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 false;
- }
-
- if (media_type->majortype == MEDIATYPE_Video &&
- media_type->formattype == FORMAT_VideoInfo) {
- VideoCaptureCapabilityWin capability(i);
- capability.supported_format.pixel_format =
- TranslateMediaSubtypeToPixelFormat(media_type->subtype);
- if (capability.supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN)
- continue;
-
- VIDEOINFOHEADER* h =
- reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat);
- capability.supported_format.frame_size.SetSize(h->bmiHeader.biWidth,
- h->bmiHeader.biHeight);
-
- // Try to get a better |time_per_frame| from IAMVideoControl. If not, use
- // the value from VIDEOINFOHEADER.
- REFERENCE_TIME time_per_frame = h->AvgTimePerFrame;
- if (video_control) {
- ScopedCoMem<LONGLONG> max_fps;
- LONG list_size = 0;
- SIZE size = {capability.supported_format.frame_size.width(),
- capability.supported_format.frame_size.height()};
-
- // GetFrameRateList doesn't return max frame rate always
- // eg: Logitech Notebook. This may be due to a bug in that API
- // because GetFrameRateList array is reversed in the above camera. So
- // a util method written. Can't assume the first value will return
- // the max fps.
- hr = video_control->GetFrameRateList(output_capture_pin_, i, size,
- &list_size, &max_fps);
- // Sometimes |list_size| will be > 0, but max_fps will be NULL. Some
- // drivers may return an HRESULT of S_FALSE which SUCCEEDED() translates
- // into success, so explicitly check S_OK. See http://crbug.com/306237.
- if (hr == S_OK && list_size > 0 && max_fps) {
- time_per_frame = *std::min_element(max_fps.get(),
- max_fps.get() + list_size);
- }
- }
-
- capability.supported_format.frame_rate =
- (time_per_frame > 0)
- ? static_cast<int>(kSecondsToReferenceTime / time_per_frame)
- : 0;
-
- // DirectShow works at the moment only on integer frame_rate but the
- // best capability matching class works on rational frame rates.
- capability.frame_rate_numerator = capability.supported_format.frame_rate;
- capability.frame_rate_denominator = 1;
+ static bool g_dlls_available = LoadMediaFoundationDlls();
+ return g_dlls_available;
+}
- capabilities_.Add(capability);
+scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create(
+ 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 !capabilities_.empty();
+ return device.Pass();
}
-// Set the power line frequency removal in |capture_filter_| if available.
-void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter() {
- const int power_line_frequency = GetPowerLineFrequencyForLocation();
- if (power_line_frequency != kPowerLine50Hz &&
- power_line_frequency != kPowerLine60Hz) {
- return;
- }
- ScopedComPtr<IKsPropertySet> ks_propset;
- DWORD type_support = 0;
- HRESULT hr;
- if (SUCCEEDED(hr = ks_propset.QueryFrom(capture_filter_)) &&
- SUCCEEDED(hr = ks_propset->QuerySupported(PROPSETID_VIDCAP_VIDEOPROCAMP,
- KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, &type_support)) &&
- (type_support & KSPROPERTY_SUPPORT_SET)) {
- KSPROPERTY_VIDEOPROCAMP_S data = {};
- data.Property.Set = PROPSETID_VIDCAP_VIDEOPROCAMP;
- data.Property.Id = KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY;
- data.Property.Flags = KSPROPERTY_TYPE_SET;
- data.Value = (power_line_frequency == kPowerLine50Hz) ? 1 : 2;
- data.Flags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL;
- hr = ks_propset->Set(PROPSETID_VIDCAP_VIDEOPROCAMP,
- KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY,
- &data, sizeof(data), &data, sizeof(data));
- DVLOG_IF(ERROR, FAILED(hr)) << "Anti-flicker setting failed.";
- DVLOG_IF(2, SUCCEEDED(hr)) << "Anti-flicker set correctly.";
+void VideoCaptureDeviceFactoryWin::GetDeviceNames(
+ VideoCaptureDevice::Names* device_names) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ 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))) {
+ GetDeviceNamesMediaFoundation(device_names);
} else {
- DVLOG(2) << "Anti-flicker setting not supported.";
+ GetDeviceNamesDirectShow(device_names);
}
}
-void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) {
- DCHECK(CalledOnValidThread());
- DVLOG(1) << reason;
- state_ = kError;
- client_->OnError(reason);
+void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats(
+ const VideoCaptureDevice::Name& device,
+ VideoCaptureFormats* formats) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ 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() &&
tommi (sloooow) - chröme 2014/05/19 10:51:37 This is a copy/paste of the previous check, right?
mcasas 2014/05/19 12:59:50 Changed to member bool. It cleans up the code too.
+ !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) ||
+ (base::win::GetVersion() >= base::win::VERSION_WIN7 &&
+ cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture))) {
+ GetDeviceSupportedFormatsMediaFoundation(device, formats);
+ } else {
+ GetDeviceSupportedFormatsDirectShow(device, formats);
+ }
}
+
} // namespace media
« no previous file with comments | « media/video/capture/win/video_capture_device_factory_win.h ('k') | media/video/capture/win/video_capture_device_mf_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698