Commit 037a83ca authored by mcasas's avatar mcasas Committed by Commit bot

Win Video Capture: add DirectShow WDM devices capabilities enumeration.

BUG=402684

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

Cr-Commit-Position: refs/heads/master@{#293127}
parent 739ce5d4
......@@ -28,7 +28,10 @@ VideoCaptureDevice::Name::Name(const std::string& name, const std::string& id)
VideoCaptureDevice::Name::Name(const std::string& name,
const std::string& id,
const CaptureApiType api_type)
: device_name_(name), unique_id_(id), capture_api_class_(api_type) {}
: device_name_(name),
unique_id_(id),
capture_api_class_(api_type),
capabilities_id_(id) {}
#endif
#if defined(OS_MACOSX)
......
......@@ -46,7 +46,7 @@ class MEDIA_EXPORT VideoCaptureDevice {
enum CaptureApiType {
MEDIA_FOUNDATION,
DIRECT_SHOW,
DIRECT_SHOW_WDM,
DIRECT_SHOW_WDM_CROSSBAR,
API_TYPE_UNKNOWN
};
#endif
......@@ -106,6 +106,16 @@ class MEDIA_EXPORT VideoCaptureDevice {
return capture_api_class_.capture_api_type();
}
#endif
#if defined(OS_WIN)
// Certain devices need an ID different from the |unique_id_| for
// capabilities retrieval.
const std::string& capabilities_id() const {
return capabilities_id_;
}
void set_capabilities_id(const std::string& id) {
capabilities_id_ = id;
}
#endif
#if defined(OS_MACOSX)
TransportType transport_type() const {
return transport_type_;
......@@ -139,6 +149,10 @@ class MEDIA_EXPORT VideoCaptureDevice {
CaptureApiClass capture_api_class_;
#endif
#if defined(OS_WIN)
// ID used for capabilities retrieval. By default is equal to |unique_id|.
std::string capabilities_id_;
#endif
#if defined(OS_MACOSX)
TransportType transport_type_;
// Flag used to mark blacklisted devices for QTKit Api.
......
......@@ -90,7 +90,10 @@ static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices,
return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count));
}
static void GetDeviceNamesDirectShow(Names* device_names) {
static void GetDeviceNamesDirectShow(
const CLSID class_id,
const Name::CaptureApiType capture_api_type,
Names* device_names) {
DCHECK(device_names);
DVLOG(1) << " GetDeviceNamesDirectShow";
......@@ -100,77 +103,59 @@ static void GetDeviceNamesDirectShow(Names* device_names) {
if (FAILED(hr))
return;
static const struct{
CLSID class_id;
Name::CaptureApiType capture_api_type;
} kDirectShowFilterClasses[] = {
{ CLSID_VideoInputDeviceCategory, Name::DIRECT_SHOW },
{ AM_KSCATEGORY_CROSSBAR, Name::DIRECT_SHOW_WDM}
};
ScopedComPtr<IEnumMoniker> enum_moniker;
hr = dev_enum->CreateClassEnumerator(class_id, 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;
// Name of a fake DirectShow filter that exist on computers with
// GTalk installed.
static const char kGoogleCameraAdapter[] = "google camera adapter";
device_names->clear();
for (int class_index = 0; class_index < arraysize(kDirectShowFilterClasses);
++class_index) {
ScopedComPtr<IEnumMoniker> enum_moniker;
hr = dev_enum->CreateClassEnumerator(
kDirectShowFilterClasses[class_index].class_id,
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)
continue;
// 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;
}
// 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();
return;
}
// 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,
kDirectShowFilterClasses[class_index].capture_api_type));
// 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, capture_api_type));
}
moniker.Release();
}
moniker.Release();
}
}
......@@ -222,11 +207,11 @@ static void GetDeviceSupportedFormatsDirectShow(const Name& device,
if (hr != S_OK)
return;
// Walk the capture devices. No need to check for device presence again, that
// is caught in GetDeviceFilter(). "google camera adapter" and old VFW devices
// are already skipped in the previous GetDeviceNames() enumeration.
// Walk the capture devices. No need to check for device presence again since
// that is anyway needed in GetDeviceFilter(). "google camera adapter" and old
// VFW devices are already skipped previously in GetDeviceNames() enumeration.
base::win::ScopedComPtr<IBaseFilter> capture_filter;
hr = VideoCaptureDeviceWin::GetDeviceFilter(device,
hr = VideoCaptureDeviceWin::GetDeviceFilter(device.capabilities_id(),
capture_filter.Receive());
if (!capture_filter) {
DLOG(ERROR) << "Failed to create capture filter: "
......@@ -404,7 +389,7 @@ scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create(
device.reset();
} else {
DCHECK(device_name.capture_api_type() == Name::DIRECT_SHOW ||
device_name.capture_api_type() == Name::DIRECT_SHOW_WDM);
device_name.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR);
device.reset(new VideoCaptureDeviceWin(device_name));
DVLOG(1) << " DirectShow Device: " << device_name.name();
if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init())
......@@ -415,10 +400,33 @@ scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create(
void VideoCaptureDeviceFactoryWin::GetDeviceNames(Names* device_names) {
DCHECK(thread_checker_.CalledOnValidThread());
if (use_media_foundation_)
if (use_media_foundation_) {
GetDeviceNamesMediaFoundation(device_names);
else
GetDeviceNamesDirectShow(device_names);
} else {
GetDeviceNamesDirectShow(CLSID_VideoInputDeviceCategory,
Name::DIRECT_SHOW,
device_names);
Names crossbar_device_names;
GetDeviceNamesDirectShow(AM_KSCATEGORY_CROSSBAR,
Name::DIRECT_SHOW_WDM_CROSSBAR,
&crossbar_device_names);
// Search in the listed |device_names| to find a device with matching USB ID
// to each device in |crossbar_device_names|.
for (Names::iterator crossbar_device_it = crossbar_device_names.begin();
crossbar_device_it != crossbar_device_names.end();
++crossbar_device_it) {
const std::string& crossbar_device_model = crossbar_device_it->GetModel();
for (Names::const_iterator device_it = device_names->begin();
device_it != device_names->end(); ++device_it) {
if (crossbar_device_model == device_it->GetModel()) {
crossbar_device_it->set_capabilities_id(device_it->id());
device_names->push_back(*crossbar_device_it);
break;
}
}
}
}
}
void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats(
......
......@@ -23,9 +23,8 @@ namespace media {
// Finds and creates a DirectShow Video Capture filter matching the device_name.
// static
HRESULT VideoCaptureDeviceWin::GetDeviceFilter(
const VideoCaptureDevice::Name& device_name,
IBaseFilter** filter) {
HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id,
IBaseFilter** filter) {
DCHECK(filter);
ScopedComPtr<ICreateDevEnum> dev_enum;
......@@ -65,7 +64,7 @@ HRESULT VideoCaptureDeviceWin::GetDeviceFilter(
}
if (name.type() == VT_BSTR) {
std::string device_path(base::SysWideToUTF8(V_BSTR(&name)));
if (device_path.compare(device_name.id()) == 0) {
if (device_path.compare(device_id) == 0) {
// We have found the requested device
hr = moniker->BindToObject(0, 0, IID_IBaseFilter,
capture_filter.ReceiveVoid());
......@@ -224,7 +223,7 @@ VideoCaptureDeviceWin::~VideoCaptureDeviceWin() {
bool VideoCaptureDeviceWin::Init() {
DCHECK(CalledOnValidThread());
HRESULT hr = GetDeviceFilter(device_name_, capture_filter_.Receive());
HRESULT hr = GetDeviceFilter(device_name_.id(), capture_filter_.Receive());
if (!capture_filter_) {
DLOG(ERROR) << "Failed to create capture filter: "
<< logging::SystemErrorCodeToString(hr);
......
......@@ -53,7 +53,7 @@ class VideoCaptureDeviceWin
AM_MEDIA_TYPE* media_type_;
};
static HRESULT GetDeviceFilter(const Name& device_name,
static HRESULT GetDeviceFilter(const std::string& device_id,
IBaseFilter** filter);
static bool PinMatchesCategory(IPin* pin, REFGUID category);
static base::win::ScopedComPtr<IPin> GetPin(IBaseFilter* filter,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment