Commit 8f68d009 authored by Réda Housni Alaoui's avatar Réda Housni Alaoui Committed by Commit Bot

[Video Capture Win] Append DirectShow virtual cameras to MediaFoundation

enumeration

MediaFoundation can't handle DirectShow virtual cameras.
This is to append MediaFoundation unsupported DirectShow cameras to the
camera enumeration supplied to the consumer.

Bug: 730068
Change-Id: I3240e2158f822c04a193ec20a091c1f17ee2e373
Reviewed-on: https://chromium-review.googlesource.com/1000853
Commit-Queue: Christian Fremerey <chfremer@chromium.org>
Reviewed-by: default avatarChristian Fremerey <chfremer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#549550}
parent 3a063d1b
......@@ -211,19 +211,27 @@ std::string GetDeviceModelId(const std::string& device_id) {
return id_vendor + ":" + id_product;
}
void GetDeviceDescriptorsDirectShow(Descriptors* device_descriptors) {
DCHECK(device_descriptors);
DVLOG(1) << __func__;
HRESULT EnumerateDirectShowDevices(IEnumMoniker** enum_moniker) {
ComPtr<ICreateDevEnum> dev_enum;
HRESULT hr = ::CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
IID_PPV_ARGS(&dev_enum));
if (FAILED(hr))
return;
return hr;
ComPtr<IEnumMoniker> enum_moniker;
hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
enum_moniker.GetAddressOf(), 0);
enum_moniker, 0);
return hr;
}
void GetDeviceDescriptorsDirectShow(
VideoCaptureDeviceFactoryWin::DirectShowEnumDevicesFunc
direct_show_enum_devices_func,
Descriptors* device_descriptors) {
DCHECK(device_descriptors);
DVLOG(1) << __func__;
ComPtr<IEnumMoniker> enum_moniker;
HRESULT hr = direct_show_enum_devices_func.Run(enum_moniker.GetAddressOf());
// CreateClassEnumerator returns S_FALSE on some Windows OS
// when no camera exist. Therefore the FAILED macro can't be used.
if (hr != S_OK)
......@@ -277,9 +285,25 @@ bool DescriptorsContainDeviceId(const Descriptors& descriptors,
}) != descriptors.end();
}
// Returns true if the provided descriptors contains a non DirectShow descriptor
// using the provided name and model
bool DescriptorsContainNonDirectShowNameAndModel(
const Descriptors& descriptors,
const std::string& name_and_model) {
return std::find_if(
descriptors.begin(), descriptors.end(),
[name_and_model](const VideoCaptureDeviceDescriptor& descriptor) {
return descriptor.capture_api !=
VideoCaptureApi::WIN_DIRECT_SHOW &&
name_and_model == descriptor.GetNameAndModel();
}) != descriptors.end();
}
void GetDeviceDescriptorsMediaFoundation(
VideoCaptureDeviceFactoryWin::MFEnumDeviceSourcesFunc
mf_enum_device_sources_func,
VideoCaptureDeviceFactoryWin::DirectShowEnumDevicesFunc
direct_show_enum_devices_func,
Descriptors* device_descriptors) {
DVLOG(1) << " GetDeviceDescriptorsMediaFoundation";
// Recent non-RGB (depth, IR) cameras could be marked as sensor cameras in
......@@ -324,6 +348,25 @@ void GetDeviceDescriptorsMediaFoundation(
devices[i]->Release();
}
}
// DirectShow virtual cameras are not supported by MediaFoundation.
// To overcome this, based on device name and model, we append
// missing DirectShow device descriptor to full descriptors list.
Descriptors direct_show_descriptors;
GetDeviceDescriptorsDirectShow(direct_show_enum_devices_func,
&direct_show_descriptors);
for (const auto& direct_show_descriptor : direct_show_descriptors) {
// DirectShow can produce two descriptors with same name and model.
// If those descriptors are missing from MediaFoundation, we want them both
// appended to the full descriptors list.
// Therefore, we prevent duplication by always comparing a DirectShow
// descriptor with a MediaFoundation one.
if (DescriptorsContainNonDirectShowNameAndModel(
*device_descriptors, direct_show_descriptor.GetNameAndModel())) {
continue;
}
device_descriptors->emplace_back(direct_show_descriptor);
}
}
void GetDeviceSupportedFormatsDirectShow(const Descriptor& descriptor,
......@@ -443,6 +486,8 @@ VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin()
weak_ptr_factory_(this) {
mf_enum_device_sources_func_ =
PlatformSupportsMediaFoundation() ? MFEnumDeviceSources : nullptr;
direct_show_enum_devices_func_ =
base::BindRepeating(&EnumerateDirectShowDevices);
if (!PlatformSupportsMediaFoundation()) {
use_media_foundation_ = false;
LogVideoCaptureWinBackendUsed(
......@@ -500,9 +545,11 @@ void VideoCaptureDeviceFactoryWin::GetDeviceDescriptors(
if (use_media_foundation_) {
GetDeviceDescriptorsMediaFoundation(mf_enum_device_sources_func_,
direct_show_enum_devices_func_,
device_descriptors);
} else {
GetDeviceDescriptorsDirectShow(device_descriptors);
GetDeviceDescriptorsDirectShow(direct_show_enum_devices_func_,
device_descriptors);
}
}
......
......@@ -30,6 +30,8 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
~VideoCaptureDeviceFactoryWin() override;
using MFEnumDeviceSourcesFunc = decltype(&MFEnumDeviceSources);
using DirectShowEnumDevicesFunc =
base::RepeatingCallback<HRESULT(IEnumMoniker**)>;
std::unique_ptr<VideoCaptureDevice> CreateDevice(
const VideoCaptureDeviceDescriptor& device_descriptor) override;
......@@ -49,6 +51,10 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
MFEnumDeviceSourcesFunc func) {
mf_enum_device_sources_func_ = func;
}
void set_direct_show_enum_devices_func_for_testing(
DirectShowEnumDevicesFunc func) {
direct_show_enum_devices_func_ = func;
}
private:
void EnumerateDevicesUWP(
......@@ -67,6 +73,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
// |mf_enum_device_sources_func_| points to MFEnumDeviceSources. It enables
// mock of Media Foundation API in unit tests.
MFEnumDeviceSourcesFunc mf_enum_device_sources_func_ = nullptr;
DirectShowEnumDevicesFunc direct_show_enum_devices_func_;
// For calling WinRT methods on a COM initiated thread.
base::Thread com_thread_;
......
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