diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.cpp index 1e5590ee94..a77c4b4324 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.cpp @@ -63,15 +63,6 @@ using namespace Microsoft::WRL; G_LOCK_DEFINE_STATIC (dupl_list_lock); static GList *dupl_list = nullptr; -enum -{ - PROP_0, - PROP_D3D11_DEVICE, - PROP_OUTPUT_INDEX, -}; - -#define DEFAULT_MONITOR_INDEX -1 - /* Below implemenation were taken from Microsoft sample * https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/DXGIDesktopDuplication */ @@ -260,7 +251,7 @@ public: } GstFlowReturn - Init (GstD3D11Device * device, UINT monitor_index) + Init (GstD3D11Device * device, HMONITOR monitor) { GstFlowReturn ret; ID3D11Device *device_handle; @@ -270,7 +261,7 @@ public: if (!InitShader (device)) return GST_FLOW_ERROR; - ret = InitDupl (device, monitor_index); + ret = InitDupl (device, monitor); if (ret != GST_FLOW_OK) return ret; @@ -661,34 +652,22 @@ private: /* Maybe returning expected error code depending on desktop status */ GstFlowReturn - InitDupl (GstD3D11Device * device, UINT monitor_index) + InitDupl (GstD3D11Device * device, HMONITOR monitor) { ComPtr d3d11_device; - ComPtr dxgi_device; - ComPtr adapter; + ComPtr adapter; ComPtr output; ComPtr output1; d3d11_device = gst_d3d11_device_get_device_handle (device); - HRESULT hr = d3d11_device.As (&dxgi_device); + HRESULT hr = gst_d3d11_desktop_dup_find_output_for_monitor (monitor, + &adapter, &output); if (!gst_d3d11_result (hr, device)) { - GST_ERROR ("Couldn't get IDXGIDevice interface, hr 0x%x", (guint) hr); + GST_ERROR ("Couldn't get adapter and output for monitor"); return GST_FLOW_ERROR; } - hr = dxgi_device->GetParent (IID_PPV_ARGS (&adapter)); - if (!gst_d3d11_result (hr, device)) { - return gst_d3d11_desktop_dup_return_from_hr (d3d11_device.Get(), - hr, SystemTransitionsExpectedErrors); - } - - hr = adapter->EnumOutputs(monitor_index, &output); - if (!gst_d3d11_result (hr, device)) { - return gst_d3d11_desktop_dup_return_from_hr (d3d11_device.Get(), - hr, EnumOutputsExpectedErrors); - } - hr = output.As (&output1); if (!gst_d3d11_result (hr, device)) { GST_ERROR ("Couldn't get IDXGIOutput1 interface, hr 0x%x", (guint) hr); @@ -1469,6 +1448,15 @@ private: }; /* *INDENT-ON* */ +enum +{ + PROP_0, + PROP_D3D11_DEVICE, + PROP_MONITOR_HANDLE, +}; + +#define DEFAULT_MONITOR_INDEX -1 + struct _GstD3D11DesktopDup { GstObject parent; @@ -1479,8 +1467,7 @@ struct _GstD3D11DesktopDup D3D11DesktopDupObject *dupl_obj; - gboolean primary; - gint monitor_index; + HMONITOR monitor_handle; RECT desktop_coordinates; gboolean prepared; @@ -1512,10 +1499,9 @@ gst_d3d11_desktop_dup_class_init (GstD3D11DesktopDupClass * klass) GST_TYPE_D3D11_DEVICE, (GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS))); - g_object_class_install_property (gobject_class, PROP_OUTPUT_INDEX, - g_param_spec_int ("monitor-index", "Monitor Index", - "Zero-based index for monitor to capture (-1 = primary monitor)", - -1, G_MAXINT, DEFAULT_MONITOR_INDEX, (GParamFlags) + g_object_class_install_property (gobject_class, PROP_MONITOR_HANDLE, + g_param_spec_pointer ("monitor-handle", "Monitor Handle", + "A HMONITOR handle of monitor to capture", (GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS))); } @@ -1523,106 +1509,44 @@ gst_d3d11_desktop_dup_class_init (GstD3D11DesktopDupClass * klass) static void gst_d3d11_desktop_dup_init (GstD3D11DesktopDup * self) { - self->monitor_index = DEFAULT_MONITOR_INDEX; g_rec_mutex_init (&self->lock); memset (&self->desktop_coordinates, 0, sizeof (RECT)); } -static gboolean -gst_d3d11_desktop_dup_get_monitor_size (GstD3D11DesktopDup * self, - HMONITOR hmonitor, RECT * size) -{ - MONITORINFOEX monitor_info; - DEVMODE dev_mode; - - monitor_info.cbSize = sizeof (MONITORINFOEX); - if (!GetMonitorInfo (hmonitor, (LPMONITORINFO) & monitor_info)) { - GST_WARNING_OBJECT (self, "Couldn't get monitor info"); - return FALSE; - } - - dev_mode.dmSize = sizeof (DEVMODE); - dev_mode.dmDriverExtra = sizeof (POINTL); - dev_mode.dmFields = DM_POSITION; - if (!EnumDisplaySettings - (monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode)) { - GST_WARNING_OBJECT (self, "Couldn't enumerate display settings"); - return FALSE; - } - - size->left = dev_mode.dmPosition.x; - size->top = dev_mode.dmPosition.y; - size->right = size->left + dev_mode.dmPelsWidth; - size->bottom = size->top + dev_mode.dmPelsHeight; - - return TRUE; -} - static void gst_d3d11_desktop_dup_constructed (GObject * object) { GstD3D11DesktopDup *self = GST_D3D11_DESKTOP_DUP (object); /* *INDENT-OFF* */ ComPtr dxgi_device; - ComPtr adapter; + ComPtr adapter; ComPtr output; ComPtr output1; /* *INDENT-ON* */ - ID3D11Device *device_handle; HRESULT hr; gboolean ret = FALSE; DXGI_OUTPUT_DESC output_desc; + DXGI_ADAPTER_DESC adapter_desc; + gint64 luid, device_luid; if (!self->device) { GST_WARNING_OBJECT (self, "D3D11 device is unavailable"); - return; + goto out; } - device_handle = gst_d3d11_device_get_device_handle (self->device); - - /* Below code is just for getting resolution of IDXGIOutput (i.e., monitor) - * and we will setup IDXGIOutputDuplication interface later. - */ - hr = device_handle->QueryInterface (IID_PPV_ARGS (&dxgi_device)); - if (!gst_d3d11_result (hr, self->device)) + if (!self->monitor_handle) { + GST_WARNING_OBJECT (self, "Null monitor handle"); goto out; + } - hr = dxgi_device->GetParent (IID_PPV_ARGS (&adapter)); - if (!gst_d3d11_result (hr, self->device)) + hr = gst_d3d11_desktop_dup_find_output_for_monitor (self->monitor_handle, + &adapter, &output); + if (!gst_d3d11_result (hr, self->device)) { + GST_WARNING_OBJECT (self, + "Failed to find associated adapter for monitor %p", + self->monitor_handle); goto out; - - if (self->monitor_index < 0) { - guint index = 0; - /* Enumerate all outputs to find primary monitor */ - do { - hr = adapter->EnumOutputs (index, output.ReleaseAndGetAddressOf ()); - if (!gst_d3d11_result (hr, self->device)) - goto out; - - output->GetDesc (&output_desc); - if (output_desc.DesktopCoordinates.left == 0 && - output_desc.DesktopCoordinates.top == 0) { - GST_DEBUG_OBJECT (self, "Found primary output, index %d", index); - self->monitor_index = index; - self->primary = TRUE; - break; - } - index++; - } while (gst_d3d11_result (hr, self->device)); - } else { - hr = adapter->EnumOutputs (self->monitor_index, &output); - if (!gst_d3d11_result (hr, self->device)) { - GST_WARNING_OBJECT (self, "No available output"); - goto out; - } - - output->GetDesc (&output_desc); - if (output_desc.DesktopCoordinates.left == 0 && - output_desc.DesktopCoordinates.top == 0) { - GST_DEBUG_OBJECT (self, "We are primary output"); - self->primary = TRUE; - } } hr = output.As (&output1); @@ -1631,14 +1555,53 @@ gst_d3d11_desktop_dup_constructed (GObject * object) goto out; } + hr = adapter->GetDesc (&adapter_desc); + if (!gst_d3d11_result (hr, self->device)) { + GST_WARNING_OBJECT (self, "Failed to get adapter desc"); + goto out; + } + + luid = gst_d3d11_luid_to_int64 (&adapter_desc.AdapterLuid); + g_object_get (self->device, "adapter-luid", &device_luid, nullptr); + if (luid != device_luid) { + GST_WARNING_OBJECT (self, "Incompatible d3d11 device"); + goto out; + } + + hr = output->GetDesc (&output_desc); + if (!gst_d3d11_result (hr, self->device)) { + GST_WARNING_OBJECT (self, "Failed to get output desc"); + goto out; + } + /* DesktopCoordinates will not report actual texture size in case that * application is running without dpi-awareness. To get actual monitor size, * we need to use Win32 API... */ - if (!gst_d3d11_desktop_dup_get_monitor_size (self, - output_desc.Monitor, &self->desktop_coordinates)) { + MONITORINFOEXW monitor_info; + DEVMODEW dev_mode; + + monitor_info.cbSize = sizeof (MONITORINFOEXW); + if (!GetMonitorInfoW (output_desc.Monitor, (LPMONITORINFO) & monitor_info)) { + GST_WARNING_OBJECT (self, "Couldn't get monitor info"); goto out; } + dev_mode.dmSize = sizeof (DEVMODEW); + dev_mode.dmDriverExtra = sizeof (POINTL); + dev_mode.dmFields = DM_POSITION; + if (!EnumDisplaySettingsW + (monitor_info.szDevice, ENUM_CURRENT_SETTINGS, &dev_mode)) { + GST_WARNING_OBJECT (self, "Couldn't enumerate display settings"); + goto out; + } + + self->desktop_coordinates.left = dev_mode.dmPosition.x; + self->desktop_coordinates.top = dev_mode.dmPosition.y; + self->desktop_coordinates.right = + dev_mode.dmPosition.x + dev_mode.dmPelsWidth; + self->desktop_coordinates.bottom = + dev_mode.dmPosition.y + dev_mode.dmPelsHeight; + self->cached_width = self->desktop_coordinates.right - self->desktop_coordinates.left; self->cached_height = @@ -1655,6 +1618,8 @@ gst_d3d11_desktop_dup_constructed (GObject * object) out: if (!ret) gst_clear_object (&self->device); + + G_OBJECT_CLASS (parent_class)->constructed (object); } static void @@ -1667,8 +1632,8 @@ gst_d3d11_desktop_dup_set_property (GObject * object, guint prop_id, case PROP_D3D11_DEVICE: self->device = (GstD3D11Device *) g_value_dup_object (value); break; - case PROP_OUTPUT_INDEX: - self->monitor_index = g_value_get_int (value); + case PROP_MONITOR_HANDLE: + self->monitor_handle = (HMONITOR) g_value_get_pointer (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1710,15 +1675,15 @@ gst_d3d11_desktop_dup_weak_ref_notify (gpointer data, GstD3D11DesktopDup * dupl) } GstD3D11DesktopDup * -gst_d3d11_desktop_dup_new (GstD3D11Device * device, gint monitor_index) +gst_d3d11_desktop_dup_new (GstD3D11Device * device, HMONITOR monitor_handle) { GstD3D11DesktopDup *self = nullptr; GList *iter; g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr); - /* Check if we have dup object corresponding to monitor_index, and if there is - * already configured capture object, reuse it. + /* Check if we have dup object corresponding to monitor_handle, + * and if there is already configured capture object, reuse it. * This is because of the limitation of desktop duplication API * (i.e., in a process, only one duplication object can exist). * See also @@ -1728,10 +1693,9 @@ gst_d3d11_desktop_dup_new (GstD3D11Device * device, gint monitor_index) for (iter = dupl_list; iter; iter = g_list_next (iter)) { GstD3D11DesktopDup *dupl = (GstD3D11DesktopDup *) iter->data; - if (dupl->monitor_index == monitor_index || - (monitor_index < 0 && dupl->primary)) { - GST_DEBUG ("Found configured desktop dup object for output index %d", - monitor_index); + if (dupl->monitor_handle == monitor_handle) { + GST_DEBUG ("Found configured desktop dup object for monitor handle %p", + monitor_handle); self = (GstD3D11DesktopDup *) gst_object_ref (dupl); break; } @@ -1743,7 +1707,7 @@ gst_d3d11_desktop_dup_new (GstD3D11Device * device, gint monitor_index) } self = (GstD3D11DesktopDup *) g_object_new (GST_TYPE_D3D11_DESKTOP_DUP, - "d3d11device", device, "monitor-index", monitor_index, nullptr); + "d3d11device", device, "monitor-handle", monitor_handle, nullptr); if (!self->device) { GST_WARNING_OBJECT (self, "Couldn't configure desktop dup object"); @@ -1778,7 +1742,7 @@ gst_d3d11_desktop_dup_prepare (GstD3D11DesktopDup * desktop) } desktop->dupl_obj = new D3D11DesktopDupObject (); - ret = desktop->dupl_obj->Init (desktop->device, desktop->monitor_index); + ret = desktop->dupl_obj->Init (desktop->device, desktop->monitor_handle); if (ret != GST_FLOW_OK) { GST_WARNING_OBJECT (desktop, "Couldn't prepare capturing, %sexpected failure", @@ -1885,3 +1849,154 @@ gst_d3d11_desktop_dup_capture (GstD3D11DesktopDup * desktop, return GST_FLOW_OK; } + +HRESULT +gst_d3d11_desktop_dup_find_output_for_monitor (HMONITOR monitor, + IDXGIAdapter1 ** adapter, IDXGIOutput ** output) +{ + ComPtr < IDXGIFactory1 > factory; + HRESULT hr = S_OK; + + g_return_val_if_fail (monitor != nullptr, E_INVALIDARG); + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (FAILED (hr)) + return hr; + + for (UINT adapter_idx = 0;; adapter_idx++) { + ComPtr < IDXGIAdapter1 > adapter_tmp; + + hr = factory->EnumAdapters1 (adapter_idx, &adapter_tmp); + if (FAILED (hr)) + break; + + for (UINT output_idx = 0;; output_idx++) { + ComPtr < IDXGIOutput > output_tmp; + DXGI_OUTPUT_DESC desc; + + hr = adapter_tmp->EnumOutputs (output_idx, &output_tmp); + if (FAILED (hr)) + break; + + hr = output_tmp->GetDesc (&desc); + if (FAILED (hr)) + continue; + + if (desc.Monitor == monitor) { + if (adapter) + *adapter = adapter_tmp.Detach (); + if (output) + *output = output_tmp.Detach (); + + return S_OK; + } + } + } + + return E_FAIL; +} + +HRESULT +gst_d3d11_desktop_dup_find_primary_monitor (HMONITOR * monitor, + IDXGIAdapter1 ** adapter, IDXGIOutput ** output) +{ + ComPtr < IDXGIFactory1 > factory; + HRESULT hr = S_OK; + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (FAILED (hr)) + return hr; + + for (UINT adapter_idx = 0;; adapter_idx++) { + ComPtr < IDXGIAdapter1 > adapter_tmp; + + hr = factory->EnumAdapters1 (adapter_idx, &adapter_tmp); + if (FAILED (hr)) + break; + + for (UINT output_idx = 0;; output_idx++) { + ComPtr < IDXGIOutput > output_tmp; + DXGI_OUTPUT_DESC desc; + MONITORINFOEXW minfo; + + hr = adapter_tmp->EnumOutputs (output_idx, &output_tmp); + if (FAILED (hr)) + break; + + hr = output_tmp->GetDesc (&desc); + if (FAILED (hr)) + continue; + + minfo.cbSize = sizeof (MONITORINFOEXW); + if (!GetMonitorInfoW (desc.Monitor, &minfo)) + continue; + + if ((minfo.dwFlags & MONITORINFOF_PRIMARY) != 0) { + if (monitor) + *monitor = desc.Monitor; + if (adapter) + *adapter = adapter_tmp.Detach (); + if (output) + *output = output_tmp.Detach (); + + return S_OK; + } + } + } + + return E_FAIL; +} + +HRESULT +gst_d3d11_desktop_dup_find_nth_monitor (guint index, HMONITOR * monitor, + IDXGIAdapter1 ** adapter, IDXGIOutput ** output) +{ + ComPtr < IDXGIFactory1 > factory; + HRESULT hr = S_OK; + guint num_found = 0; + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (FAILED (hr)) + return hr; + + for (UINT adapter_idx = 0;; adapter_idx++) { + ComPtr < IDXGIAdapter1 > adapter_tmp; + + hr = factory->EnumAdapters1 (adapter_idx, &adapter_tmp); + if (FAILED (hr)) + break; + + for (UINT output_idx = 0;; output_idx++) { + ComPtr < IDXGIOutput > output_tmp; + DXGI_OUTPUT_DESC desc; + MONITORINFOEXW minfo; + + hr = adapter_tmp->EnumOutputs (output_idx, &output_tmp); + if (FAILED (hr)) + break; + + hr = output_tmp->GetDesc (&desc); + if (FAILED (hr)) + continue; + + minfo.cbSize = sizeof (MONITORINFOEXW); + if (!GetMonitorInfoW (desc.Monitor, &minfo)) + continue; + + if (num_found == index) { + if (monitor) + *monitor = desc.Monitor; + if (adapter) + *adapter = adapter_tmp.Detach (); + if (output) + *output = output_tmp.Detach (); + + return S_OK; + } + + num_found++; + } + } + + return E_FAIL; +} diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.h b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.h index 5741c19316..eeacb995de 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.h +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdup.h @@ -36,7 +36,7 @@ G_DECLARE_FINAL_TYPE (GstD3D11DesktopDup, gst_d3d11_desktop_dup, GST, D3D11_DESKTOP_DUP, GstObject); GstD3D11DesktopDup * gst_d3d11_desktop_dup_new (GstD3D11Device * device, - gint output_index); + HMONITOR monitor_handle); GstFlowReturn gst_d3d11_desktop_dup_prepare (GstD3D11DesktopDup * desktop); @@ -49,6 +49,19 @@ GstFlowReturn gst_d3d11_desktop_dup_capture (GstD3D11DesktopDup * desktop, ID3D11RenderTargetView *rtv, gboolean draw_mouse); +HRESULT gst_d3d11_desktop_dup_find_output_for_monitor (HMONITOR monitor, + IDXGIAdapter1 ** adapter, + IDXGIOutput ** output); + +HRESULT gst_d3d11_desktop_dup_find_primary_monitor (HMONITOR * monitor, + IDXGIAdapter1 ** adapter, + IDXGIOutput ** output); + +HRESULT gst_d3d11_desktop_dup_find_nth_monitor (guint index, + HMONITOR * monitor, + IDXGIAdapter1 ** adapter, + IDXGIOutput ** output); + G_END_DECLS #endif /* __GST_D3D11_DESKTOP_DUP_H__ */ diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupdevice.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupdevice.cpp new file mode 100644 index 0000000000..db1c934e9b --- /dev/null +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupdevice.cpp @@ -0,0 +1,447 @@ +/* GStreamer + * Copyright (C) 2021 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstd3d11desktopdupdevice.h" +#include +#include +#include +#include +#include +#include +#include + +/* *INDENT-OFF* */ +using namespace Microsoft::WRL; +/* *INDENT-ON* */ + +GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_desktop_dup_device_debug); +#define GST_CAT_DEFAULT gst_d3d11_desktop_dup_device_debug + +static GstStaticCaps template_caps = + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES + (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, "BGRA") ";" + GST_VIDEO_CAPS_MAKE ("BGRA")); + +enum +{ + PROP_0, + PROP_MONITOR_HANDLE, +}; + +struct _GstD3D11DesktopDupDevice +{ + GstDevice parent; + + HMONITOR monitor_handle; +}; + +static void gst_d3d11_desktop_dup_device_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec); +static void gst_d3d11_desktop_dup_device_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec); +static GstElement *gst_d3d11_desktop_dup_device_create_element (GstDevice * + device, const gchar * name); + +G_DEFINE_TYPE (GstD3D11DesktopDupDevice, + gst_d3d11_desktop_dup_device, GST_TYPE_DEVICE); + +static void +gst_d3d11_desktop_dup_device_class_init (GstD3D11DesktopDupDeviceClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstDeviceClass *dev_class = GST_DEVICE_CLASS (klass); + + object_class->get_property = gst_d3d11_desktop_dup_device_get_property; + object_class->set_property = gst_d3d11_desktop_dup_device_set_property; + + g_object_class_install_property (object_class, PROP_MONITOR_HANDLE, + g_param_spec_uint64 ("monitor-handle", "Monitor Handle", + "A HMONITOR handle", 0, G_MAXUINT64, 0, + (GParamFlags) (G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY))); + + + dev_class->create_element = gst_d3d11_desktop_dup_device_create_element; +} + +static void +gst_d3d11_desktop_dup_device_init (GstD3D11DesktopDupDevice * self) +{ +} + +static void +gst_d3d11_desktop_dup_device_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstD3D11DesktopDupDevice *self = GST_D3D11_DESKTOP_DUP_DEVICE (object); + + switch (prop_id) { + case PROP_MONITOR_HANDLE: + g_value_set_uint64 (value, (guint64) self->monitor_handle); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_d3d11_desktop_dup_device_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstD3D11DesktopDupDevice *self = GST_D3D11_DESKTOP_DUP_DEVICE (object); + + switch (prop_id) { + case PROP_MONITOR_HANDLE: + self->monitor_handle = (HMONITOR) g_value_get_uint64 (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstElement * +gst_d3d11_desktop_dup_device_create_element (GstDevice * device, + const gchar * name) +{ + GstD3D11DesktopDupDevice *self = GST_D3D11_DESKTOP_DUP_DEVICE (device); + GstElement *elem; + + elem = gst_element_factory_make ("d3d11desktopdupsrc", name); + + g_object_set (elem, "monitor-handle", self->monitor_handle, NULL); + + return elem; +} + +struct _GstD3D11DesktopDupDeviceProvider +{ + GstDeviceProvider parent; +}; + +G_DEFINE_TYPE (GstD3D11DesktopDupDeviceProvider, + gst_d3d11_desktop_dup_device_provider, GST_TYPE_DEVICE_PROVIDER); + +static GList *gst_d3d11_desktop_dup_device_provider_probe (GstDeviceProvider * + provider); + +static void + gst_d3d11_desktop_dup_device_provider_class_init + (GstD3D11DesktopDupDeviceProviderClass * klass) +{ + GstDeviceProviderClass *provider_class = GST_DEVICE_PROVIDER_CLASS (klass); + + provider_class->probe = + GST_DEBUG_FUNCPTR (gst_d3d11_desktop_dup_device_provider_probe); + + gst_device_provider_class_set_static_metadata (provider_class, + "Direct3D11 Desktop Capture Device Provider", + "Source/Monitor", "List Direct3D11 desktop capture source devices", + "Seungha Yang "); +} + +static void +gst_d3d11_desktop_dup_device_provider_init (GstD3D11DesktopDupDeviceProvider * + self) +{ +} + +static gboolean +get_monitor_name (const MONITORINFOEXW * info, + DISPLAYCONFIG_TARGET_DEVICE_NAME * target) +{ + UINT32 num_path = 0; + UINT32 num_mode = 0; + LONG query_ret; + + memset (target, 0, sizeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)); + + query_ret = GetDisplayConfigBufferSizes (QDC_ONLY_ACTIVE_PATHS, + &num_path, &num_mode); + if (query_ret != ERROR_SUCCESS || num_path == 0 || num_mode == 0) + return FALSE; + + DISPLAYCONFIG_PATH_INFO *path_infos = (DISPLAYCONFIG_PATH_INFO *) + g_alloca (num_path * sizeof (DISPLAYCONFIG_PATH_INFO)); + DISPLAYCONFIG_MODE_INFO *mode_infos = (DISPLAYCONFIG_MODE_INFO *) + g_alloca (num_mode * sizeof (DISPLAYCONFIG_MODE_INFO)); + + query_ret = QueryDisplayConfig (QDC_ONLY_ACTIVE_PATHS, &num_path, + path_infos, &num_mode, mode_infos, nullptr); + if (query_ret != ERROR_SUCCESS) + return FALSE; + + for (UINT32 i = 0; i < num_path; i++) { + DISPLAYCONFIG_PATH_INFO *p = &path_infos[i]; + DISPLAYCONFIG_SOURCE_DEVICE_NAME source; + + memset (&source, 0, sizeof (DISPLAYCONFIG_SOURCE_DEVICE_NAME)); + + source.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + source.header.size = sizeof (DISPLAYCONFIG_SOURCE_DEVICE_NAME); + source.header.adapterId = p->sourceInfo.adapterId; + source.header.id = p->sourceInfo.id; + + query_ret = DisplayConfigGetDeviceInfo (&source.header); + if (query_ret != ERROR_SUCCESS) + continue; + + if (wcscmp (info->szDevice, source.viewGdiDeviceName) != 0) + continue; + + DISPLAYCONFIG_TARGET_DEVICE_NAME tmp; + + memset (&tmp, 0, sizeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)); + + tmp.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + tmp.header.size = sizeof (DISPLAYCONFIG_TARGET_DEVICE_NAME); + tmp.header.adapterId = p->sourceInfo.adapterId; + tmp.header.id = p->targetInfo.id; + + query_ret = DisplayConfigGetDeviceInfo (&tmp.header); + if (query_ret != ERROR_SUCCESS) + continue; + + memcpy (target, &tmp, sizeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)); + + return TRUE; + } + + return FALSE; +} + +/* XXX: please bump MinGW toolchain version, + * DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY defined in wingdi.h */ +typedef enum +{ + OUTPUT_TECH_OTHER = -1, + OUTPUT_TECH_HD15 = 0, + OUTPUT_TECH_SVIDEO = 1, + OUTPUT_TECH_COMPOSITE_VIDEO = 2, + OUTPUT_TECH_COMPONENT_VIDEO = 3, + OUTPUT_TECH_DVI = 4, + OUTPUT_TECH_HDMI = 5, + OUTPUT_TECH_LVDS = 6, + OUTPUT_TECH_D_JPN = 8, + OUTPUT_TECH_SDI = 9, + OUTPUT_TECH_DISPLAYPORT_EXTERNAL = 10, + OUTPUT_TECH_DISPLAYPORT_EMBEDDED = 11, + OUTPUT_TECH_UDI_EXTERNAL = 12, + OUTPUT_TECH_UDI_EMBEDDED = 13, + OUTPUT_TECH_SDTVDONGLE = 14, + OUTPUT_TECH_MIRACAST = 15, + OUTPUT_TECH_INDIRECT_WIRED = 16, + OUTPUT_TECH_INDIRECT_VIRTUAL = 17, + OUTPUT_TECH_INTERNAL = 0x80000000, + OUTPUT_TECH_FORCE_UINT32 = 0xFFFFFFFF +} GST_OUTPUT_TECHNOLOGY; + +static const gchar * +output_tech_to_string (GST_OUTPUT_TECHNOLOGY tech) +{ + switch (tech) { + case OUTPUT_TECH_HD15: + return "hd15"; + case OUTPUT_TECH_SVIDEO: + return "svideo"; + case OUTPUT_TECH_COMPOSITE_VIDEO: + return "composite-video"; + case OUTPUT_TECH_DVI: + return "dvi"; + case OUTPUT_TECH_HDMI: + return "hdmi"; + case OUTPUT_TECH_LVDS: + return "lvds"; + case OUTPUT_TECH_D_JPN: + return "d-jpn"; + case OUTPUT_TECH_SDI: + return "sdi"; + case OUTPUT_TECH_DISPLAYPORT_EXTERNAL: + return "displayport-external"; + case OUTPUT_TECH_DISPLAYPORT_EMBEDDED: + return "displayport-internal"; + case OUTPUT_TECH_UDI_EXTERNAL: + return "udi-external"; + case OUTPUT_TECH_UDI_EMBEDDED: + return "udi-embedded"; + case OUTPUT_TECH_SDTVDONGLE: + return "sdtv"; + case OUTPUT_TECH_MIRACAST: + return "miracast"; + case OUTPUT_TECH_INDIRECT_WIRED: + return "indirect-wired"; + case OUTPUT_TECH_INDIRECT_VIRTUAL: + return "indirect-virtual"; + case OUTPUT_TECH_INTERNAL: + return "internal"; + default: + break; + } + + return "unknown"; +} + +static GstDevice * +create_device (const DXGI_ADAPTER_DESC * adapter_desc, + const DXGI_OUTPUT_DESC * output_desc, + const MONITORINFOEXW * minfo, const DEVMODEW * dev_mode, + const DISPLAYCONFIG_TARGET_DEVICE_NAME * target) +{ + GstCaps *caps; + gint width, height, left, top, right, bottom; + GstStructure *props; + std::wstring_convert < std::codecvt_utf8 < wchar_t >, wchar_t >converter; + std::string device_name; + std::string display_name; + std::string device_path; + std::string device_description; + const gchar *output_type; + gboolean primary = FALSE; + GstDevice *device; + + left = (gint) dev_mode->dmPosition.x; + top = (gint) dev_mode->dmPosition.y; + width = dev_mode->dmPelsWidth; + height = dev_mode->dmPelsHeight; + right = left + width; + bottom = top + height; + + caps = gst_static_caps_get (&template_caps); + caps = gst_caps_make_writable (caps); + gst_caps_set_simple (caps, + "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, nullptr); + + device_name = converter.to_bytes (minfo->szDevice); + display_name = converter.to_bytes (target->monitorFriendlyDeviceName); + device_path = converter.to_bytes (target->monitorDevicePath); + device_description = converter.to_bytes (adapter_desc->Description); + output_type = + output_tech_to_string ((GST_OUTPUT_TECHNOLOGY) target->outputTechnology); + if ((minfo->dwFlags & MONITORINFOF_PRIMARY) != 0) + primary = TRUE; + + props = gst_structure_new ("d3d11desktopdupdevice-proplist", + "device.api", G_TYPE_STRING, "d3d11", + "device.name", G_TYPE_STRING, GST_STR_NULL (device_name.c_str ()), + "device.path", G_TYPE_STRING, GST_STR_NULL (device_path.c_str ()), + "device.primary", G_TYPE_BOOLEAN, primary, + "device.type", G_TYPE_STRING, output_type, + "device.hmonitor", G_TYPE_UINT64, (guint64) output_desc->Monitor, + "device.adapter.luid", G_TYPE_INT64, + gst_d3d11_luid_to_int64 (&adapter_desc->AdapterLuid), + "device.adapter.description", G_TYPE_STRING, + GST_STR_NULL (device_description.c_str ()), + "desktop.coordinates.left", G_TYPE_INT, + (gint) output_desc->DesktopCoordinates.left, + "desktop.coordinates.top", G_TYPE_INT, + (gint) output_desc->DesktopCoordinates.top, + "desktop.coordinates.right", G_TYPE_INT, + (gint) output_desc->DesktopCoordinates.right, + "desktop.coordinates.bottom", G_TYPE_INT, + (gint) output_desc->DesktopCoordinates.bottom, + "display.coordinates.left", G_TYPE_INT, left, + "display.coordinates.top", G_TYPE_INT, top, + "display.coordinates.right", G_TYPE_INT, right, + "display.coordinates.bottom", G_TYPE_INT, bottom, nullptr); + + device = (GstDevice *) g_object_new (GST_TYPE_D3D11_DESKTOP_DUP_DEVICE, + "display-name", display_name.c_str (), "caps", caps, "device-class", + "Source/Monitor", "properties", props, "monitor-handle", + (guint64) output_desc->Monitor, nullptr); + + gst_caps_unref (caps); + + return device; +} + +static GList * +gst_d3d11_desktop_dup_device_provider_probe (GstDeviceProvider * provider) +{ + GList *devices = nullptr; + ComPtr < IDXGIFactory1 > factory; + HRESULT hr = S_OK; + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (FAILED (hr)) + return nullptr; + + for (UINT adapter_idx = 0;; adapter_idx++) { + ComPtr < IDXGIAdapter1 > adapter; + DXGI_ADAPTER_DESC adapter_desc; + + hr = factory->EnumAdapters1 (adapter_idx, &adapter); + if (FAILED (hr)) + break; + + hr = adapter->GetDesc (&adapter_desc); + if (FAILED (hr)) + continue; + + for (UINT output_idx = 0;; output_idx++) { + ComPtr < IDXGIOutput > output; + ComPtr < IDXGIOutput1 > output1; + DXGI_OUTPUT_DESC desc; + MONITORINFOEXW minfo; + DEVMODEW dev_mode; + DISPLAYCONFIG_TARGET_DEVICE_NAME target; + GstDevice *dev; + + hr = adapter->EnumOutputs (output_idx, &output); + if (FAILED (hr)) + break; + + hr = output.As (&output1); + if (FAILED (hr)) + continue; + + hr = output->GetDesc (&desc); + if (FAILED (hr)) + continue; + + minfo.cbSize = sizeof (MONITORINFOEXW); + if (!GetMonitorInfoW (desc.Monitor, &minfo)) + continue; + + dev_mode.dmSize = sizeof (DEVMODEW); + dev_mode.dmDriverExtra = sizeof (POINTL); + dev_mode.dmFields = DM_POSITION; + if (!EnumDisplaySettingsW (minfo.szDevice, + ENUM_CURRENT_SETTINGS, &dev_mode)) { + continue; + } + + /* Human readable monitor name is not always availabe, if it's empty + * fill it with generic one */ + if (!get_monitor_name (&minfo, &target) || + wcslen (target.monitorFriendlyDeviceName) == 0) { + wcscpy (target.monitorFriendlyDeviceName, L"Generic PnP Monitor"); + } + + dev = create_device (&adapter_desc, &desc, &minfo, &dev_mode, &target); + devices = g_list_append (devices, dev); + } + } + + return devices; +} diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupdevice.h b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupdevice.h new file mode 100644 index 0000000000..d919424c7b --- /dev/null +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupdevice.h @@ -0,0 +1,36 @@ +/* GStreamer + * Copyright (C) 2021 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_D3D11_DESKTOP_DUP_DEVICE (gst_d3d11_desktop_dup_device_get_type()) +G_DECLARE_FINAL_TYPE (GstD3D11DesktopDupDevice, gst_d3d11_desktop_dup_device, + GST, D3D11_DESKTOP_DUP_DEVICE, GstDevice); + +#define GST_TYPE_D3D11_DESKTOP_DUP_DEVICE_PROVIDER (gst_d3d11_desktop_dup_device_provider_get_type()) +G_DECLARE_FINAL_TYPE (GstD3D11DesktopDupDeviceProvider, + gst_d3d11_desktop_dup_device_provider, + GST, D3D11_DESKTOP_DUP_DEVICE_PROVIDER, GstDeviceProvider); + +G_END_DECLS + diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupsrc.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupsrc.cpp index f5aa08775c..6861fb2e91 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupsrc.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11desktopdupsrc.cpp @@ -39,9 +39,13 @@ #include "gstd3d11desktopdupsrc.h" #include "gstd3d11desktopdup.h" #include "gstd3d11pluginutils.h" - +#include #include +/* *INDENT-OFF* */ +using namespace Microsoft::WRL; +/* *INDENT-ON* */ + GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_desktop_dup_debug); #define GST_CAT_DEFAULT gst_d3d11_desktop_dup_debug @@ -49,6 +53,7 @@ enum { PROP_0, PROP_MONITOR_INDEX, + PROP_MONITOR_HANDLE, PROP_SHOW_CURSOR, PROP_LAST, @@ -77,8 +82,9 @@ struct _GstD3D11DesktopDupSrc GstBufferPool *pool; - gint adapter; + gint64 adapter_luid; gint monitor_index; + HMONITOR monitor_handle; gboolean show_cursor; gboolean flushing; @@ -138,6 +144,13 @@ gst_d3d11_desktop_dup_src_class_init (GstD3D11DesktopDupSrcClass * klass) (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | G_PARAM_STATIC_STRINGS)); + properties[PROP_MONITOR_HANDLE] = + g_param_spec_uint64 ("monitor-handle", "Monitor Handle", + "A HMONITOR handle of monitor to capture", + 0, G_MAXUINT64, 0, + (GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | + G_PARAM_STATIC_STRINGS)); + properties[PROP_SHOW_CURSOR] = g_param_spec_boolean ("show-cursor", "Show Mouse Cursor", "Whether to show mouse cursor", @@ -183,8 +196,6 @@ gst_d3d11_desktop_dup_src_init (GstD3D11DesktopDupSrc * self) gst_base_src_set_live (GST_BASE_SRC (self), TRUE); gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME); - /* FIXME: investigate non-zero adapter use case */ - self->adapter = 0; self->monitor_index = DEFAULT_MONITOR_INDEX; self->show_cursor = DEFAULT_SHOW_CURSOR; self->min_latency = GST_CLOCK_TIME_NONE; @@ -212,6 +223,9 @@ gst_d3d11_desktop_dup_src_set_property (GObject * object, guint prop_id, case PROP_MONITOR_INDEX: self->monitor_index = g_value_get_int (value); break; + case PROP_MONITOR_HANDLE: + self->monitor_handle = (HMONITOR) g_value_get_uint64 (value); + break; case PROP_SHOW_CURSOR: self->show_cursor = g_value_get_boolean (value); break; @@ -231,6 +245,9 @@ gst_d3d11_desktop_dup_src_get_property (GObject * object, guint prop_id, case PROP_MONITOR_INDEX: g_value_set_int (value, self->monitor_index); break; + case PROP_MONITOR_HANDLE: + g_value_set_uint64 (value, (guint64) self->monitor_handle); + break; case PROP_SHOW_CURSOR: g_value_set_boolean (value, self->show_cursor); break; @@ -246,7 +263,8 @@ gst_d3d11_desktop_dup_src_set_context (GstElement * element, { GstD3D11DesktopDupSrc *self = GST_D3D11_DESKTOP_DUP_SRC (element); - gst_d3d11_handle_set_context (element, context, self->adapter, &self->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, self->adapter_luid, &self->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -487,20 +505,42 @@ gst_d3d11_desktop_dup_src_start (GstBaseSrc * bsrc) { GstD3D11DesktopDupSrc *self = GST_D3D11_DESKTOP_DUP_SRC (bsrc); GstFlowReturn ret; + HMONITOR monitor = self->monitor_handle; + ComPtr < IDXGIAdapter1 > adapter; + DXGI_ADAPTER_DESC desc; + HRESULT hr; - /* FIXME: this element will use only the first adapter, but - * this might cause issue in case of multi-gpu environment and - * some monitor is connected to non-default adapter */ - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), self->adapter, - &self->device)) { + if (monitor) { + hr = gst_d3d11_desktop_dup_find_output_for_monitor (monitor, + &adapter, nullptr); + } else if (self->monitor_index < 0) { + hr = gst_d3d11_desktop_dup_find_primary_monitor (&monitor, + &adapter, nullptr); + } else { + hr = gst_d3d11_desktop_dup_find_nth_monitor (self->monitor_index, + &monitor, &adapter, nullptr); + } + + if (FAILED (hr)) + goto error; + + hr = adapter->GetDesc (&desc); + if (FAILED (hr)) + goto error; + + self->adapter_luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid); + gst_clear_object (&self->device); + + if (!gst_d3d11_ensure_element_data_for_adapter_luid (GST_ELEMENT_CAST (self), + self->adapter_luid, &self->device)) { GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, - ("D3D11 device with adapter index %d is unavailble", self->adapter), - (NULL)); + ("D3D11 device for LUID %" G_GINT64_FORMAT " is unavailble", + self->adapter_luid), (nullptr)); return FALSE; } - self->dupl = gst_d3d11_desktop_dup_new (self->device, self->monitor_index); + self->dupl = gst_d3d11_desktop_dup_new (self->device, monitor); if (!self->dupl) goto error; @@ -524,16 +564,18 @@ gst_d3d11_desktop_dup_src_start (GstBaseSrc * bsrc) error: { GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, - ("Failed to prepare duplication for output index %d", - self->monitor_index), (NULL)); + ("Failed to prepare duplication with given configuration, " + "monitor-index: %d, monitor-handle: %p", + self->monitor_index, self->monitor_handle), (nullptr)); + return FALSE; } - return FALSE; unsupported: { GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ, - ("Failed to prepare duplication for output index %d", - self->monitor_index), + ("Failed to prepare duplication with given configuration, " + "monitor-index: %d, monitor-handle: %p", + self->monitor_index, self->monitor_handle), ("Try run the application on the integrated GPU")); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/meson.build b/subprojects/gst-plugins-bad/sys/d3d11/meson.build index 43f213d9c9..d7ddf664f7 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/meson.build +++ b/subprojects/gst-plugins-bad/sys/d3d11/meson.build @@ -84,7 +84,9 @@ if d3d11_winapi_desktop # Desktop Duplication API is unavailable for UWP # and MinGW is not supported due to some missing headers extra_args += ['-DHAVE_DXGI_DESKTOP_DUP'] - d3d11_sources += ['gstd3d11desktopdup.cpp', 'gstd3d11desktopdupsrc.cpp'] + d3d11_sources += ['gstd3d11desktopdup.cpp', + 'gstd3d11desktopdupdevice.cpp', + 'gstd3d11desktopdupsrc.cpp'] message('Enable D3D11 Desktop Duplication API') endif # multimedia clock is desktop only API diff --git a/subprojects/gst-plugins-bad/sys/d3d11/plugin.cpp b/subprojects/gst-plugins-bad/sys/d3d11/plugin.cpp index bc41e38825..0a8ffdfb47 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/plugin.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/plugin.cpp @@ -40,6 +40,7 @@ #endif #ifdef HAVE_DXGI_DESKTOP_DUP #include "gstd3d11desktopdupsrc.h" +#include "gstd3d11desktopdupdevice.h" #endif #ifdef HAVE_D3D11_VIDEO_PROC #include "gstd3d11deinterlace.h" @@ -68,6 +69,7 @@ GST_DEBUG_CATEGORY (gst_d3d11_av1_dec_debug); #ifdef HAVE_DXGI_DESKTOP_DUP GST_DEBUG_CATEGORY (gst_d3d11_desktop_dup_debug); +GST_DEBUG_CATEGORY (gst_d3d11_desktop_dup_device_debug); #endif #ifdef HAVE_D3D11_VIDEO_PROC @@ -213,8 +215,14 @@ plugin_init (GstPlugin * plugin) if (gst_d3d11_is_windows_8_or_greater ()) { GST_DEBUG_CATEGORY_INIT (gst_d3d11_desktop_dup_debug, "d3d11desktopdupsrc", 0, "d3d11desktopdupsrc"); + GST_DEBUG_CATEGORY_INIT (gst_d3d11_desktop_dup_device_debug, + "d3d11desktopdupdevice", 0, "d3d11desktopdupdevice"); + gst_element_register (plugin, "d3d11desktopdupsrc", GST_RANK_NONE, GST_TYPE_D3D11_DESKTOP_DUP_SRC); + gst_device_provider_register (plugin, + "d3d11desktopdupdeviceprovider", GST_RANK_PRIMARY, + GST_TYPE_D3D11_DESKTOP_DUP_DEVICE_PROVIDER); } #endif