mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-06 22:42:35 +00:00
d3d11: Add device provider for d3d11desktopdupsrc
... and add support for multi-GPU/multi-monitor By using newly added "monitor-handle" property, user can specify a monitor to be captured via HMONITOR handle. Fixes: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1673 Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1103>
This commit is contained in:
parent
2200a3dbcd
commit
4b85704b88
7 changed files with 805 additions and 142 deletions
|
@ -63,15 +63,6 @@ using namespace Microsoft::WRL;
|
||||||
G_LOCK_DEFINE_STATIC (dupl_list_lock);
|
G_LOCK_DEFINE_STATIC (dupl_list_lock);
|
||||||
static GList *dupl_list = nullptr;
|
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
|
/* Below implemenation were taken from Microsoft sample
|
||||||
* https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/DXGIDesktopDuplication
|
* https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/DXGIDesktopDuplication
|
||||||
*/
|
*/
|
||||||
|
@ -260,7 +251,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
Init (GstD3D11Device * device, UINT monitor_index)
|
Init (GstD3D11Device * device, HMONITOR monitor)
|
||||||
{
|
{
|
||||||
GstFlowReturn ret;
|
GstFlowReturn ret;
|
||||||
ID3D11Device *device_handle;
|
ID3D11Device *device_handle;
|
||||||
|
@ -270,7 +261,7 @@ public:
|
||||||
if (!InitShader (device))
|
if (!InitShader (device))
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
|
|
||||||
ret = InitDupl (device, monitor_index);
|
ret = InitDupl (device, monitor);
|
||||||
if (ret != GST_FLOW_OK)
|
if (ret != GST_FLOW_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -661,34 +652,22 @@ private:
|
||||||
|
|
||||||
/* Maybe returning expected error code depending on desktop status */
|
/* Maybe returning expected error code depending on desktop status */
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
InitDupl (GstD3D11Device * device, UINT monitor_index)
|
InitDupl (GstD3D11Device * device, HMONITOR monitor)
|
||||||
{
|
{
|
||||||
ComPtr<ID3D11Device> d3d11_device;
|
ComPtr<ID3D11Device> d3d11_device;
|
||||||
ComPtr<IDXGIDevice> dxgi_device;
|
ComPtr<IDXGIAdapter1> adapter;
|
||||||
ComPtr<IDXGIAdapter> adapter;
|
|
||||||
ComPtr<IDXGIOutput> output;
|
ComPtr<IDXGIOutput> output;
|
||||||
ComPtr<IDXGIOutput1> output1;
|
ComPtr<IDXGIOutput1> output1;
|
||||||
|
|
||||||
d3d11_device = gst_d3d11_device_get_device_handle (device);
|
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)) {
|
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;
|
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);
|
hr = output.As (&output1);
|
||||||
if (!gst_d3d11_result (hr, device)) {
|
if (!gst_d3d11_result (hr, device)) {
|
||||||
GST_ERROR ("Couldn't get IDXGIOutput1 interface, hr 0x%x", (guint) hr);
|
GST_ERROR ("Couldn't get IDXGIOutput1 interface, hr 0x%x", (guint) hr);
|
||||||
|
@ -1469,6 +1448,15 @@ private:
|
||||||
};
|
};
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_D3D11_DEVICE,
|
||||||
|
PROP_MONITOR_HANDLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DEFAULT_MONITOR_INDEX -1
|
||||||
|
|
||||||
struct _GstD3D11DesktopDup
|
struct _GstD3D11DesktopDup
|
||||||
{
|
{
|
||||||
GstObject parent;
|
GstObject parent;
|
||||||
|
@ -1479,8 +1467,7 @@ struct _GstD3D11DesktopDup
|
||||||
|
|
||||||
D3D11DesktopDupObject *dupl_obj;
|
D3D11DesktopDupObject *dupl_obj;
|
||||||
|
|
||||||
gboolean primary;
|
HMONITOR monitor_handle;
|
||||||
gint monitor_index;
|
|
||||||
RECT desktop_coordinates;
|
RECT desktop_coordinates;
|
||||||
gboolean prepared;
|
gboolean prepared;
|
||||||
|
|
||||||
|
@ -1512,10 +1499,9 @@ gst_d3d11_desktop_dup_class_init (GstD3D11DesktopDupClass * klass)
|
||||||
GST_TYPE_D3D11_DEVICE, (GParamFlags)
|
GST_TYPE_D3D11_DEVICE, (GParamFlags)
|
||||||
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||||
G_PARAM_STATIC_STRINGS)));
|
G_PARAM_STATIC_STRINGS)));
|
||||||
g_object_class_install_property (gobject_class, PROP_OUTPUT_INDEX,
|
g_object_class_install_property (gobject_class, PROP_MONITOR_HANDLE,
|
||||||
g_param_spec_int ("monitor-index", "Monitor Index",
|
g_param_spec_pointer ("monitor-handle", "Monitor Handle",
|
||||||
"Zero-based index for monitor to capture (-1 = primary monitor)",
|
"A HMONITOR handle of monitor to capture", (GParamFlags)
|
||||||
-1, G_MAXINT, DEFAULT_MONITOR_INDEX, (GParamFlags)
|
|
||||||
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
(G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||||
G_PARAM_STATIC_STRINGS)));
|
G_PARAM_STATIC_STRINGS)));
|
||||||
}
|
}
|
||||||
|
@ -1523,122 +1509,99 @@ gst_d3d11_desktop_dup_class_init (GstD3D11DesktopDupClass * klass)
|
||||||
static void
|
static void
|
||||||
gst_d3d11_desktop_dup_init (GstD3D11DesktopDup * self)
|
gst_d3d11_desktop_dup_init (GstD3D11DesktopDup * self)
|
||||||
{
|
{
|
||||||
self->monitor_index = DEFAULT_MONITOR_INDEX;
|
|
||||||
g_rec_mutex_init (&self->lock);
|
g_rec_mutex_init (&self->lock);
|
||||||
|
|
||||||
memset (&self->desktop_coordinates, 0, sizeof (RECT));
|
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
|
static void
|
||||||
gst_d3d11_desktop_dup_constructed (GObject * object)
|
gst_d3d11_desktop_dup_constructed (GObject * object)
|
||||||
{
|
{
|
||||||
GstD3D11DesktopDup *self = GST_D3D11_DESKTOP_DUP (object);
|
GstD3D11DesktopDup *self = GST_D3D11_DESKTOP_DUP (object);
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
ComPtr<IDXGIDevice> dxgi_device;
|
ComPtr<IDXGIDevice> dxgi_device;
|
||||||
ComPtr<IDXGIAdapter> adapter;
|
ComPtr<IDXGIAdapter1> adapter;
|
||||||
ComPtr<IDXGIOutput> output;
|
ComPtr<IDXGIOutput> output;
|
||||||
ComPtr<IDXGIOutput1> output1;
|
ComPtr<IDXGIOutput1> output1;
|
||||||
/* *INDENT-ON* */
|
/* *INDENT-ON* */
|
||||||
ID3D11Device *device_handle;
|
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
gboolean ret = FALSE;
|
gboolean ret = FALSE;
|
||||||
DXGI_OUTPUT_DESC output_desc;
|
DXGI_OUTPUT_DESC output_desc;
|
||||||
|
DXGI_ADAPTER_DESC adapter_desc;
|
||||||
|
gint64 luid, device_luid;
|
||||||
|
|
||||||
if (!self->device) {
|
if (!self->device) {
|
||||||
GST_WARNING_OBJECT (self, "D3D11 device is unavailable");
|
GST_WARNING_OBJECT (self, "D3D11 device is unavailable");
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
device_handle = gst_d3d11_device_get_device_handle (self->device);
|
if (!self->monitor_handle) {
|
||||||
|
GST_WARNING_OBJECT (self, "Null monitor handle");
|
||||||
/* 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))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hr = dxgi_device->GetParent (IID_PPV_ARGS (&adapter));
|
|
||||||
if (!gst_d3d11_result (hr, self->device))
|
|
||||||
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));
|
hr = gst_d3d11_desktop_dup_find_output_for_monitor (self->monitor_handle,
|
||||||
} else {
|
&adapter, &output);
|
||||||
hr = adapter->EnumOutputs (self->monitor_index, &output);
|
|
||||||
if (!gst_d3d11_result (hr, self->device)) {
|
if (!gst_d3d11_result (hr, self->device)) {
|
||||||
GST_WARNING_OBJECT (self, "No available output");
|
GST_WARNING_OBJECT (self,
|
||||||
|
"Failed to find associated adapter for monitor %p",
|
||||||
|
self->monitor_handle);
|
||||||
goto out;
|
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);
|
hr = output.As (&output1);
|
||||||
if (!gst_d3d11_result (hr, self->device)) {
|
if (!gst_d3d11_result (hr, self->device)) {
|
||||||
GST_WARNING_OBJECT (self, "IDXGIOutput1 interface is unavailble");
|
GST_WARNING_OBJECT (self, "IDXGIOutput1 interface is unavailble");
|
||||||
goto out;
|
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
|
/* DesktopCoordinates will not report actual texture size in case that
|
||||||
* application is running without dpi-awareness. To get actual monitor size,
|
* application is running without dpi-awareness. To get actual monitor size,
|
||||||
* we need to use Win32 API... */
|
* we need to use Win32 API... */
|
||||||
if (!gst_d3d11_desktop_dup_get_monitor_size (self,
|
MONITORINFOEXW monitor_info;
|
||||||
output_desc.Monitor, &self->desktop_coordinates)) {
|
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;
|
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->cached_width =
|
||||||
self->desktop_coordinates.right - self->desktop_coordinates.left;
|
self->desktop_coordinates.right - self->desktop_coordinates.left;
|
||||||
self->cached_height =
|
self->cached_height =
|
||||||
|
@ -1655,6 +1618,8 @@ gst_d3d11_desktop_dup_constructed (GObject * object)
|
||||||
out:
|
out:
|
||||||
if (!ret)
|
if (!ret)
|
||||||
gst_clear_object (&self->device);
|
gst_clear_object (&self->device);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1667,8 +1632,8 @@ gst_d3d11_desktop_dup_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_D3D11_DEVICE:
|
case PROP_D3D11_DEVICE:
|
||||||
self->device = (GstD3D11Device *) g_value_dup_object (value);
|
self->device = (GstD3D11Device *) g_value_dup_object (value);
|
||||||
break;
|
break;
|
||||||
case PROP_OUTPUT_INDEX:
|
case PROP_MONITOR_HANDLE:
|
||||||
self->monitor_index = g_value_get_int (value);
|
self->monitor_handle = (HMONITOR) g_value_get_pointer (value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
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 *
|
GstD3D11DesktopDup *
|
||||||
gst_d3d11_desktop_dup_new (GstD3D11Device * device, gint monitor_index)
|
gst_d3d11_desktop_dup_new (GstD3D11Device * device, HMONITOR monitor_handle)
|
||||||
{
|
{
|
||||||
GstD3D11DesktopDup *self = nullptr;
|
GstD3D11DesktopDup *self = nullptr;
|
||||||
GList *iter;
|
GList *iter;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
|
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
|
/* Check if we have dup object corresponding to monitor_handle,
|
||||||
* already configured capture object, reuse it.
|
* and if there is already configured capture object, reuse it.
|
||||||
* This is because of the limitation of desktop duplication API
|
* This is because of the limitation of desktop duplication API
|
||||||
* (i.e., in a process, only one duplication object can exist).
|
* (i.e., in a process, only one duplication object can exist).
|
||||||
* See also
|
* 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)) {
|
for (iter = dupl_list; iter; iter = g_list_next (iter)) {
|
||||||
GstD3D11DesktopDup *dupl = (GstD3D11DesktopDup *) iter->data;
|
GstD3D11DesktopDup *dupl = (GstD3D11DesktopDup *) iter->data;
|
||||||
|
|
||||||
if (dupl->monitor_index == monitor_index ||
|
if (dupl->monitor_handle == monitor_handle) {
|
||||||
(monitor_index < 0 && dupl->primary)) {
|
GST_DEBUG ("Found configured desktop dup object for monitor handle %p",
|
||||||
GST_DEBUG ("Found configured desktop dup object for output index %d",
|
monitor_handle);
|
||||||
monitor_index);
|
|
||||||
self = (GstD3D11DesktopDup *) gst_object_ref (dupl);
|
self = (GstD3D11DesktopDup *) gst_object_ref (dupl);
|
||||||
break;
|
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,
|
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) {
|
if (!self->device) {
|
||||||
GST_WARNING_OBJECT (self, "Couldn't configure desktop dup object");
|
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 ();
|
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) {
|
if (ret != GST_FLOW_OK) {
|
||||||
GST_WARNING_OBJECT (desktop,
|
GST_WARNING_OBJECT (desktop,
|
||||||
"Couldn't prepare capturing, %sexpected failure",
|
"Couldn't prepare capturing, %sexpected failure",
|
||||||
|
@ -1885,3 +1849,154 @@ gst_d3d11_desktop_dup_capture (GstD3D11DesktopDup * desktop,
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ G_DECLARE_FINAL_TYPE (GstD3D11DesktopDup, gst_d3d11_desktop_dup,
|
||||||
GST, D3D11_DESKTOP_DUP, GstObject);
|
GST, D3D11_DESKTOP_DUP, GstObject);
|
||||||
|
|
||||||
GstD3D11DesktopDup * gst_d3d11_desktop_dup_new (GstD3D11Device * device,
|
GstD3D11DesktopDup * gst_d3d11_desktop_dup_new (GstD3D11Device * device,
|
||||||
gint output_index);
|
HMONITOR monitor_handle);
|
||||||
|
|
||||||
GstFlowReturn gst_d3d11_desktop_dup_prepare (GstD3D11DesktopDup * desktop);
|
GstFlowReturn gst_d3d11_desktop_dup_prepare (GstD3D11DesktopDup * desktop);
|
||||||
|
|
||||||
|
@ -49,6 +49,19 @@ GstFlowReturn gst_d3d11_desktop_dup_capture (GstD3D11DesktopDup * desktop,
|
||||||
ID3D11RenderTargetView *rtv,
|
ID3D11RenderTargetView *rtv,
|
||||||
gboolean draw_mouse);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __GST_D3D11_DESKTOP_DUP_H__ */
|
#endif /* __GST_D3D11_DESKTOP_DUP_H__ */
|
||||||
|
|
|
@ -0,0 +1,447 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||||
|
*
|
||||||
|
* 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 <gst/d3d11/gstd3d11.h>
|
||||||
|
#include <gst/video/video.h>
|
||||||
|
#include <wrl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <locale>
|
||||||
|
#include <codecvt>
|
||||||
|
|
||||||
|
/* *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 <seungha@centricular.com>");
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
|
||||||
|
*
|
||||||
|
* 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 <gst/gst.h>
|
||||||
|
|
||||||
|
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
|
||||||
|
|
|
@ -39,9 +39,13 @@
|
||||||
#include "gstd3d11desktopdupsrc.h"
|
#include "gstd3d11desktopdupsrc.h"
|
||||||
#include "gstd3d11desktopdup.h"
|
#include "gstd3d11desktopdup.h"
|
||||||
#include "gstd3d11pluginutils.h"
|
#include "gstd3d11pluginutils.h"
|
||||||
|
#include <wrl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
using namespace Microsoft::WRL;
|
||||||
|
/* *INDENT-ON* */
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_desktop_dup_debug);
|
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_desktop_dup_debug);
|
||||||
#define GST_CAT_DEFAULT gst_d3d11_desktop_dup_debug
|
#define GST_CAT_DEFAULT gst_d3d11_desktop_dup_debug
|
||||||
|
|
||||||
|
@ -49,6 +53,7 @@ enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_MONITOR_INDEX,
|
PROP_MONITOR_INDEX,
|
||||||
|
PROP_MONITOR_HANDLE,
|
||||||
PROP_SHOW_CURSOR,
|
PROP_SHOW_CURSOR,
|
||||||
|
|
||||||
PROP_LAST,
|
PROP_LAST,
|
||||||
|
@ -77,8 +82,9 @@ struct _GstD3D11DesktopDupSrc
|
||||||
|
|
||||||
GstBufferPool *pool;
|
GstBufferPool *pool;
|
||||||
|
|
||||||
gint adapter;
|
gint64 adapter_luid;
|
||||||
gint monitor_index;
|
gint monitor_index;
|
||||||
|
HMONITOR monitor_handle;
|
||||||
gboolean show_cursor;
|
gboolean show_cursor;
|
||||||
|
|
||||||
gboolean flushing;
|
gboolean flushing;
|
||||||
|
@ -138,6 +144,13 @@ gst_d3d11_desktop_dup_src_class_init (GstD3D11DesktopDupSrcClass * klass)
|
||||||
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
|
(GParamFlags) (G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
|
||||||
G_PARAM_STATIC_STRINGS));
|
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] =
|
properties[PROP_SHOW_CURSOR] =
|
||||||
g_param_spec_boolean ("show-cursor",
|
g_param_spec_boolean ("show-cursor",
|
||||||
"Show Mouse Cursor", "Whether to show mouse 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_live (GST_BASE_SRC (self), TRUE);
|
||||||
gst_base_src_set_format (GST_BASE_SRC (self), GST_FORMAT_TIME);
|
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->monitor_index = DEFAULT_MONITOR_INDEX;
|
||||||
self->show_cursor = DEFAULT_SHOW_CURSOR;
|
self->show_cursor = DEFAULT_SHOW_CURSOR;
|
||||||
self->min_latency = GST_CLOCK_TIME_NONE;
|
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:
|
case PROP_MONITOR_INDEX:
|
||||||
self->monitor_index = g_value_get_int (value);
|
self->monitor_index = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MONITOR_HANDLE:
|
||||||
|
self->monitor_handle = (HMONITOR) g_value_get_uint64 (value);
|
||||||
|
break;
|
||||||
case PROP_SHOW_CURSOR:
|
case PROP_SHOW_CURSOR:
|
||||||
self->show_cursor = g_value_get_boolean (value);
|
self->show_cursor = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
@ -231,6 +245,9 @@ gst_d3d11_desktop_dup_src_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_MONITOR_INDEX:
|
case PROP_MONITOR_INDEX:
|
||||||
g_value_set_int (value, self->monitor_index);
|
g_value_set_int (value, self->monitor_index);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MONITOR_HANDLE:
|
||||||
|
g_value_set_uint64 (value, (guint64) self->monitor_handle);
|
||||||
|
break;
|
||||||
case PROP_SHOW_CURSOR:
|
case PROP_SHOW_CURSOR:
|
||||||
g_value_set_boolean (value, self->show_cursor);
|
g_value_set_boolean (value, self->show_cursor);
|
||||||
break;
|
break;
|
||||||
|
@ -246,7 +263,8 @@ gst_d3d11_desktop_dup_src_set_context (GstElement * element,
|
||||||
{
|
{
|
||||||
GstD3D11DesktopDupSrc *self = GST_D3D11_DESKTOP_DUP_SRC (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);
|
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);
|
GstD3D11DesktopDupSrc *self = GST_D3D11_DESKTOP_DUP_SRC (bsrc);
|
||||||
GstFlowReturn ret;
|
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
|
if (monitor) {
|
||||||
* this might cause issue in case of multi-gpu environment and
|
hr = gst_d3d11_desktop_dup_find_output_for_monitor (monitor,
|
||||||
* some monitor is connected to non-default adapter */
|
&adapter, nullptr);
|
||||||
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), self->adapter,
|
} else if (self->monitor_index < 0) {
|
||||||
&self->device)) {
|
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,
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||||
("D3D11 device with adapter index %d is unavailble", self->adapter),
|
("D3D11 device for LUID %" G_GINT64_FORMAT " is unavailble",
|
||||||
(NULL));
|
self->adapter_luid), (nullptr));
|
||||||
|
|
||||||
return FALSE;
|
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)
|
if (!self->dupl)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
|
@ -524,16 +564,18 @@ gst_d3d11_desktop_dup_src_start (GstBaseSrc * bsrc)
|
||||||
error:
|
error:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||||
("Failed to prepare duplication for output index %d",
|
("Failed to prepare duplication with given configuration, "
|
||||||
self->monitor_index), (NULL));
|
"monitor-index: %d, monitor-handle: %p",
|
||||||
}
|
self->monitor_index, self->monitor_handle), (nullptr));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
unsupported:
|
unsupported:
|
||||||
{
|
{
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
|
GST_ELEMENT_ERROR (self, RESOURCE, OPEN_READ,
|
||||||
("Failed to prepare duplication for output index %d",
|
("Failed to prepare duplication with given configuration, "
|
||||||
self->monitor_index),
|
"monitor-index: %d, monitor-handle: %p",
|
||||||
|
self->monitor_index, self->monitor_handle),
|
||||||
("Try run the application on the integrated GPU"));
|
("Try run the application on the integrated GPU"));
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,9 @@ if d3d11_winapi_desktop
|
||||||
# Desktop Duplication API is unavailable for UWP
|
# Desktop Duplication API is unavailable for UWP
|
||||||
# and MinGW is not supported due to some missing headers
|
# and MinGW is not supported due to some missing headers
|
||||||
extra_args += ['-DHAVE_DXGI_DESKTOP_DUP']
|
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')
|
message('Enable D3D11 Desktop Duplication API')
|
||||||
endif
|
endif
|
||||||
# multimedia clock is desktop only API
|
# multimedia clock is desktop only API
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_DXGI_DESKTOP_DUP
|
#ifdef HAVE_DXGI_DESKTOP_DUP
|
||||||
#include "gstd3d11desktopdupsrc.h"
|
#include "gstd3d11desktopdupsrc.h"
|
||||||
|
#include "gstd3d11desktopdupdevice.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_D3D11_VIDEO_PROC
|
#ifdef HAVE_D3D11_VIDEO_PROC
|
||||||
#include "gstd3d11deinterlace.h"
|
#include "gstd3d11deinterlace.h"
|
||||||
|
@ -68,6 +69,7 @@ GST_DEBUG_CATEGORY (gst_d3d11_av1_dec_debug);
|
||||||
|
|
||||||
#ifdef HAVE_DXGI_DESKTOP_DUP
|
#ifdef HAVE_DXGI_DESKTOP_DUP
|
||||||
GST_DEBUG_CATEGORY (gst_d3d11_desktop_dup_debug);
|
GST_DEBUG_CATEGORY (gst_d3d11_desktop_dup_debug);
|
||||||
|
GST_DEBUG_CATEGORY (gst_d3d11_desktop_dup_device_debug);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_D3D11_VIDEO_PROC
|
#ifdef HAVE_D3D11_VIDEO_PROC
|
||||||
|
@ -213,8 +215,14 @@ plugin_init (GstPlugin * plugin)
|
||||||
if (gst_d3d11_is_windows_8_or_greater ()) {
|
if (gst_d3d11_is_windows_8_or_greater ()) {
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_d3d11_desktop_dup_debug,
|
GST_DEBUG_CATEGORY_INIT (gst_d3d11_desktop_dup_debug,
|
||||||
"d3d11desktopdupsrc", 0, "d3d11desktopdupsrc");
|
"d3d11desktopdupsrc", 0, "d3d11desktopdupsrc");
|
||||||
|
GST_DEBUG_CATEGORY_INIT (gst_d3d11_desktop_dup_device_debug,
|
||||||
|
"d3d11desktopdupdevice", 0, "d3d11desktopdupdevice");
|
||||||
|
|
||||||
gst_element_register (plugin,
|
gst_element_register (plugin,
|
||||||
"d3d11desktopdupsrc", GST_RANK_NONE, GST_TYPE_D3D11_DESKTOP_DUP_SRC);
|
"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
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue