Commit c36b0902 authored by Isuru Pathirana's avatar Isuru Pathirana Committed by Commit Bot

Reland [Win Camera Capture]Use D3D11 with Media Foundation Video Capture

This is a reland of f2f4de88.
The original version of this change caused crashes when running the
capture unit tests on Win7 (due to the MF DXGI Device Manager not being
supported on Win7).

The capture unit tests have been updated to skip MF D3D11 tests on Win7
 or earlier.

Original CL description:

[Win Camera Capture] Use D3D11 with Media Foundation Video Capture

This CL updates the VideoCaptureDeviceFactoryWin/VideoCaptureDeviceMFWin
implementations to use D3D11 with the MF device source and capture
engine. The VideoCaptureDeviceFactoryWin creates and manages an
IMFDXGIDeviceManager and associated D3D11 device instance. It provides
the IMFDXGIDeviceManager to the MF device source and also plumbs it to
the VideoCaptureDeviceMFWin implementation. The VideoCaptureDeviceMFWin
implementation subsequently provides the IMFDXGIDeviceManager to the MF
capture engine on initialization.

Providing a MF DXGI device manager to the MF device source and capture
engine is required for zero-copy capture (it allows the Windows frame
server service and MF capture engine to keep captured video frames in
GPU memory and expose MF samples backed by D3D11 textures).

Bug: 1120900
Change-Id: I41f1ef14e7040c84fa63e0ad2618330d73e7cdc6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2434469Reviewed-by: default avatarIlya Nikolaevskiy <ilnik@chromium.org>
Reviewed-by: default avatarMarkus Handell <handellm@google.com>
Reviewed-by: default avatarHenrik Andreasson <henrika@chromium.org>
Reviewed-by: default avatarGuido Urdaneta <guidou@chromium.org>
Commit-Queue: Isuru Pathirana <Isuru.Pathirana@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#811483}
parent f4f799ec
...@@ -221,15 +221,19 @@ component("capture_lib") { ...@@ -221,15 +221,19 @@ component("capture_lib") {
"video/win/video_capture_device_utils_win.h", "video/win/video_capture_device_utils_win.h",
"video/win/video_capture_device_win.cc", "video/win/video_capture_device_win.cc",
"video/win/video_capture_device_win.h", "video/win/video_capture_device_win.h",
"video/win/video_capture_dxgi_device_manager.cc",
"video/win/video_capture_dxgi_device_manager.h",
] ]
deps += [ "//media/base/win:media_foundation_util" ] deps += [ "//media/base/win:media_foundation_util" ]
libs = [ libs = [
"d3d11.lib",
"mf.lib", "mf.lib",
"mfplat.lib", "mfplat.lib",
"mfreadwrite.lib", "mfreadwrite.lib",
"mfuuid.lib", "mfuuid.lib",
] ]
ldflags = [ ldflags = [
"/DELAYLOAD:d3d11.dll",
"/DELAYLOAD:mf.dll", "/DELAYLOAD:mf.dll",
"/DELAYLOAD:mfplat.dll", "/DELAYLOAD:mfplat.dll",
"/DELAYLOAD:mfreadwrite.dll", "/DELAYLOAD:mfreadwrite.dll",
......
...@@ -348,7 +348,7 @@ std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::CreateDevice( ...@@ -348,7 +348,7 @@ std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::CreateDevice(
break; break;
} }
auto device = std::make_unique<VideoCaptureDeviceMFWin>( auto device = std::make_unique<VideoCaptureDeviceMFWin>(
device_descriptor, std::move(source)); device_descriptor, std::move(source), dxgi_device_manager_);
DVLOG(1) << " MediaFoundation Device: " DVLOG(1) << " MediaFoundation Device: "
<< device_descriptor.display_name(); << device_descriptor.display_name();
if (device->Init()) if (device->Init())
...@@ -496,10 +496,16 @@ bool VideoCaptureDeviceFactoryWin::CreateDeviceSourceMediaFoundation( ...@@ -496,10 +496,16 @@ bool VideoCaptureDeviceFactoryWin::CreateDeviceSourceMediaFoundation(
bool VideoCaptureDeviceFactoryWin::CreateDeviceSourceMediaFoundation( bool VideoCaptureDeviceFactoryWin::CreateDeviceSourceMediaFoundation(
ComPtr<IMFAttributes> attributes, ComPtr<IMFAttributes> attributes,
IMFMediaSource** source) { IMFMediaSource** source_out) {
HRESULT hr = MFCreateDeviceSource(attributes.Get(), source); ComPtr<IMFMediaSource> source;
HRESULT hr = MFCreateDeviceSource(attributes.Get(), &source);
DLOG_IF(ERROR, FAILED(hr)) << "MFCreateDeviceSource failed: " DLOG_IF(ERROR, FAILED(hr)) << "MFCreateDeviceSource failed: "
<< logging::SystemErrorCodeToString(hr); << logging::SystemErrorCodeToString(hr);
if (SUCCEEDED(hr) && use_d3d11_with_media_foundation_ &&
dxgi_device_manager_) {
dxgi_device_manager_->RegisterWithMediaSource(source);
}
*source_out = source.Detach();
return SUCCEEDED(hr); return SUCCEEDED(hr);
} }
...@@ -698,6 +704,10 @@ DevicesInfo VideoCaptureDeviceFactoryWin::GetDevicesInfoMediaFoundation() { ...@@ -698,6 +704,10 @@ DevicesInfo VideoCaptureDeviceFactoryWin::GetDevicesInfoMediaFoundation() {
DevicesInfo devices_info; DevicesInfo devices_info;
if (use_d3d11_with_media_foundation_ && !dxgi_device_manager_) {
dxgi_device_manager_ = VideoCaptureDXGIDeviceManager::Create();
}
// Recent non-RGB (depth, IR) cameras could be marked as sensor cameras in // Recent non-RGB (depth, IR) cameras could be marked as sensor cameras in
// driver inf file and MFEnumDeviceSources enumerates them only if attribute // driver inf file and MFEnumDeviceSources enumerates them only if attribute
// KSCATEGORY_SENSOR_CAMERA is supplied. We enumerate twice. As it is possible // KSCATEGORY_SENSOR_CAMERA is supplied. We enumerate twice. As it is possible
......
...@@ -7,16 +7,19 @@ ...@@ -7,16 +7,19 @@
#ifndef MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_ #ifndef MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_
#define MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_ #define MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DEVICE_FACTORY_WIN_H_
#include <d3d11.h>
// Avoid including strsafe.h via dshow as it will cause build warnings. // Avoid including strsafe.h via dshow as it will cause build warnings.
#define NO_DSHOW_STRSAFE #define NO_DSHOW_STRSAFE
#include <dshow.h> #include <dshow.h>
#include <mfidl.h> #include <mfidl.h>
#include <windows.devices.enumeration.h> #include <windows.devices.enumeration.h>
#include <wrl.h>
#include "base/macros.h" #include "base/macros.h"
#include "base/threading/thread.h" #include "base/threading/thread.h"
#include "media/base/win/mf_initializer.h" #include "media/base/win/mf_initializer.h"
#include "media/capture/video/video_capture_device_factory.h" #include "media/capture/video/video_capture_device_factory.h"
#include "media/capture/video/win/video_capture_dxgi_device_manager.h"
namespace media { namespace media {
...@@ -41,6 +44,10 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin ...@@ -41,6 +44,10 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
use_media_foundation_ = use; use_media_foundation_ = use;
} }
void set_use_d3d11_with_media_foundation_for_testing(bool use) {
use_d3d11_with_media_foundation_ = use;
}
protected: protected:
// Protected and virtual for testing. // Protected and virtual for testing.
virtual bool CreateDeviceEnumMonikerDirectShow(IEnumMoniker** enum_moniker); virtual bool CreateDeviceEnumMonikerDirectShow(IEnumMoniker** enum_moniker);
...@@ -51,7 +58,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin ...@@ -51,7 +58,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
IBaseFilter** capture_filter); IBaseFilter** capture_filter);
virtual bool CreateDeviceSourceMediaFoundation(const std::string& device_id, virtual bool CreateDeviceSourceMediaFoundation(const std::string& device_id,
VideoCaptureApi capture_api, VideoCaptureApi capture_api,
IMFMediaSource** source); IMFMediaSource** source_out);
virtual bool CreateDeviceSourceMediaFoundation( virtual bool CreateDeviceSourceMediaFoundation(
Microsoft::WRL::ComPtr<IMFAttributes> attributes, Microsoft::WRL::ComPtr<IMFAttributes> attributes,
IMFMediaSource** source); IMFMediaSource** source);
...@@ -66,6 +73,15 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin ...@@ -66,6 +73,15 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
Microsoft::WRL::ComPtr<IMFMediaSource> source, Microsoft::WRL::ComPtr<IMFMediaSource> source,
const std::string& display_name); const std::string& display_name);
bool use_d3d11_with_media_foundation_for_testing() {
return use_d3d11_with_media_foundation_;
}
scoped_refptr<VideoCaptureDXGIDeviceManager>
dxgi_device_manager_for_testing() {
return dxgi_device_manager_;
}
private: private:
void EnumerateDevicesUWP(std::vector<VideoCaptureDeviceInfo> devices_info, void EnumerateDevicesUWP(std::vector<VideoCaptureDeviceInfo> devices_info,
GetDevicesInfoCallback result_callback); GetDevicesInfoCallback result_callback);
...@@ -81,12 +97,15 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin ...@@ -81,12 +97,15 @@ class CAPTURE_EXPORT VideoCaptureDeviceFactoryWin
std::vector<VideoCaptureDeviceInfo> GetDevicesInfoDirectShow(); std::vector<VideoCaptureDeviceInfo> GetDevicesInfoDirectShow();
bool use_media_foundation_; bool use_media_foundation_;
bool use_d3d11_with_media_foundation_ = false;
MFSessionLifetime session_; MFSessionLifetime session_;
// For calling WinRT methods on a COM initiated thread. // For calling WinRT methods on a COM initiated thread.
base::Thread com_thread_; base::Thread com_thread_;
scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_;
std::unordered_set<IAsyncOperation<DeviceInformationCollection*>*> async_ops_; std::unordered_set<IAsyncOperation<DeviceInformationCollection*>*> async_ops_;
// For hardware acceleration in MediaFoundation capture engine
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager_;
base::WeakPtrFactory<VideoCaptureDeviceFactoryWin> weak_ptr_factory_{this}; base::WeakPtrFactory<VideoCaptureDeviceFactoryWin> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryWin); DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryWin);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/win/windows_version.h"
#include "media/capture/video/win/video_capture_device_factory_win.h" #include "media/capture/video/win/video_capture_device_factory_win.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -1119,6 +1120,12 @@ class FakeVideoCaptureDeviceFactoryWin : public VideoCaptureDeviceFactoryWin { ...@@ -1119,6 +1120,12 @@ class FakeVideoCaptureDeviceFactoryWin : public VideoCaptureDeviceFactoryWin {
&symbolic_link[0], length + 1, &length))) { &symbolic_link[0], length + 1, &length))) {
return false; return false;
} }
const bool has_dxgi_device_manager =
static_cast<bool>(dxgi_device_manager_for_testing());
if (use_d3d11_with_media_foundation_for_testing() !=
has_dxgi_device_manager) {
return false;
}
*source = *source =
AddReference(new StubMFMediaSource(base::SysWideToUTF8(symbolic_link))); AddReference(new StubMFMediaSource(base::SysWideToUTF8(symbolic_link)));
return true; return true;
...@@ -1199,23 +1206,39 @@ class VideoCaptureDeviceFactoryWinTest : public ::testing::Test { ...@@ -1199,23 +1206,39 @@ class VideoCaptureDeviceFactoryWinTest : public ::testing::Test {
return true; return true;
} }
bool ShouldSkipD3D11Test() {
// D3D11 is only supported with Media Foundation on Windows 8 or later
if (base::win::GetVersion() >= base::win::Version::WIN8)
return false;
DVLOG(1) << "D3D11 with Media foundation is not supported by the current "
"platform. "
"Skipping test.";
return true;
}
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
FakeVideoCaptureDeviceFactoryWin factory_; FakeVideoCaptureDeviceFactoryWin factory_;
const bool media_foundation_supported_; const bool media_foundation_supported_;
}; };
class VideoCaptureDeviceFactoryMFWinTest class VideoCaptureDeviceFactoryMFWinTest
: public VideoCaptureDeviceFactoryWinTest { : public VideoCaptureDeviceFactoryWinTest,
public testing::WithParamInterface<bool> {
void SetUp() override { void SetUp() override {
VideoCaptureDeviceFactoryWinTest::SetUp(); VideoCaptureDeviceFactoryWinTest::SetUp();
factory_.set_use_media_foundation_for_testing(true); factory_.set_use_media_foundation_for_testing(true);
} }
}; };
TEST_F(VideoCaptureDeviceFactoryMFWinTest, GetDevicesInfo) { TEST_P(VideoCaptureDeviceFactoryMFWinTest, GetDevicesInfo) {
if (ShouldSkipMFTest()) if (ShouldSkipMFTest())
return; return;
const bool use_d3d11 = GetParam();
if (use_d3d11 && ShouldSkipD3D11Test())
return;
factory_.set_use_d3d11_with_media_foundation_for_testing(use_d3d11);
std::vector<VideoCaptureDeviceInfo> devices_info; std::vector<VideoCaptureDeviceInfo> devices_info;
base::RunLoop run_loop; base::RunLoop run_loop;
factory_.GetDevicesInfo(base::BindLambdaForTesting( factory_.GetDevicesInfo(base::BindLambdaForTesting(
...@@ -1298,4 +1321,8 @@ TEST_F(VideoCaptureDeviceFactoryMFWinTest, GetDevicesInfo) { ...@@ -1298,4 +1321,8 @@ TEST_F(VideoCaptureDeviceFactoryMFWinTest, GetDevicesInfo) {
EXPECT_TRUE(it->descriptor.pan_tilt_zoom_supported()); EXPECT_TRUE(it->descriptor.pan_tilt_zoom_supported());
} }
INSTANTIATE_TEST_SUITE_P(VideoCaptureDeviceFactoryMFWinTests,
VideoCaptureDeviceFactoryMFWinTest,
testing::Bool());
} // namespace media } // namespace media
...@@ -713,12 +713,17 @@ HRESULT VideoCaptureDeviceMFWin::FillCapabilities( ...@@ -713,12 +713,17 @@ HRESULT VideoCaptureDeviceMFWin::FillCapabilities(
VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin( VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin(
const VideoCaptureDeviceDescriptor& device_descriptor, const VideoCaptureDeviceDescriptor& device_descriptor,
ComPtr<IMFMediaSource> source) ComPtr<IMFMediaSource> source,
: VideoCaptureDeviceMFWin(device_descriptor, source, nullptr) {} scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager)
: VideoCaptureDeviceMFWin(device_descriptor,
source,
std::move(dxgi_device_manager),
nullptr) {}
VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin( VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin(
const VideoCaptureDeviceDescriptor& device_descriptor, const VideoCaptureDeviceDescriptor& device_descriptor,
ComPtr<IMFMediaSource> source, ComPtr<IMFMediaSource> source,
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager,
ComPtr<IMFCaptureEngine> engine) ComPtr<IMFCaptureEngine> engine)
: facing_mode_(device_descriptor.facing), : facing_mode_(device_descriptor.facing),
create_mf_photo_callback_(base::BindRepeating(&CreateMFPhotoCallback)), create_mf_photo_callback_(base::BindRepeating(&CreateMFPhotoCallback)),
...@@ -736,7 +741,8 @@ VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin( ...@@ -736,7 +741,8 @@ VideoCaptureDeviceMFWin::VideoCaptureDeviceMFWin(
base::WaitableEvent::InitialState::NOT_SIGNALED), base::WaitableEvent::InitialState::NOT_SIGNALED),
// We never want to reset |capture_error_|. // We never want to reset |capture_error_|.
capture_error_(base::WaitableEvent::ResetPolicy::MANUAL, capture_error_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) { base::WaitableEvent::InitialState::NOT_SIGNALED),
dxgi_device_manager_(std::move(dxgi_device_manager)) {
DETACH_FROM_SEQUENCE(sequence_checker_); DETACH_FROM_SEQUENCE(sequence_checker_);
} }
...@@ -789,6 +795,10 @@ bool VideoCaptureDeviceMFWin::Init() { ...@@ -789,6 +795,10 @@ bool VideoCaptureDeviceMFWin::Init() {
return false; return false;
} }
if (dxgi_device_manager_) {
dxgi_device_manager_->RegisterInCaptureEngineAttributes(attributes.Get());
}
video_callback_ = new MFVideoCallback(this); video_callback_ = new MFVideoCallback(this);
hr = engine_->Initialize(video_callback_.get(), attributes.Get(), nullptr, hr = engine_->Initialize(video_callback_.get(), attributes.Get(), nullptr,
source_.Get()); source_.Get());
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "media/capture/video/video_capture_device.h" #include "media/capture/video/video_capture_device.h"
#include "media/capture/video/win/capability_list_win.h" #include "media/capture/video/win/capability_list_win.h"
#include "media/capture/video/win/metrics.h" #include "media/capture/video/win/metrics.h"
#include "media/capture/video/win/video_capture_dxgi_device_manager.h"
interface IMFSourceReader; interface IMFSourceReader;
...@@ -45,10 +46,12 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice { ...@@ -45,10 +46,12 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
explicit VideoCaptureDeviceMFWin( explicit VideoCaptureDeviceMFWin(
const VideoCaptureDeviceDescriptor& device_descriptor, const VideoCaptureDeviceDescriptor& device_descriptor,
Microsoft::WRL::ComPtr<IMFMediaSource> source); Microsoft::WRL::ComPtr<IMFMediaSource> source,
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager);
explicit VideoCaptureDeviceMFWin( explicit VideoCaptureDeviceMFWin(
const VideoCaptureDeviceDescriptor& device_descriptor, const VideoCaptureDeviceDescriptor& device_descriptor,
Microsoft::WRL::ComPtr<IMFMediaSource> source, Microsoft::WRL::ComPtr<IMFMediaSource> source,
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager,
Microsoft::WRL::ComPtr<IMFCaptureEngine> engine); Microsoft::WRL::ComPtr<IMFCaptureEngine> engine);
~VideoCaptureDeviceMFWin() override; ~VideoCaptureDeviceMFWin() override;
...@@ -95,6 +98,11 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice { ...@@ -95,6 +98,11 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
retry_delay_in_ms_ = retry_delay_in_ms; retry_delay_in_ms_ = retry_delay_in_ms;
} }
void set_dxgi_device_manager_for_testing(
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager) {
dxgi_device_manager_ = std::move(dxgi_device_manager);
}
private: private:
HRESULT ExecuteHresultCallbackWithRetries( HRESULT ExecuteHresultCallbackWithRetries(
base::RepeatingCallback<HRESULT()> callback, base::RepeatingCallback<HRESULT()> callback,
...@@ -150,6 +158,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice { ...@@ -150,6 +158,7 @@ class CAPTURE_EXPORT VideoCaptureDeviceMFWin : public VideoCaptureDevice {
base::queue<TakePhotoCallback> video_stream_take_photo_callbacks_; base::queue<TakePhotoCallback> video_stream_take_photo_callbacks_;
base::WaitableEvent capture_initialize_; base::WaitableEvent capture_initialize_;
base::WaitableEvent capture_error_; base::WaitableEvent capture_error_;
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
......
...@@ -13,9 +13,11 @@ ...@@ -13,9 +13,11 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
#include "base/win/windows_version.h"
#include "media/capture/video/win/sink_filter_win.h" #include "media/capture/video/win/sink_filter_win.h"
#include "media/capture/video/win/video_capture_device_factory_win.h" #include "media/capture/video/win/video_capture_device_factory_win.h"
#include "media/capture/video/win/video_capture_device_mf_win.h" #include "media/capture/video/win/video_capture_device_mf_win.h"
#include "media/capture/video/win/video_capture_dxgi_device_manager.h"
#include "testing/gmock/include/gmock/gmock.h" #include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
...@@ -514,6 +516,10 @@ class MockMFCaptureEngine : public MockInterface<IMFCaptureEngine> { ...@@ -514,6 +516,10 @@ class MockMFCaptureEngine : public MockInterface<IMFCaptureEngine> {
EXPECT_TRUE(pEventCallback); EXPECT_TRUE(pEventCallback);
EXPECT_TRUE(pAttributes); EXPECT_TRUE(pAttributes);
EXPECT_TRUE(pVideoSource); EXPECT_TRUE(pVideoSource);
Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> device_manager;
EXPECT_EQ(SUCCEEDED(pAttributes->GetUnknown(MF_CAPTURE_ENGINE_D3D_MANAGER,
IID_PPV_ARGS(&device_manager))),
expect_mf_dxgi_device_manager_attribute_);
event_callback = pEventCallback; event_callback = pEventCallback;
OnCorrectInitializeQueued(); OnCorrectInitializeQueued();
...@@ -589,8 +595,14 @@ class MockMFCaptureEngine : public MockInterface<IMFCaptureEngine> { ...@@ -589,8 +595,14 @@ class MockMFCaptureEngine : public MockInterface<IMFCaptureEngine> {
} }
} }
scoped_refptr<IMFCaptureEngineOnEventCallback> event_callback; scoped_refptr<IMFCaptureEngineOnEventCallback> event_callback;
void set_expect_mf_dxgi_device_manager_attribute(bool expect) {
expect_mf_dxgi_device_manager_attribute_ = expect;
}
private: private:
~MockMFCaptureEngine() override = default; ~MockMFCaptureEngine() override = default;
bool expect_mf_dxgi_device_manager_attribute_ = false;
}; };
class StubMFMediaType : public MockInterface<IMFMediaType> { class StubMFMediaType : public MockInterface<IMFMediaType> {
...@@ -959,8 +971,10 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test { ...@@ -959,8 +971,10 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test {
engine_(new MockMFCaptureEngine()), engine_(new MockMFCaptureEngine()),
client_(new MockClient()), client_(new MockClient()),
image_capture_client_(new MockImageCaptureClient()), image_capture_client_(new MockImageCaptureClient()),
device_( device_(new VideoCaptureDeviceMFWin(descriptor_,
new VideoCaptureDeviceMFWin(descriptor_, media_source_, engine_)), media_source_,
nullptr,
engine_)),
capture_source_(new MockMFCaptureSource()), capture_source_(new MockMFCaptureSource()),
capture_preview_sink_(new MockCapturePreviewSink()), capture_preview_sink_(new MockCapturePreviewSink()),
media_foundation_supported_( media_foundation_supported_(
...@@ -971,6 +985,9 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test { ...@@ -971,6 +985,9 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test {
return; return;
device_->set_max_retry_count_for_testing(3); device_->set_max_retry_count_for_testing(3);
device_->set_retry_delay_in_ms_for_testing(1); device_->set_retry_delay_in_ms_for_testing(1);
device_->set_dxgi_device_manager_for_testing(dxgi_device_manager_);
engine_->set_expect_mf_dxgi_device_manager_attribute(dxgi_device_manager_ !=
nullptr);
EXPECT_CALL(*(engine_.Get()), OnCorrectInitializeQueued()); EXPECT_CALL(*(engine_.Get()), OnCorrectInitializeQueued());
EXPECT_TRUE(device_->Init()); EXPECT_TRUE(device_->Init());
...@@ -989,6 +1006,16 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test { ...@@ -989,6 +1006,16 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test {
return true; return true;
} }
bool ShouldSkipD3D11Test() {
// D3D11 is only supported with Media Foundation on Windows 8 or later
if (base::win::GetVersion() >= base::win::Version::WIN8)
return false;
DVLOG(1) << "D3D11 with Media foundation is not supported by the current "
"platform. "
"Skipping test.";
return true;
}
void PrepareMFDeviceWithOneVideoStream(GUID mf_video_subtype) { void PrepareMFDeviceWithOneVideoStream(GUID mf_video_subtype) {
EXPECT_CALL(*capture_source_, DoGetDeviceStreamCount(_)) EXPECT_CALL(*capture_source_, DoGetDeviceStreamCount(_))
.WillRepeatedly(Invoke([](DWORD* stream_count) { .WillRepeatedly(Invoke([](DWORD* stream_count) {
...@@ -1180,6 +1207,7 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test { ...@@ -1180,6 +1207,7 @@ class VideoCaptureDeviceMFWinTest : public ::testing::Test {
scoped_refptr<MockMFCaptureSource> capture_source_; scoped_refptr<MockMFCaptureSource> capture_source_;
scoped_refptr<MockCapturePreviewSink> capture_preview_sink_; scoped_refptr<MockCapturePreviewSink> capture_preview_sink_;
base::test::TaskEnvironment task_environment_; base::test::TaskEnvironment task_environment_;
scoped_refptr<VideoCaptureDXGIDeviceManager> dxgi_device_manager_;
private: private:
const bool media_foundation_supported_; const bool media_foundation_supported_;
...@@ -1230,8 +1258,9 @@ TEST_F(VideoCaptureDeviceMFWinTest, CallClientOnErrorDurringInit) { ...@@ -1230,8 +1258,9 @@ TEST_F(VideoCaptureDeviceMFWinTest, CallClientOnErrorDurringInit) {
Microsoft::WRL::ComPtr<MockMFCaptureEngine> engine = Microsoft::WRL::ComPtr<MockMFCaptureEngine> engine =
new MockMFCaptureEngine(); new MockMFCaptureEngine();
std::unique_ptr<VideoCaptureDeviceMFWin> device = std::unique_ptr<VideoCaptureDeviceMFWin> device =
std::make_unique<VideoCaptureDeviceMFWin>(descriptor, media_source, std::make_unique<VideoCaptureDeviceMFWin>(
engine); descriptor, media_source,
/*mf_dxgi_device_manager=*/nullptr, engine);
EXPECT_CALL(*(engine.Get()), OnInitEventGuid).WillOnce([]() { EXPECT_CALL(*(engine.Get()), OnInitEventGuid).WillOnce([]() {
return MF_CAPTURE_ENGINE_INITIALIZED; return MF_CAPTURE_ENGINE_INITIALIZED;
...@@ -1258,8 +1287,9 @@ TEST_F(VideoCaptureDeviceMFWinTest, CallClientOnFireCaptureEngineInitEarly) { ...@@ -1258,8 +1287,9 @@ TEST_F(VideoCaptureDeviceMFWinTest, CallClientOnFireCaptureEngineInitEarly) {
Microsoft::WRL::ComPtr<MockMFCaptureEngine> engine = Microsoft::WRL::ComPtr<MockMFCaptureEngine> engine =
new MockMFCaptureEngine(); new MockMFCaptureEngine();
std::unique_ptr<VideoCaptureDeviceMFWin> device = std::unique_ptr<VideoCaptureDeviceMFWin> device =
std::make_unique<VideoCaptureDeviceMFWin>(descriptor, media_source, std::make_unique<VideoCaptureDeviceMFWin>(
engine); descriptor, media_source,
/*mf_dxgi_device_manager=*/nullptr, engine);
EXPECT_CALL(*(engine.Get()), OnInitEventGuid).WillOnce([]() { EXPECT_CALL(*(engine.Get()), OnInitEventGuid).WillOnce([]() {
return MF_CAPTURE_ENGINE_INITIALIZED; return MF_CAPTURE_ENGINE_INITIALIZED;
...@@ -1285,8 +1315,9 @@ TEST_F(VideoCaptureDeviceMFWinTest, ...@@ -1285,8 +1315,9 @@ TEST_F(VideoCaptureDeviceMFWinTest,
Microsoft::WRL::ComPtr<MockMFCaptureEngine> engine = Microsoft::WRL::ComPtr<MockMFCaptureEngine> engine =
new MockMFCaptureEngine(); new MockMFCaptureEngine();
std::unique_ptr<VideoCaptureDeviceMFWin> device = std::unique_ptr<VideoCaptureDeviceMFWin> device =
std::make_unique<VideoCaptureDeviceMFWin>(descriptor, media_source, std::make_unique<VideoCaptureDeviceMFWin>(
engine); descriptor, media_source,
/*mf_dxgi_device_manager=*/nullptr, engine);
EXPECT_CALL(*(engine.Get()), OnInitEventGuid).WillOnce([]() { EXPECT_CALL(*(engine.Get()), OnInitEventGuid).WillOnce([]() {
return MF_CAPTURE_ENGINE_INITIALIZED; return MF_CAPTURE_ENGINE_INITIALIZED;
...@@ -1661,4 +1692,24 @@ TEST_P(DepthCameraDeviceMFWinTest, AllocateAndStartDepthCamera) { ...@@ -1661,4 +1692,24 @@ TEST_P(DepthCameraDeviceMFWinTest, AllocateAndStartDepthCamera) {
capture_preview_sink_->sample_callback->OnSample(nullptr); capture_preview_sink_->sample_callback->OnSample(nullptr);
} }
class VideoCaptureDeviceMFWinTestWithDXGI : public VideoCaptureDeviceMFWinTest {
protected:
void SetUp() override {
if (ShouldSkipD3D11Test())
GTEST_SKIP();
dxgi_device_manager_ = VideoCaptureDXGIDeviceManager::Create();
VideoCaptureDeviceMFWinTest::SetUp();
}
};
TEST_F(VideoCaptureDeviceMFWinTestWithDXGI, SimpleInit) {
if (ShouldSkipTest())
return;
// The purpose of this test is to ensure that the capture engine is correctly
// initialized with a MF DXGI device manager.
// All required logic for this test is in SetUp().
}
} // namespace media } // namespace media
// Copyright (c) 2020 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/capture/video/win/video_capture_dxgi_device_manager.h"
#include <d3d11.h>
#include <mfcaptureengine.h>
#include "base/logging.h"
using Microsoft::WRL::ComPtr;
namespace media {
scoped_refptr<VideoCaptureDXGIDeviceManager>
VideoCaptureDXGIDeviceManager::Create() {
ComPtr<IMFDXGIDeviceManager> mf_dxgi_device_manager;
UINT d3d_device_reset_token = 0;
HRESULT hr = MFCreateDXGIDeviceManager(&d3d_device_reset_token,
&mf_dxgi_device_manager);
if (FAILED(hr)) {
DLOG(ERROR) << "Failed to create MF DXGI device manager: "
<< logging::SystemErrorCodeToString(hr);
return scoped_refptr<VideoCaptureDXGIDeviceManager>();
}
scoped_refptr<VideoCaptureDXGIDeviceManager>
video_capture_dxgi_device_manager(new VideoCaptureDXGIDeviceManager(
std::move(mf_dxgi_device_manager), d3d_device_reset_token));
if (!video_capture_dxgi_device_manager->ResetDevice()) {
// If setting a device failed, ensure that an empty scoped_refptr is
// returned so that we fall back to software mode
return scoped_refptr<VideoCaptureDXGIDeviceManager>();
}
return video_capture_dxgi_device_manager;
}
VideoCaptureDXGIDeviceManager::VideoCaptureDXGIDeviceManager(
Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> mf_dxgi_device_manager,
UINT d3d_device_reset_token)
: mf_dxgi_device_manager_(std::move(mf_dxgi_device_manager)),
d3d_device_reset_token_(d3d_device_reset_token) {}
VideoCaptureDXGIDeviceManager::~VideoCaptureDXGIDeviceManager() {}
bool VideoCaptureDXGIDeviceManager::ResetDevice() {
Microsoft::WRL::ComPtr<ID3D11Device> d3d_device;
constexpr uint32_t device_flags =
(D3D11_CREATE_DEVICE_VIDEO_SUPPORT | D3D11_CREATE_DEVICE_BGRA_SUPPORT);
HRESULT hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr,
device_flags, nullptr, 0, D3D11_SDK_VERSION,
&d3d_device, nullptr, nullptr);
if (FAILED(hr)) {
DLOG(ERROR) << "D3D11 device creation failed: "
<< logging::SystemErrorCodeToString(hr);
return false;
}
hr = mf_dxgi_device_manager_->ResetDevice(d3d_device.Get(),
d3d_device_reset_token_);
if (FAILED(hr)) {
DLOG(ERROR) << "Failed to reset device on MF DXGI device manager: "
<< logging::SystemErrorCodeToString(hr);
return false;
}
return true;
}
void VideoCaptureDXGIDeviceManager::RegisterInCaptureEngineAttributes(
IMFAttributes* attributes) {
HRESULT result = attributes->SetUnknown(MF_CAPTURE_ENGINE_D3D_MANAGER,
mf_dxgi_device_manager_.Get());
DCHECK(SUCCEEDED(result));
}
void VideoCaptureDXGIDeviceManager::RegisterWithMediaSource(
ComPtr<IMFMediaSource> media_source) {
ComPtr<IMFMediaSourceEx> source_ext;
if (FAILED(media_source.As(&source_ext))) {
DCHECK(false);
return;
}
source_ext->SetD3DManager(mf_dxgi_device_manager_.Get());
}
} // namespace media
\ No newline at end of file
// Copyright (c) 2020 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.
#ifndef MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DXGI_DEVICE_MANAGER_H_
#define MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DXGI_DEVICE_MANAGER_H_
#include <mfapi.h>
#include <mfidl.h>
#include <wrl/client.h>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "media/capture/capture_export.h"
namespace media {
class CAPTURE_EXPORT VideoCaptureDXGIDeviceManager
: public base::RefCounted<VideoCaptureDXGIDeviceManager> {
public:
// Returns a VideoCaptureDXGIDeviceManager with associated D3D device set, or
// nullptr on failure.
static scoped_refptr<VideoCaptureDXGIDeviceManager> Create();
// Associates a new D3D device with the DXGI Device Manager
bool ResetDevice();
// Registers this manager in capture engine attributes.
void RegisterInCaptureEngineAttributes(IMFAttributes* attributes);
// Registers this manager with a media source
void RegisterWithMediaSource(
Microsoft::WRL::ComPtr<IMFMediaSource> media_source);
protected:
friend class base::RefCounted<VideoCaptureDXGIDeviceManager>;
VideoCaptureDXGIDeviceManager(
Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> mf_dxgi_device_manager,
UINT d3d_device_reset_token);
virtual ~VideoCaptureDXGIDeviceManager();
Microsoft::WRL::ComPtr<IMFDXGIDeviceManager> mf_dxgi_device_manager_;
UINT d3d_device_reset_token_ = 0;
};
} // namespace media
#endif // MEDIA_CAPTURE_VIDEO_WIN_VIDEO_CAPTURE_DXGI_DEVICE_MANAGER_H_
\ No newline at end of file
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