mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-23 16:50:47 +00:00
d3d11: Add support for Universal Windows Platform
Initial UWP support via new window (CoreWindow and SwapChainPanel) implementation.
This commit is contained in:
parent
43a8eb9e92
commit
e4daa2ef43
16 changed files with 3184 additions and 1718 deletions
|
@ -21,7 +21,7 @@
|
|||
#define __GST_D3D11_FWD_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "d3d11config.h"
|
||||
#include "gstd3d11config.h"
|
||||
|
||||
#ifndef INITGUID
|
||||
#include <initguid.h>
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "d3d11config.h"
|
||||
|
||||
#include "gstd3d11device.h"
|
||||
#include "gstd3d11utils.h"
|
||||
#include "gmodule.h"
|
||||
|
@ -200,20 +198,39 @@ static gboolean
|
|||
gst_d3d11_device_enable_dxgi_debug (void)
|
||||
{
|
||||
static volatile gsize _init = 0;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
/* If all below libraries are unavailable, d3d11 device would fail with
|
||||
* D3D11_CREATE_DEVICE_DEBUG flag */
|
||||
if (g_once_init_enter (&_init)) {
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
dxgi_debug_module = g_module_open ("dxgidebug.dll", G_MODULE_BIND_LAZY);
|
||||
|
||||
if (dxgi_debug_module)
|
||||
g_module_symbol (dxgi_debug_module,
|
||||
"DXGIGetDebugInterface", (gpointer *) & GstDXGIGetDebugInterface);
|
||||
|
||||
ret = ! !GstDXGIGetDebugInterface;
|
||||
#elif (DXGI_HEADER_VERSION >= 3)
|
||||
ret = TRUE;
|
||||
#endif
|
||||
g_once_init_leave (&_init, 1);
|
||||
}
|
||||
|
||||
return ! !GstDXGIGetDebugInterface;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
gst_d3d11_device_dxgi_get_device_interface (REFIID riid, void **debug)
|
||||
{
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
if (GstDXGIGetDebugInterface) {
|
||||
return GstDXGIGetDebugInterface (riid, debug);
|
||||
}
|
||||
#elif (DXGI_HEADER_VERSION >= 3)
|
||||
return DXGIGetDebugInterface1 (0, riid, debug);
|
||||
#endif
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static inline GstDebugLevel
|
||||
|
@ -374,14 +391,15 @@ gst_d3d11_device_constructed (GObject * object)
|
|||
|
||||
GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
|
||||
"dxgi debug library was loaded");
|
||||
hr = GstDXGIGetDebugInterface (&IID_IDXGIDebug, (void **) &debug);
|
||||
hr = gst_d3d11_device_dxgi_get_device_interface (&IID_IDXGIDebug,
|
||||
(void **) &debug);
|
||||
|
||||
if (SUCCEEDED (hr)) {
|
||||
GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
|
||||
"IDXGIDebug interface available");
|
||||
priv->dxgi_debug = debug;
|
||||
|
||||
hr = GstDXGIGetDebugInterface (&IID_IDXGIInfoQueue,
|
||||
hr = gst_d3d11_device_dxgi_get_device_interface (&IID_IDXGIInfoQueue,
|
||||
(void **) &info_queue);
|
||||
if (SUCCEEDED (hr)) {
|
||||
GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
|
||||
|
@ -762,7 +780,7 @@ gst_d3d11_device_create_swap_chain (GstD3D11Device * device,
|
|||
gst_d3d11_device_unlock (device);
|
||||
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
|
||||
GST_WARNING_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
|
||||
(guint) hr);
|
||||
swap_chain = NULL;
|
||||
}
|
||||
|
@ -771,6 +789,7 @@ gst_d3d11_device_create_swap_chain (GstD3D11Device * device,
|
|||
}
|
||||
|
||||
#if (DXGI_HEADER_VERSION >= 2)
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
/**
|
||||
* gst_d3d11_device_create_swap_chain_for_hwnd:
|
||||
* @device: a #GstD3D11Device
|
||||
|
@ -807,14 +826,96 @@ gst_d3d11_device_create_swap_chain_for_hwnd (GstD3D11Device * device,
|
|||
gst_d3d11_device_unlock (device);
|
||||
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
|
||||
GST_WARNING_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
|
||||
(guint) hr);
|
||||
swap_chain = NULL;
|
||||
}
|
||||
|
||||
return swap_chain;
|
||||
}
|
||||
#endif
|
||||
#endif /* GST_D3D11_WINAPI_ONLY_APP */
|
||||
|
||||
#if GST_D3D11_WINAPI_ONLY_APP
|
||||
/**
|
||||
* gst_d3d11_device_create_swap_chain_for_core_window:
|
||||
* @device: a #GstD3D11Device
|
||||
* @core_window: CoreWindow handle
|
||||
* @desc: a DXGI_SWAP_CHAIN_DESC1 structure for swapchain
|
||||
* @output: (nullable): a IDXGIOutput interface for the output to restrict content to
|
||||
*
|
||||
* Create a IDXGISwapChain1 object. Caller must release returned swap chain object
|
||||
* via IDXGISwapChain1_Release()
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a new IDXGISwapChain1 or %NULL
|
||||
* when failed to create swap chain with given @desc
|
||||
*/
|
||||
IDXGISwapChain1 *
|
||||
gst_d3d11_device_create_swap_chain_for_core_window (GstD3D11Device * device,
|
||||
guintptr core_window, const DXGI_SWAP_CHAIN_DESC1 * desc,
|
||||
IDXGIOutput * output)
|
||||
{
|
||||
GstD3D11DevicePrivate *priv;
|
||||
IDXGISwapChain1 *swap_chain = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
|
||||
|
||||
priv = device->priv;
|
||||
|
||||
gst_d3d11_device_lock (device);
|
||||
hr = IDXGIFactory2_CreateSwapChainForCoreWindow ((IDXGIFactory2 *)
|
||||
priv->factory, (IUnknown *) priv->device, (IUnknown *) core_window, desc,
|
||||
output, &swap_chain);
|
||||
gst_d3d11_device_unlock (device);
|
||||
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_WARNING_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
|
||||
(guint) hr);
|
||||
swap_chain = NULL;
|
||||
}
|
||||
|
||||
return swap_chain;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_d3d11_device_create_swap_chain_for_composition:
|
||||
* @device: a #GstD3D11Device
|
||||
* @desc: a DXGI_SWAP_CHAIN_DESC1 structure for swapchain
|
||||
* @output: (nullable): a IDXGIOutput interface for the output to restrict content to
|
||||
*
|
||||
* Create a IDXGISwapChain1 object. Caller must release returned swap chain object
|
||||
* via IDXGISwapChain1_Release()
|
||||
*
|
||||
* Returns: (transfer full) (nullable): a new IDXGISwapChain1 or %NULL
|
||||
* when failed to create swap chain with given @desc
|
||||
*/
|
||||
IDXGISwapChain1 *
|
||||
gst_d3d11_device_create_swap_chain_for_composition (GstD3D11Device * device,
|
||||
const DXGI_SWAP_CHAIN_DESC1 * desc, IDXGIOutput * output)
|
||||
{
|
||||
GstD3D11DevicePrivate *priv;
|
||||
IDXGISwapChain1 *swap_chain = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
|
||||
|
||||
priv = device->priv;
|
||||
|
||||
gst_d3d11_device_lock (device);
|
||||
hr = IDXGIFactory2_CreateSwapChainForComposition ((IDXGIFactory2 *)
|
||||
priv->factory, (IUnknown *) priv->device, desc, output, &swap_chain);
|
||||
gst_d3d11_device_unlock (device);
|
||||
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_WARNING_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
|
||||
(guint) hr);
|
||||
swap_chain = NULL;
|
||||
}
|
||||
|
||||
return swap_chain;
|
||||
}
|
||||
#endif /* GST_D3D11_WINAPI_ONLY_APP */
|
||||
#endif /* (DXGI_HEADER_VERSION >= 2) */
|
||||
|
||||
/**
|
||||
* gst_d3d11_device_release_swap_chain:
|
||||
|
|
|
@ -91,6 +91,7 @@ IDXGISwapChain * gst_d3d11_device_create_swap_chain (GstD3D11Device * devi
|
|||
const DXGI_SWAP_CHAIN_DESC * desc);
|
||||
|
||||
#if (DXGI_HEADER_VERSION >= 2)
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
IDXGISwapChain1 * gst_d3d11_device_create_swap_chain_for_hwnd (GstD3D11Device * device,
|
||||
HWND hwnd,
|
||||
const DXGI_SWAP_CHAIN_DESC1 * desc,
|
||||
|
@ -98,6 +99,19 @@ IDXGISwapChain1 * gst_d3d11_device_create_swap_chain_for_hwnd (GstD3D11Devic
|
|||
IDXGIOutput * output);
|
||||
#endif
|
||||
|
||||
#if GST_D3D11_WINAPI_ONLY_APP
|
||||
IDXGISwapChain1 * gst_d3d11_device_create_swap_chain_for_core_window (GstD3D11Device * device,
|
||||
guintptr core_window,
|
||||
const DXGI_SWAP_CHAIN_DESC1 * desc,
|
||||
IDXGIOutput * output);
|
||||
|
||||
IDXGISwapChain1 * gst_d3d11_device_create_swap_chain_for_composition (GstD3D11Device * device,
|
||||
const DXGI_SWAP_CHAIN_DESC1 * desc,
|
||||
IDXGIOutput * output);
|
||||
|
||||
#endif /* GST_D3D11_WINAPI_ONLY_APP */
|
||||
#endif /* (DXGI_HEADER_VERSION >= 2) */
|
||||
|
||||
void gst_d3d11_device_release_swap_chain (GstD3D11Device * device,
|
||||
IDXGISwapChain * swap_chain);
|
||||
|
||||
|
|
|
@ -21,8 +21,6 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "d3d11config.h"
|
||||
|
||||
#include "gstd3d11utils.h"
|
||||
#include "gstd3d11device.h"
|
||||
|
||||
|
@ -331,8 +329,12 @@ gst_d3d11_is_windows_8_or_greater (void)
|
|||
static gboolean ret = FALSE;
|
||||
|
||||
if (g_once_init_enter (&version_once)) {
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
if (IsWindows8OrGreater ())
|
||||
ret = TRUE;
|
||||
#else
|
||||
ret = TRUE;
|
||||
#endif
|
||||
|
||||
g_once_init_leave (&version_once, 1);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,13 @@
|
|||
#include "gstd3d11bufferpool.h"
|
||||
#include "gstd3d11format.h"
|
||||
|
||||
#if GST_D3D11_WINAPI_ONLY_APP
|
||||
#include "gstd3d11window_corewindow.h"
|
||||
#include "gstd3d11window_swapchainpanel.h"
|
||||
#else
|
||||
#include "gstd3d11window_win32.h"
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
|
@ -82,6 +89,7 @@ static gboolean gst_d3d11_video_sink_propose_allocation (GstBaseSink * sink,
|
|||
static gboolean gst_d3d11_video_sink_query (GstBaseSink * sink,
|
||||
GstQuery * query);
|
||||
static gboolean gst_d3d11_video_sink_unlock (GstBaseSink * sink);
|
||||
static gboolean gst_d3d11_video_sink_unlock_stop (GstBaseSink * sink);
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d11_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf);
|
||||
|
@ -159,6 +167,8 @@ gst_d3d11_video_sink_class_init (GstD3D11VideoSinkClass * klass)
|
|||
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_propose_allocation);
|
||||
basesink_class->query = GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_query);
|
||||
basesink_class->unlock = GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_unlock);
|
||||
basesink_class->unlock_stop =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_unlock_stop);
|
||||
|
||||
videosink_class->show_frame =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_show_frame);
|
||||
|
@ -362,15 +372,6 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
|
|||
if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0)
|
||||
goto no_display_size;
|
||||
|
||||
if (!self->window_id)
|
||||
gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (self));
|
||||
|
||||
if (self->window_id) {
|
||||
GST_DEBUG_OBJECT (self, "Set external window %" G_GUINTPTR_FORMAT,
|
||||
(guintptr) self->window_id);
|
||||
gst_d3d11_window_set_window_handle (self->window, self->window_id);
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
if (!self->pending_render_rect) {
|
||||
self->render_rect.x = 0;
|
||||
|
@ -383,12 +384,6 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
|
|||
self->render_rect.x, self->render_rect.y, self->render_rect.w,
|
||||
self->render_rect.h);
|
||||
self->pending_render_rect = FALSE;
|
||||
|
||||
g_object_set (self->window,
|
||||
"force-aspect-ratio", self->force_aspect_ratio,
|
||||
"fullscreen-toggle-mode", self->fullscreen_toggle_mode,
|
||||
"fullscreen", self->fullscreen, NULL);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
if (!gst_d3d11_window_prepare (self->window, GST_VIDEO_SINK_WIDTH (self),
|
||||
|
@ -484,21 +479,12 @@ gst_d3d11_video_mouse_key_event (GstD3D11Window * window, const gchar * event,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_video_sink_got_window_handle (GstD3D11Window * window,
|
||||
gpointer window_handle, GstD3D11VideoSink * self)
|
||||
{
|
||||
GST_LOG_OBJECT (self,
|
||||
"got window handle %" G_GUINTPTR_FORMAT, (guintptr) window_handle);
|
||||
gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (self),
|
||||
(guintptr) window_handle);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_video_sink_start (GstBaseSink * sink)
|
||||
{
|
||||
GstD3D11VideoSink *self = GST_D3D11_VIDEO_SINK (sink);
|
||||
gboolean is_hardware = TRUE;
|
||||
GstD3D11WindowNativeType window_type = GST_D3D11_WINDOW_NATIVE_TYPE_HWND;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Start");
|
||||
|
||||
|
@ -508,12 +494,67 @@ gst_d3d11_video_sink_start (GstBaseSink * sink)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
self->window = gst_d3d11_window_new (self->device);
|
||||
if (!self->window_id)
|
||||
gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (self));
|
||||
|
||||
if (self->window_id) {
|
||||
window_type =
|
||||
gst_d3d11_window_get_native_type_from_handle (self->window_id);
|
||||
|
||||
if (window_type != GST_D3D11_WINDOW_NATIVE_TYPE_NONE) {
|
||||
gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (self),
|
||||
self->window_id);
|
||||
}
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Create window (type: %s)",
|
||||
gst_d3d11_window_get_native_type_to_string (window_type));
|
||||
|
||||
#if GST_D3D11_WINAPI_ONLY_APP
|
||||
if (window_type != GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW &&
|
||||
window_type != GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL) {
|
||||
GST_ERROR_OBJECT (sink, "Overlay handle must be set before READY state");
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (window_type) {
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_HWND:
|
||||
self->window = gst_d3d11_window_win32_new (self->device, self->window_id);
|
||||
break;
|
||||
#else
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW:
|
||||
self->window = gst_d3d11_window_core_window_new (self->device,
|
||||
self->window_id);
|
||||
break;
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL:
|
||||
self->window = gst_d3d11_window_swap_chain_panel_new (self->device,
|
||||
self->window_id);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!self->window) {
|
||||
GST_ERROR_OBJECT (sink, "Cannot create d3d11window");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
g_object_set (self->window,
|
||||
"force-aspect-ratio", self->force_aspect_ratio,
|
||||
"fullscreen-toggle-mode", self->fullscreen_toggle_mode,
|
||||
"fullscreen", self->fullscreen,
|
||||
"enable-navigation-events", self->enable_navigation_events, NULL);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
g_signal_connect (self->window, "key-event",
|
||||
G_CALLBACK (gst_d3d11_video_sink_key_event), self);
|
||||
g_signal_connect (self->window, "mouse-event",
|
||||
G_CALLBACK (gst_d3d11_video_mouse_key_event), self);
|
||||
|
||||
g_object_get (self->device, "hardware", &is_hardware, NULL);
|
||||
|
||||
if (!is_hardware) {
|
||||
|
@ -523,16 +564,6 @@ gst_d3d11_video_sink_start (GstBaseSink * sink)
|
|||
self->can_convert = TRUE;
|
||||
}
|
||||
|
||||
g_object_set (self->window,
|
||||
"enable-navigation-events", self->enable_navigation_events, NULL);
|
||||
|
||||
g_signal_connect (self->window, "key-event",
|
||||
G_CALLBACK (gst_d3d11_video_sink_key_event), self);
|
||||
g_signal_connect (self->window, "mouse-event",
|
||||
G_CALLBACK (gst_d3d11_video_mouse_key_event), self);
|
||||
g_signal_connect (self->window, "got-window-handle",
|
||||
G_CALLBACK (gst_d3d11_video_sink_got_window_handle), self);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -688,7 +719,18 @@ gst_d3d11_video_sink_unlock (GstBaseSink * sink)
|
|||
GstD3D11VideoSink *self = GST_D3D11_VIDEO_SINK (sink);
|
||||
|
||||
if (self->window)
|
||||
gst_d3d11_window_flush (self->window);
|
||||
gst_d3d11_window_unlock (self->window);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_video_sink_unlock_stop (GstBaseSink * sink)
|
||||
{
|
||||
GstD3D11VideoSink *self = GST_D3D11_VIDEO_SINK (sink);
|
||||
|
||||
if (self->window)
|
||||
gst_d3d11_window_unlock_stop (self->window);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
940
sys/d3d11/gstd3d11window.cpp
Normal file
940
sys/d3d11/gstd3d11window.cpp
Normal file
|
@ -0,0 +1,940 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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 "gstd3d11window.h"
|
||||
#include "gstd3d11device.h"
|
||||
#include "gstd3d11memory.h"
|
||||
#include "gstd3d11utils.h"
|
||||
|
||||
#if GST_D3D11_WINAPI_ONLY_APP
|
||||
/* workaround for GetCurrentTime collision */
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
#include <windows.ui.xaml.h>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
|
||||
#define GST_CAT_DEFAULT gst_d3d11_window_debug
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_D3D11_DEVICE,
|
||||
PROP_FORCE_ASPECT_RATIO,
|
||||
PROP_ENABLE_NAVIGATION_EVENTS,
|
||||
PROP_FULLSCREEN_TOGGLE_MODE,
|
||||
PROP_FULLSCREEN,
|
||||
PROP_WINDOW_HANDLE,
|
||||
};
|
||||
|
||||
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
|
||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
|
||||
#define DEFAULT_FULLSCREEN FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_KEY_EVENT,
|
||||
SIGNAL_MOUSE_EVENT,
|
||||
SIGNAL_LAST
|
||||
};
|
||||
|
||||
static guint d3d11_window_signals[SIGNAL_LAST] = { 0, };
|
||||
|
||||
GType
|
||||
gst_d3d11_window_fullscreen_toggle_mode_type (void)
|
||||
{
|
||||
static volatile gsize mode_type = 0;
|
||||
|
||||
if (g_once_init_enter (&mode_type)) {
|
||||
static const GFlagsValue mode_types[] = {
|
||||
{GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE,
|
||||
"GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE", "none"},
|
||||
{GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER,
|
||||
"GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER", "alt-enter"},
|
||||
{GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY,
|
||||
"GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY", "property"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
GType tmp = g_flags_register_static ("GstD3D11WindowFullscreenToggleMode",
|
||||
mode_types);
|
||||
g_once_init_leave (&mode_type, tmp);
|
||||
}
|
||||
|
||||
return (GType) mode_type;
|
||||
}
|
||||
|
||||
#define gst_d3d11_window_parent_class parent_class
|
||||
G_DEFINE_ABSTRACT_TYPE (GstD3D11Window, gst_d3d11_window, GST_TYPE_OBJECT);
|
||||
|
||||
static void gst_d3d11_window_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
static void gst_d3d11_window_dispose (GObject * object);
|
||||
static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
|
||||
GstBuffer * buffer);
|
||||
|
||||
static void
|
||||
gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gst_d3d11_window_set_property;
|
||||
gobject_class->get_property = gst_d3d11_window_get_property;
|
||||
gobject_class->dispose = gst_d3d11_window_dispose;
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_D3D11_DEVICE,
|
||||
g_param_spec_object ("d3d11device", "D3D11 Device",
|
||||
"GstD3D11Device object for creating swapchain",
|
||||
GST_TYPE_D3D11_DEVICE,
|
||||
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
|
||||
g_param_spec_boolean ("force-aspect-ratio",
|
||||
"Force aspect ratio",
|
||||
"When enabled, scaling will respect original aspect ratio",
|
||||
DEFAULT_FORCE_ASPECT_RATIO,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_ENABLE_NAVIGATION_EVENTS,
|
||||
g_param_spec_boolean ("enable-navigation-events",
|
||||
"Enable navigation events",
|
||||
"When enabled, signals for navigation events are emitted",
|
||||
DEFAULT_ENABLE_NAVIGATION_EVENTS,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FULLSCREEN_TOGGLE_MODE,
|
||||
g_param_spec_flags ("fullscreen-toggle-mode",
|
||||
"Full screen toggle mode",
|
||||
"Full screen toggle mode used to trigger fullscreen mode change",
|
||||
GST_D3D11_WINDOW_TOGGLE_MODE_GET_TYPE, DEFAULT_FULLSCREEN_TOGGLE_MODE,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_FULLSCREEN,
|
||||
g_param_spec_boolean ("fullscreen",
|
||||
"fullscreen",
|
||||
"Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
|
||||
DEFAULT_FULLSCREEN,
|
||||
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_WINDOW_HANDLE,
|
||||
g_param_spec_pointer ("window-handle",
|
||||
"Window Handle", "External Window Handle",
|
||||
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
d3d11_window_signals[SIGNAL_KEY_EVENT] =
|
||||
g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
|
||||
|
||||
d3d11_window_signals[SIGNAL_MOUSE_EVENT] =
|
||||
g_signal_new ("mouse-event", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_init (GstD3D11Window * self)
|
||||
{
|
||||
self->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
|
||||
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
|
||||
self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE;
|
||||
self->fullscreen = DEFAULT_FULLSCREEN;
|
||||
|
||||
self->aspect_ratio_n = 1;
|
||||
self->aspect_ratio_d = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstD3D11Window *self = GST_D3D11_WINDOW (object);
|
||||
GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_D3D11_DEVICE:
|
||||
self->device = (GstD3D11Device *) g_value_dup_object (value);
|
||||
break;
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
{
|
||||
self->force_aspect_ratio = g_value_get_boolean (value);
|
||||
if (self->swap_chain)
|
||||
klass->update_swap_chain (self);
|
||||
break;
|
||||
}
|
||||
case PROP_ENABLE_NAVIGATION_EVENTS:
|
||||
self->enable_navigation_events = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_FULLSCREEN_TOGGLE_MODE:
|
||||
self->fullscreen_toggle_mode =
|
||||
(GstD3D11WindowFullscreenToggleMode) g_value_get_flags (value);
|
||||
break;
|
||||
case PROP_FULLSCREEN:
|
||||
{
|
||||
self->requested_fullscreen = g_value_get_boolean (value);
|
||||
if (self->swap_chain)
|
||||
klass->change_fullscreen_mode (self);
|
||||
break;
|
||||
}
|
||||
case PROP_WINDOW_HANDLE:
|
||||
self->external_handle = (guintptr) g_value_get_pointer (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstD3D11Window *self = GST_D3D11_WINDOW (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ENABLE_NAVIGATION_EVENTS:
|
||||
g_value_set_boolean (value, self->enable_navigation_events);
|
||||
break;
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
g_value_set_boolean (value, self->force_aspect_ratio);
|
||||
break;
|
||||
case PROP_FULLSCREEN_TOGGLE_MODE:
|
||||
g_value_set_flags (value, self->fullscreen_toggle_mode);
|
||||
break;
|
||||
case PROP_FULLSCREEN:
|
||||
g_value_set_boolean (value, self->fullscreen);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_release_resources (GstD3D11Device * device,
|
||||
GstD3D11Window * window)
|
||||
{
|
||||
if (window->rtv) {
|
||||
window->rtv->Release ();
|
||||
window->rtv = NULL;
|
||||
}
|
||||
|
||||
if (window->swap_chain) {
|
||||
window->swap_chain->Release ();
|
||||
window->swap_chain = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_dispose (GObject * object)
|
||||
{
|
||||
GstD3D11Window *self = GST_D3D11_WINDOW (object);
|
||||
|
||||
if (self->device) {
|
||||
gst_d3d11_window_release_resources (self->device, self);
|
||||
}
|
||||
|
||||
if (self->converter) {
|
||||
gst_d3d11_color_converter_free (self->converter);
|
||||
self->converter = NULL;
|
||||
}
|
||||
|
||||
if (self->compositor) {
|
||||
gst_d3d11_overlay_compositor_free (self->compositor);
|
||||
self->compositor = NULL;
|
||||
}
|
||||
|
||||
gst_clear_buffer (&self->cached_buffer);
|
||||
gst_clear_object (&self->device);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d11_window_on_resize (GstD3D11Window * window, guint width, guint height)
|
||||
{
|
||||
HRESULT hr;
|
||||
ID3D11Device *device_handle;
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
DXGI_SWAP_CHAIN_DESC swap_desc;
|
||||
ID3D11Texture2D *backbuffer = NULL;
|
||||
GstVideoRectangle src_rect, dst_rect, rst_rect;
|
||||
IDXGISwapChain *swap_chain;
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
if (!window->swap_chain)
|
||||
goto done;
|
||||
|
||||
device_handle = gst_d3d11_device_get_device_handle (window->device);
|
||||
swap_chain = window->swap_chain;
|
||||
|
||||
if (window->rtv) {
|
||||
window->rtv->Release ();
|
||||
window->rtv = NULL;
|
||||
}
|
||||
|
||||
/* Set zero width and height here. dxgi will decide client area by itself */
|
||||
swap_chain->GetDesc (&swap_desc);
|
||||
hr = swap_chain->ResizeBuffers (0, width, height, DXGI_FORMAT_UNKNOWN,
|
||||
swap_desc.Flags);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (window, "Couldn't resize buffers, hr: 0x%x", (guint) hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
hr = swap_chain->GetBuffer (0, IID_ID3D11Texture2D, (void **) &backbuffer);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (window,
|
||||
"Cannot get backbuffer from swapchain, hr: 0x%x", (guint) hr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
backbuffer->GetDesc (&desc);
|
||||
window->surface_width = desc.Width;
|
||||
window->surface_height = desc.Height;
|
||||
|
||||
width = window->width;
|
||||
height = window->height;
|
||||
|
||||
{
|
||||
src_rect.x = 0;
|
||||
src_rect.y = 0;
|
||||
src_rect.w = width * window->aspect_ratio_n;
|
||||
src_rect.h = height * window->aspect_ratio_d;
|
||||
|
||||
dst_rect.x = 0;
|
||||
dst_rect.y = 0;
|
||||
dst_rect.w = window->surface_width;
|
||||
dst_rect.h = window->surface_height;
|
||||
|
||||
if (window->force_aspect_ratio) {
|
||||
src_rect.w = width * window->aspect_ratio_n;
|
||||
src_rect.h = height * window->aspect_ratio_d;
|
||||
|
||||
gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE);
|
||||
} else {
|
||||
rst_rect = dst_rect;
|
||||
}
|
||||
}
|
||||
|
||||
window->render_rect.left = rst_rect.x;
|
||||
window->render_rect.top = rst_rect.y;
|
||||
window->render_rect.right = rst_rect.x + rst_rect.w;
|
||||
window->render_rect.bottom = rst_rect.y + rst_rect.h;
|
||||
|
||||
GST_LOG_OBJECT (window,
|
||||
"New client area %dx%d, render rect x: %d, y: %d, %dx%d",
|
||||
desc.Width, desc.Height, rst_rect.x, rst_rect.y, rst_rect.w, rst_rect.h);
|
||||
|
||||
hr = device_handle->CreateRenderTargetView ((ID3D11Resource *) backbuffer,
|
||||
NULL, &window->rtv);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_ERROR_OBJECT (window, "Cannot create render target view, hr: 0x%x",
|
||||
(guint) hr);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
window->first_present = TRUE;
|
||||
|
||||
/* redraw the last scene if cached buffer exits */
|
||||
gst_d3d111_window_present (window, NULL);
|
||||
|
||||
done:
|
||||
if (backbuffer)
|
||||
backbuffer->Release ();
|
||||
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d11_window_on_key_event (GstD3D11Window * window, const gchar * event,
|
||||
const gchar * key)
|
||||
{
|
||||
g_return_if_fail (GST_IS_D3D11_WINDOW (window));
|
||||
|
||||
if (!window->enable_navigation_events)
|
||||
return;
|
||||
|
||||
g_signal_emit (window, d3d11_window_signals[SIGNAL_KEY_EVENT], 0, event, key);
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d11_window_on_mouse_event (GstD3D11Window * window, const gchar * event,
|
||||
gint button, gdouble x, gdouble y)
|
||||
{
|
||||
g_return_if_fail (GST_IS_D3D11_WINDOW (window));
|
||||
|
||||
if (!window->enable_navigation_events)
|
||||
return;
|
||||
|
||||
g_signal_emit (window, d3d11_window_signals[SIGNAL_MOUSE_EVENT], 0,
|
||||
event, button, x, y);
|
||||
}
|
||||
|
||||
#if (DXGI_HEADER_VERSION >= 5)
|
||||
static inline UINT16
|
||||
fraction_to_uint (guint num, guint den, guint scale)
|
||||
{
|
||||
gdouble val;
|
||||
gst_util_fraction_to_double (num, den, &val);
|
||||
|
||||
return (UINT16) val *scale;
|
||||
}
|
||||
|
||||
static void
|
||||
mastering_display_gst_to_dxgi (GstVideoMasteringDisplayInfo * m,
|
||||
GstVideoContentLightLevel * c, DXGI_HDR_METADATA_HDR10 * meta)
|
||||
{
|
||||
meta->RedPrimary[0] = fraction_to_uint (m->Rx_n, m->Rx_d, 50000);
|
||||
meta->RedPrimary[1] = fraction_to_uint (m->Ry_n, m->Ry_d, 50000);
|
||||
meta->GreenPrimary[0] = fraction_to_uint (m->Gx_n, m->Gx_d, 50000);
|
||||
meta->GreenPrimary[1] = fraction_to_uint (m->Gy_n, m->Gy_d, 50000);
|
||||
meta->BluePrimary[0] = fraction_to_uint (m->Bx_n, m->Bx_d, 50000);
|
||||
meta->BluePrimary[1] = fraction_to_uint (m->By_n, m->By_d, 50000);
|
||||
meta->WhitePoint[0] = fraction_to_uint (m->Wx_n, m->Wx_d, 50000);
|
||||
meta->WhitePoint[1] = fraction_to_uint (m->Wy_n, m->Wy_d, 50000);
|
||||
meta->MaxMasteringLuminance =
|
||||
fraction_to_uint (m->max_luma_n, m->max_luma_d, 1);
|
||||
meta->MinMasteringLuminance =
|
||||
fraction_to_uint (m->min_luma_n, m->min_luma_d, 1);
|
||||
meta->MaxContentLightLevel = fraction_to_uint (c->maxCLL_n, c->maxCLL_d, 1);
|
||||
meta->MaxFrameAverageLightLevel =
|
||||
fraction_to_uint (c->maxFALL_n, c->maxFALL_d, 1);
|
||||
}
|
||||
|
||||
/* missing in mingw header... */
|
||||
typedef enum
|
||||
{
|
||||
GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 = 0,
|
||||
GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709 = 1,
|
||||
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709 = 2,
|
||||
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020 = 3,
|
||||
GST_DXGI_COLOR_SPACE_RESERVED = 4,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_NONE_P709_X601 = 5,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601 = 6,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601 = 7,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709 = 8,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709 = 9,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P2020 = 10,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P2020 = 11,
|
||||
GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 = 12,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020 = 13,
|
||||
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020 = 14,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_TOPLEFT_P2020 = 15,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020 = 16,
|
||||
GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020 = 17,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020 = 18,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_FULL_GHLG_TOPLEFT_P2020 = 19,
|
||||
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709 = 20,
|
||||
GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020 = 21,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P709 = 22,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_LEFT_P2020 = 23,
|
||||
GST_DXGI_COLOR_SPACE_YCBCR_STUDIO_G24_TOPLEFT_P2020 = 24,
|
||||
GST_DXGI_COLOR_SPACE_CUSTOM = 0xFFFFFFFF
|
||||
} GST_DXGI_COLOR_SPACE_TYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GST_DXGI_COLOR_SPACE_TYPE type;
|
||||
GstVideoColorRange range;
|
||||
GstVideoTransferFunction transfer;
|
||||
GstVideoColorPrimaries primaries;
|
||||
} DxgiColorSpaceMap;
|
||||
|
||||
/* https://docs.microsoft.com/en-us/windows/win32/api/dxgicommon/ne-dxgicommon-dxgi_color_space_type */
|
||||
static const DxgiColorSpaceMap colorspace_map[] = {
|
||||
/* RGB, bt709 */
|
||||
{GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, GST_VIDEO_COLOR_RANGE_0_255,
|
||||
GST_VIDEO_TRANSFER_BT709, GST_VIDEO_COLOR_PRIMARIES_BT709},
|
||||
{GST_DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709, GST_VIDEO_COLOR_RANGE_0_255,
|
||||
GST_VIDEO_TRANSFER_GAMMA10, GST_VIDEO_COLOR_PRIMARIES_BT709},
|
||||
{GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709, GST_VIDEO_COLOR_RANGE_16_235,
|
||||
GST_VIDEO_TRANSFER_BT709, GST_VIDEO_COLOR_PRIMARIES_BT709},
|
||||
/* RGB, bt2020 */
|
||||
{GST_DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020, GST_VIDEO_COLOR_RANGE_0_255,
|
||||
GST_VIDEO_TRANSFER_BT2020_10, GST_VIDEO_COLOR_PRIMARIES_BT2020},
|
||||
{GST_DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020, GST_VIDEO_COLOR_RANGE_16_235,
|
||||
GST_VIDEO_TRANSFER_BT2020_10, GST_VIDEO_COLOR_PRIMARIES_BT2020},
|
||||
/* RGB, bt2084 */
|
||||
{GST_DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020, GST_VIDEO_COLOR_RANGE_0_255,
|
||||
GST_VIDEO_TRANSFER_SMPTE2084, GST_VIDEO_COLOR_PRIMARIES_BT2020},
|
||||
{GST_DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020,
|
||||
GST_VIDEO_COLOR_RANGE_16_235,
|
||||
GST_VIDEO_TRANSFER_SMPTE2084, GST_VIDEO_COLOR_PRIMARIES_BT2020},
|
||||
/* RGB, SRGB */
|
||||
{GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P709, GST_VIDEO_COLOR_RANGE_16_235,
|
||||
GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT709},
|
||||
{GST_DXGI_COLOR_SPACE_RGB_STUDIO_G24_NONE_P2020, GST_VIDEO_COLOR_RANGE_16_235,
|
||||
GST_VIDEO_TRANSFER_SRGB, GST_VIDEO_COLOR_PRIMARIES_BT2020},
|
||||
};
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_color_space_from_video_info (GstD3D11Window * self,
|
||||
GstVideoInfo * info, IDXGISwapChain4 * swapchain,
|
||||
GST_DXGI_COLOR_SPACE_TYPE * dxgi_colorspace)
|
||||
{
|
||||
guint i;
|
||||
gint best_idx = -1;
|
||||
gint best_score = 0;
|
||||
|
||||
g_return_val_if_fail (info != NULL, FALSE);
|
||||
g_return_val_if_fail (dxgi_colorspace != NULL, FALSE);
|
||||
|
||||
/* We render only RGB for now */
|
||||
if (!GST_VIDEO_FORMAT_INFO_IS_RGB (info->finfo))
|
||||
return FALSE;
|
||||
|
||||
/* find the best matching colorspace */
|
||||
for (i = 0; i < G_N_ELEMENTS (colorspace_map); i++) {
|
||||
GstVideoColorimetry *cinfo = &info->colorimetry;
|
||||
UINT can_support = 0;
|
||||
HRESULT hr;
|
||||
gint score = 0;
|
||||
GstVideoTransferFunction transfer = cinfo->transfer;
|
||||
DXGI_COLOR_SPACE_TYPE type = (DXGI_COLOR_SPACE_TYPE) colorspace_map[i].type;
|
||||
|
||||
if (transfer == GST_VIDEO_TRANSFER_BT2020_12)
|
||||
transfer = GST_VIDEO_TRANSFER_BT2020_10;
|
||||
|
||||
hr = swapchain->CheckColorSpaceSupport (type, &can_support);
|
||||
|
||||
if (SUCCEEDED (hr) &&
|
||||
(can_support & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) ==
|
||||
DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT) {
|
||||
if (cinfo->range == colorspace_map[i].range)
|
||||
score++;
|
||||
|
||||
if (transfer == colorspace_map[i].transfer)
|
||||
score++;
|
||||
|
||||
if (cinfo->primaries == colorspace_map[i].primaries)
|
||||
score++;
|
||||
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"colorspace %d supported, score %d", type, score);
|
||||
|
||||
if (score > best_score) {
|
||||
best_score = score;
|
||||
best_idx = i;
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"colorspace %d not supported", type);
|
||||
}
|
||||
}
|
||||
|
||||
if (best_idx < 0)
|
||||
return FALSE;
|
||||
|
||||
*dxgi_colorspace = colorspace_map[best_idx].type;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
|
||||
guint aspect_ratio_n, guint aspect_ratio_d, GstCaps * caps, GError ** error)
|
||||
{
|
||||
GstD3D11WindowClass *klass;
|
||||
GstCaps *render_caps;
|
||||
guint swapchain_flags = 0;
|
||||
#if (DXGI_HEADER_VERSION >= 5)
|
||||
gboolean have_cll = FALSE;
|
||||
gboolean have_mastering = FALSE;
|
||||
gboolean swapchain4_available = FALSE;
|
||||
#endif
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
|
||||
g_return_val_if_fail (aspect_ratio_n > 0, FALSE);
|
||||
g_return_val_if_fail (aspect_ratio_d > 0, FALSE);
|
||||
|
||||
GST_DEBUG_OBJECT (window, "Prepare window with %dx%d caps %" GST_PTR_FORMAT,
|
||||
width, height, caps);
|
||||
|
||||
render_caps = gst_d3d11_device_get_supported_caps (window->device,
|
||||
(D3D11_FORMAT_SUPPORT) (D3D11_FORMAT_SUPPORT_TEXTURE2D |
|
||||
D3D11_FORMAT_SUPPORT_DISPLAY));
|
||||
|
||||
GST_DEBUG_OBJECT (window, "rendering caps %" GST_PTR_FORMAT, render_caps);
|
||||
render_caps = gst_d3d11_caps_fixate_format (caps, render_caps);
|
||||
|
||||
if (!render_caps || gst_caps_is_empty (render_caps)) {
|
||||
GST_ERROR_OBJECT (window, "Couldn't define render caps");
|
||||
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||
"Couldn't define render caps");
|
||||
gst_clear_caps (&render_caps);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
render_caps = gst_caps_fixate (render_caps);
|
||||
gst_video_info_from_caps (&window->render_info, render_caps);
|
||||
gst_clear_caps (&render_caps);
|
||||
|
||||
window->render_format =
|
||||
gst_d3d11_format_from_gst (GST_VIDEO_INFO_FORMAT (&window->render_info));
|
||||
if (!window->render_format ||
|
||||
window->render_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
|
||||
GST_ERROR_OBJECT (window, "Unknown dxgi render format");
|
||||
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||
"Unknown dxgi render format");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gst_video_info_from_caps (&window->info, caps);
|
||||
|
||||
if (window->converter)
|
||||
gst_d3d11_color_converter_free (window->converter);
|
||||
window->converter = NULL;
|
||||
|
||||
if (window->compositor)
|
||||
gst_d3d11_overlay_compositor_free (window->compositor);
|
||||
window->compositor = NULL;
|
||||
|
||||
/* preserve upstream colorimetry */
|
||||
window->render_info.width = width;
|
||||
window->render_info.height = height;
|
||||
|
||||
window->render_info.colorimetry.primaries =
|
||||
window->info.colorimetry.primaries;
|
||||
window->render_info.colorimetry.transfer = window->info.colorimetry.transfer;
|
||||
|
||||
window->converter =
|
||||
gst_d3d11_color_converter_new (window->device, &window->info,
|
||||
&window->render_info);
|
||||
|
||||
if (!window->converter) {
|
||||
GST_ERROR_OBJECT (window, "Cannot create converter");
|
||||
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||
"Cannot create converter");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
window->compositor =
|
||||
gst_d3d11_overlay_compositor_new (window->device, &window->render_info);
|
||||
if (!window->compositor) {
|
||||
GST_ERROR_OBJECT (window, "Cannot create overlay compositor");
|
||||
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||
"Cannot create overlay compositor");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
window->allow_tearing = FALSE;
|
||||
#if (DXGI_HEADER_VERSION >= 5)
|
||||
if (!gst_video_content_light_level_from_caps (&window->content_light_level,
|
||||
caps)) {
|
||||
gst_video_content_light_level_init (&window->content_light_level);
|
||||
} else {
|
||||
have_cll = TRUE;
|
||||
}
|
||||
|
||||
if (!gst_video_mastering_display_info_from_caps
|
||||
(&window->mastering_display_info, caps)) {
|
||||
gst_video_mastering_display_info_init (&window->mastering_display_info);
|
||||
} else {
|
||||
have_mastering = TRUE;
|
||||
}
|
||||
|
||||
if (gst_d3d11_device_get_chosen_dxgi_factory_version (window->device) >=
|
||||
GST_D3D11_DXGI_FACTORY_5) {
|
||||
GST_DEBUG_OBJECT (window, "DXGI 1.5 interface is available");
|
||||
swapchain4_available = TRUE;
|
||||
|
||||
g_object_get (window->device,
|
||||
"allow-tearing", &window->allow_tearing, NULL);
|
||||
if (window->allow_tearing) {
|
||||
GST_DEBUG_OBJECT (window, "device support tearning");
|
||||
swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (window->swap_chain) {
|
||||
gst_d3d11_device_lock (window->device);
|
||||
gst_d3d11_window_release_resources (window->device, window);
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
}
|
||||
|
||||
window->aspect_ratio_n = aspect_ratio_n;
|
||||
window->aspect_ratio_d = aspect_ratio_d;
|
||||
|
||||
window->render_rect.left = 0;
|
||||
window->render_rect.top = 0;
|
||||
window->render_rect.right = width;
|
||||
window->render_rect.bottom = height;
|
||||
|
||||
window->width = width;
|
||||
window->height = height;
|
||||
|
||||
klass = GST_D3D11_WINDOW_GET_CLASS (window);
|
||||
if (!klass->create_swap_chain (window, window->render_format->dxgi_format,
|
||||
width, height, swapchain_flags, &window->swap_chain)) {
|
||||
GST_ERROR_OBJECT (window, "Cannot create swapchain");
|
||||
g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
|
||||
"Cannot create swapchain");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#if (DXGI_HEADER_VERSION >= 5)
|
||||
if (swapchain4_available) {
|
||||
HRESULT hr;
|
||||
GST_DXGI_COLOR_SPACE_TYPE ctype;
|
||||
IDXGISwapChain4* swap_chain4 = (IDXGISwapChain4 *) window->swap_chain;
|
||||
|
||||
if (gst_d3d11_window_color_space_from_video_info (window,
|
||||
&window->render_info, swap_chain4, &ctype)) {
|
||||
hr = swap_chain4->SetColorSpace1 ((DXGI_COLOR_SPACE_TYPE) ctype);
|
||||
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (window, "Failed to set colorspace %d, hr: 0x%x",
|
||||
ctype, (guint) hr);
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (window, "Set colorspace %d", ctype);
|
||||
}
|
||||
|
||||
if (have_cll && have_mastering) {
|
||||
DXGI_HDR_METADATA_HDR10 metadata = { 0, };
|
||||
|
||||
GST_DEBUG_OBJECT (window, "Have HDR metadata, set to DXGI swapchain");
|
||||
|
||||
mastering_display_gst_to_dxgi (&window->mastering_display_info,
|
||||
&window->content_light_level, &metadata);
|
||||
|
||||
hr = swap_chain4->SetHDRMetaData (DXGI_HDR_METADATA_TYPE_HDR10,
|
||||
sizeof (DXGI_HDR_METADATA_HDR10), &metadata);
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (window, "Couldn't set HDR metadata, hr 0x%x",
|
||||
(guint) hr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (window,
|
||||
"Could not get color space from %" GST_PTR_FORMAT, caps);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (window->requested_fullscreen != window->fullscreen) {
|
||||
klass->change_fullscreen_mode (window);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (window, "New swap chain 0x%p created", window->swap_chain);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d11_window_show (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowClass *klass;
|
||||
|
||||
g_return_if_fail (GST_IS_D3D11_WINDOW (window));
|
||||
|
||||
klass = GST_D3D11_WINDOW_GET_CLASS (window);
|
||||
|
||||
if (klass->show)
|
||||
klass->show (window);
|
||||
}
|
||||
|
||||
void
|
||||
gst_d3d11_window_set_render_rectangle (GstD3D11Window * window, gint x, gint y,
|
||||
gint width, gint height)
|
||||
{
|
||||
g_return_if_fail (GST_IS_D3D11_WINDOW (window));
|
||||
|
||||
/* TODO: resize window and view */
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
|
||||
{
|
||||
GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (self);
|
||||
GstFlowReturn ret = GST_FLOW_OK;
|
||||
guint present_flags = 0;
|
||||
|
||||
if (buffer) {
|
||||
gst_buffer_replace (&self->cached_buffer, buffer);
|
||||
}
|
||||
|
||||
if (self->cached_buffer) {
|
||||
ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
|
||||
guint i, j, k;
|
||||
|
||||
for (i = 0, j = 0; i < gst_buffer_n_memory (self->cached_buffer); i++) {
|
||||
GstD3D11Memory *mem =
|
||||
(GstD3D11Memory *) gst_buffer_peek_memory (self->cached_buffer, i);
|
||||
for (k = 0; k < mem->num_shader_resource_views; k++) {
|
||||
srv[j] = mem->shader_resource_view[k];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->first_present) {
|
||||
gst_d3d11_color_converter_update_rect (self->converter,
|
||||
&self->render_rect);
|
||||
gst_d3d11_overlay_compositor_update_rect (self->compositor,
|
||||
&self->render_rect);
|
||||
}
|
||||
|
||||
gst_d3d11_color_converter_convert_unlocked (self->converter,
|
||||
srv, &self->rtv);
|
||||
|
||||
gst_d3d11_overlay_compositor_upload (self->compositor, self->cached_buffer);
|
||||
gst_d3d11_overlay_compositor_draw_unlocked (self->compositor, &self->rtv);
|
||||
|
||||
#if (DXGI_HEADER_VERSION >= 5)
|
||||
if (self->allow_tearing) {
|
||||
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
}
|
||||
#endif
|
||||
|
||||
ret = klass->present (self, present_flags);
|
||||
|
||||
self->first_present = FALSE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstFlowReturn
|
||||
gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer,
|
||||
GstVideoRectangle * rect)
|
||||
{
|
||||
GstMemory *mem;
|
||||
GstFlowReturn ret;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
|
||||
g_return_val_if_fail (rect != NULL, GST_FLOW_ERROR);
|
||||
|
||||
mem = gst_buffer_peek_memory (buffer, 0);
|
||||
if (!gst_is_d3d11_memory (mem)) {
|
||||
GST_ERROR_OBJECT (window, "Invalid buffer");
|
||||
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
ret = gst_d3d111_window_present (window, buffer);
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d11_window_unlock (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowClass *klass;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
|
||||
|
||||
klass = GST_D3D11_WINDOW_GET_CLASS (window);
|
||||
|
||||
if (klass->unlock)
|
||||
ret = klass->unlock (window);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_d3d11_window_unlock_stop (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowClass *klass;
|
||||
gboolean ret = TRUE;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
|
||||
|
||||
klass = GST_D3D11_WINDOW_GET_CLASS (window);
|
||||
|
||||
if (klass->unlock_stop)
|
||||
ret = klass->unlock_stop (window);
|
||||
|
||||
gst_d3d11_device_lock (window->device);
|
||||
gst_clear_buffer (&window->cached_buffer);
|
||||
gst_d3d11_device_unlock (window->device);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
GstD3D11WindowNativeType
|
||||
gst_d3d11_window_get_native_type_from_handle (guintptr handle)
|
||||
{
|
||||
if (!handle)
|
||||
return GST_D3D11_WINDOW_NATIVE_TYPE_NONE;
|
||||
|
||||
#if (!GST_D3D11_WINAPI_ONLY_APP)
|
||||
if (IsWindow ((HWND) handle))
|
||||
return GST_D3D11_WINDOW_NATIVE_TYPE_HWND;
|
||||
#else
|
||||
{
|
||||
ComPtr<IInspectable> window = reinterpret_cast<IInspectable*> (handle);
|
||||
ComPtr<ABI::Windows::UI::Core::ICoreWindow> core_window;
|
||||
ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> panel;
|
||||
|
||||
if (SUCCEEDED (window.As (&core_window)))
|
||||
return GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW;
|
||||
|
||||
if (SUCCEEDED (window.As (&panel)))
|
||||
return GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL;
|
||||
}
|
||||
#endif
|
||||
|
||||
return GST_D3D11_WINDOW_NATIVE_TYPE_NONE;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
gst_d3d11_window_get_native_type_to_string (GstD3D11WindowNativeType type)
|
||||
{
|
||||
switch (type) {
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_NONE:
|
||||
return "none";
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_HWND:
|
||||
return "hwnd";
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW:
|
||||
return "core-window";
|
||||
case GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL:
|
||||
return "swap-chain-panel";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "none";
|
||||
}
|
|
@ -31,9 +31,9 @@
|
|||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D11_WINDOW (gst_d3d11_window_get_type())
|
||||
#define GST_D3D11_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_D3D11_WINDOW, GstD3D11Window))
|
||||
#define GST_D3D11_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS((klass), GST_TYPE_D3D11_WINDOW, GstD3D11WindowClass))
|
||||
#define GST_IS_D3D11_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_D3D11_WINDOW))
|
||||
#define GST_D3D11_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_D3D11_WINDOW, GstD3D11Window))
|
||||
#define GST_D3D11_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_D3D11_WINDOW, GstD3D11WindowClass))
|
||||
#define GST_IS_D3D11_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_D3D11_WINDOW))
|
||||
#define GST_IS_D3D11_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_D3D11_WINDOW))
|
||||
#define GST_D3D11_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_D3D11_WINDOW, GstD3D11WindowClass))
|
||||
#define GST_D3D11_WINDOW_TOGGLE_MODE_GET_TYPE (gst_d3d11_window_fullscreen_toggle_mode_type())
|
||||
|
@ -43,13 +43,6 @@ typedef struct _GstD3D11WindowClass GstD3D11WindowClass;
|
|||
|
||||
#define GST_D3D11_WINDOW_FLOW_CLOSED GST_FLOW_CUSTOM_ERROR
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_D3D11_WINDOW_OVERLAY_STATE_NONE = 0,
|
||||
GST_D3D11_WINDOW_OVERLAY_STATE_OPENED,
|
||||
GST_D3D11_WINDOW_OVERLAY_STATE_CLOSED,
|
||||
} GstD3D11WindowOverlayState;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE = 0,
|
||||
|
@ -59,10 +52,30 @@ typedef enum
|
|||
|
||||
GType gst_d3d11_window_fullscreen_toggle_mode_type (void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_D3D11_WINDOW_NATIVE_TYPE_NONE = 0,
|
||||
GST_D3D11_WINDOW_NATIVE_TYPE_HWND,
|
||||
GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW,
|
||||
GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL,
|
||||
} GstD3D11WindowNativeType;
|
||||
|
||||
struct _GstD3D11Window
|
||||
{
|
||||
GstObject parent;
|
||||
|
||||
/*< protected >*/
|
||||
gboolean initialized;
|
||||
GstD3D11Device *device;
|
||||
guintptr external_handle;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gboolean enable_navigation_events;
|
||||
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
|
||||
gboolean requested_fullscreen;
|
||||
gboolean fullscreen;
|
||||
|
||||
GstVideoInfo info;
|
||||
GstVideoInfo render_info;
|
||||
const GstD3D11Format *render_format;
|
||||
|
@ -78,12 +91,6 @@ struct _GstD3D11Window
|
|||
/* requested rect via gst_d3d11_window_render */
|
||||
GstVideoRectangle rect;
|
||||
|
||||
GMutex lock;
|
||||
GCond cond;
|
||||
|
||||
GMainContext *main_context;
|
||||
GMainLoop *loop;
|
||||
|
||||
guint width;
|
||||
guint height;
|
||||
|
||||
|
@ -93,77 +100,83 @@ struct _GstD3D11Window
|
|||
guint aspect_ratio_n;
|
||||
guint aspect_ratio_d;
|
||||
|
||||
gboolean visible;
|
||||
|
||||
GSource *msg_source;
|
||||
GIOChannel *msg_io_channel;
|
||||
|
||||
GThread *thread;
|
||||
|
||||
gboolean created;
|
||||
|
||||
HWND internal_win_id;
|
||||
HWND external_win_id;
|
||||
GstD3D11WindowOverlayState overlay_state;
|
||||
|
||||
HDC device_handle;
|
||||
IDXGISwapChain *swap_chain;
|
||||
ID3D11RenderTargetView *rtv;
|
||||
DXGI_FORMAT format;
|
||||
gboolean first_present;
|
||||
gboolean have_swapchain1;
|
||||
|
||||
GstD3D11Device *device;
|
||||
|
||||
/* properties */
|
||||
gboolean force_aspect_ratio;
|
||||
gboolean enable_navigation_events;
|
||||
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
|
||||
gboolean requested_fullscreen;
|
||||
gboolean fullscreen;
|
||||
|
||||
/* atomic */
|
||||
volatile gint pending_fullscreen_count;
|
||||
|
||||
GstBuffer *cached_buffer;
|
||||
gboolean first_present;
|
||||
gboolean allow_tearing;
|
||||
|
||||
/* fullscreen related */
|
||||
RECT restore_rect;
|
||||
LONG restore_style;
|
||||
};
|
||||
|
||||
struct _GstD3D11WindowClass
|
||||
{
|
||||
GstObjectClass object_class;
|
||||
|
||||
void (*show) (GstD3D11Window * window);
|
||||
|
||||
void (*update_swap_chain) (GstD3D11Window * window);
|
||||
|
||||
void (*change_fullscreen_mode) (GstD3D11Window * window);
|
||||
|
||||
gboolean (*create_swap_chain) (GstD3D11Window * window,
|
||||
DXGI_FORMAT format,
|
||||
guint width,
|
||||
guint height,
|
||||
guint swapchain_flags,
|
||||
IDXGISwapChain ** swap_chain);
|
||||
|
||||
GstFlowReturn (*present) (GstD3D11Window * window,
|
||||
guint present_flags);
|
||||
|
||||
gboolean (*unlock) (GstD3D11Window * window);
|
||||
|
||||
gboolean (*unlock_stop) (GstD3D11Window * window);
|
||||
};
|
||||
|
||||
GType gst_d3d11_window_get_type (void);
|
||||
GType gst_d3d11_window_get_type (void);
|
||||
|
||||
GstD3D11Window * gst_d3d11_window_new (GstD3D11Device * device);
|
||||
void gst_d3d11_window_show (GstD3D11Window * window);
|
||||
|
||||
void gst_d3d11_window_show (GstD3D11Window * window);
|
||||
void gst_d3d11_window_set_render_rectangle (GstD3D11Window * window,
|
||||
gint x, gint y,
|
||||
gint width, gint height);
|
||||
|
||||
void gst_d3d11_window_set_window_handle (GstD3D11Window * window,
|
||||
guintptr id);
|
||||
gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
|
||||
guint width,
|
||||
guint height,
|
||||
guint aspect_ratio_n,
|
||||
guint aspect_ratio_d,
|
||||
GstCaps * caps,
|
||||
GError ** error);
|
||||
|
||||
void gst_d3d11_window_set_render_rectangle (GstD3D11Window * window,
|
||||
gint x, gint y,
|
||||
gint width, gint height);
|
||||
GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
|
||||
GstBuffer * buffer,
|
||||
GstVideoRectangle * src_rect);
|
||||
|
||||
gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
|
||||
guint width,
|
||||
guint height,
|
||||
guint aspect_ratio_n,
|
||||
guint aspect_ratio_d,
|
||||
GstCaps * caps,
|
||||
GError ** error);
|
||||
gboolean gst_d3d11_window_unlock (GstD3D11Window * window);
|
||||
|
||||
GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
|
||||
GstBuffer * buffer,
|
||||
GstVideoRectangle * src_rect);
|
||||
gboolean gst_d3d11_window_unlock_stop (GstD3D11Window * window);
|
||||
|
||||
gboolean gst_d3d11_window_flush (GstD3D11Window * window);
|
||||
void gst_d3d11_window_on_resize (GstD3D11Window * window,
|
||||
guint width,
|
||||
guint height);
|
||||
|
||||
void gst_d3d11_window_on_key_event (GstD3D11Window * window,
|
||||
const gchar * event,
|
||||
const gchar * key);
|
||||
|
||||
void gst_d3d11_window_on_mouse_event (GstD3D11Window * window,
|
||||
const gchar * event,
|
||||
gint button,
|
||||
gdouble x,
|
||||
gdouble y);
|
||||
|
||||
/* utils */
|
||||
GstD3D11WindowNativeType gst_d3d11_window_get_native_type_from_handle (guintptr handle);
|
||||
|
||||
const gchar * gst_d3d11_window_get_native_type_to_string (GstD3D11WindowNativeType type);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstD3D11Window, gst_object_unref)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
364
sys/d3d11/gstd3d11window_corewindow.cpp
Normal file
364
sys/d3d11/gstd3d11window_corewindow.cpp
Normal file
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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 "gstd3d11window.h"
|
||||
#include "gstd3d11device.h"
|
||||
#include "gstd3d11memory.h"
|
||||
#include "gstd3d11utils.h"
|
||||
#include "gstd3d11window_corewindow.h"
|
||||
|
||||
/* workaround for GetCurrentTime collision */
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
#include <windows.ui.xaml.h>
|
||||
#include <windows.ui.xaml.media.dxinterop.h>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
#include <windows.graphics.display.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace ABI::Windows::UI;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::Foundation::Collections;
|
||||
using namespace ABI::Windows::Graphics;
|
||||
|
||||
typedef ABI::Windows::Foundation::
|
||||
__FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t
|
||||
IWindowSizeChangedEventHandler;
|
||||
|
||||
extern "C" {
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
|
||||
#define GST_CAT_DEFAULT gst_d3d11_window_debug
|
||||
}
|
||||
|
||||
typedef struct _CoreWindowWinRTStorage
|
||||
{
|
||||
ComPtr<Core::ICoreWindow> core_window;
|
||||
EventRegistrationToken event_token;
|
||||
} CoreWindowWinRTStorage;
|
||||
|
||||
struct _GstD3D11WindowCoreWindow
|
||||
{
|
||||
GstD3D11Window parent;
|
||||
|
||||
CoreWindowWinRTStorage *storage;
|
||||
};
|
||||
|
||||
#define gst_d3d11_window_core_window_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstD3D11WindowCoreWindow, gst_d3d11_window_core_window,
|
||||
GST_TYPE_D3D11_WINDOW);
|
||||
|
||||
static void gst_d3d11_window_core_window_constructed (GObject * object);
|
||||
static void gst_d3d11_window_core_window_dispose (GObject * object);
|
||||
static void gst_d3d11_window_core_window_update_swap_chain (GstD3D11Window * window);
|
||||
static void
|
||||
gst_d3d11_window_core_window_change_fullscreen_mode (GstD3D11Window * window);
|
||||
static gboolean
|
||||
gst_d3d11_window_core_window_create_swap_chain (GstD3D11Window * window,
|
||||
DXGI_FORMAT format, guint width, guint height, guint swapchain_flags,
|
||||
IDXGISwapChain ** swap_chain);
|
||||
static GstFlowReturn
|
||||
gst_d3d11_window_core_window_present (GstD3D11Window * window,
|
||||
guint present_flags);
|
||||
static void
|
||||
gst_d3d11_window_core_window_on_resize (GstD3D11WindowCoreWindow * self,
|
||||
guint width, guint height);
|
||||
|
||||
static float
|
||||
get_logical_dpi (void)
|
||||
{
|
||||
ComPtr<Display::IDisplayPropertiesStatics> properties;
|
||||
HRESULT hr;
|
||||
HStringReference str_ref =
|
||||
HStringReference (RuntimeClass_Windows_Graphics_Display_DisplayProperties);
|
||||
|
||||
hr = GetActivationFactory (str_ref.Get(), properties.GetAddressOf());
|
||||
|
||||
if (gst_d3d11_result (hr, NULL)) {
|
||||
float dpi = 96.0f;
|
||||
|
||||
hr = properties->get_LogicalDpi (&dpi);
|
||||
if (gst_d3d11_result (hr, NULL))
|
||||
return dpi;
|
||||
}
|
||||
|
||||
return 96.0f;
|
||||
}
|
||||
|
||||
static inline float dip_to_pixel (float dip)
|
||||
{
|
||||
/* https://docs.microsoft.com/en-us/windows/win32/learnwin32/dpi-and-device-independent-pixels */
|
||||
return dip * get_logical_dpi() / 96.0f;
|
||||
}
|
||||
|
||||
class CoreResizeHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>,
|
||||
IWindowSizeChangedEventHandler>
|
||||
{
|
||||
public:
|
||||
CoreResizeHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstD3D11WindowCoreWindow * listener)
|
||||
{
|
||||
if (!listener)
|
||||
return E_INVALIDARG;
|
||||
|
||||
window = listener;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(Core::ICoreWindow * sender, Core::IWindowSizeChangedEventArgs * args)
|
||||
{
|
||||
if (window) {
|
||||
Size new_size;
|
||||
HRESULT hr = args->get_Size(&new_size);
|
||||
if (gst_d3d11_result (hr, NULL)) {
|
||||
guint width, height;
|
||||
|
||||
width = (guint) dip_to_pixel (new_size.Width);
|
||||
height = (guint) dip_to_pixel (new_size.Height);
|
||||
|
||||
gst_d3d11_window_core_window_on_resize (window, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstD3D11WindowCoreWindow * window;
|
||||
};
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_class_init (GstD3D11WindowCoreWindowClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstD3D11WindowClass *window_class = GST_D3D11_WINDOW_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = gst_d3d11_window_core_window_constructed;
|
||||
gobject_class->dispose = gst_d3d11_window_core_window_dispose;
|
||||
|
||||
window_class->update_swap_chain =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_core_window_update_swap_chain);
|
||||
window_class->change_fullscreen_mode =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_core_window_change_fullscreen_mode);
|
||||
window_class->create_swap_chain =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_core_window_create_swap_chain);
|
||||
window_class->present =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_core_window_present);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_init (GstD3D11WindowCoreWindow * self)
|
||||
{
|
||||
self->storage = new CoreWindowWinRTStorage;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_constructed (GObject * object)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (object);
|
||||
GstD3D11WindowCoreWindow *self = GST_D3D11_WINDOW_CORE_WINDOW (object);
|
||||
CoreWindowWinRTStorage *storage = self->storage;
|
||||
HRESULT hr;
|
||||
ComPtr<IInspectable> inspectable;
|
||||
ComPtr<IWindowSizeChangedEventHandler> resize_handler;
|
||||
Rect bounds;
|
||||
|
||||
if (!window->external_handle) {
|
||||
GST_ERROR_OBJECT (self, "No external window handle");
|
||||
return;
|
||||
}
|
||||
|
||||
inspectable = reinterpret_cast<IInspectable*> (window->external_handle);
|
||||
|
||||
hr = inspectable.As (&storage->core_window);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = storage->core_window->get_Bounds (&bounds);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
window->surface_width = dip_to_pixel (bounds.Width);
|
||||
window->surface_height = dip_to_pixel (bounds.Height);
|
||||
|
||||
GST_DEBUG_OBJECT (self,
|
||||
"client size %dx%d", window->surface_width, window->surface_height);
|
||||
|
||||
hr = MakeAndInitialize<CoreResizeHandler>(&resize_handler, self);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = storage->core_window->add_SizeChanged (resize_handler.Get(),
|
||||
&storage->event_token);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
window->initialized = TRUE;
|
||||
return;
|
||||
|
||||
error:
|
||||
GST_ERROR_OBJECT (self, "Invalid window handle");
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_dispose (GObject * object)
|
||||
{
|
||||
GstD3D11WindowCoreWindow *self = GST_D3D11_WINDOW_CORE_WINDOW (object);
|
||||
CoreWindowWinRTStorage *storage = self->storage;
|
||||
|
||||
if (storage) {
|
||||
if (storage->core_window)
|
||||
storage->core_window->remove_SizeChanged (storage->event_token);
|
||||
|
||||
delete storage;
|
||||
}
|
||||
|
||||
self->storage = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_core_window_create_swap_chain (GstD3D11Window * window,
|
||||
DXGI_FORMAT format, guint width, guint height, guint swapchain_flags,
|
||||
IDXGISwapChain ** swap_chain)
|
||||
{
|
||||
GstD3D11WindowCoreWindow *self = GST_D3D11_WINDOW_CORE_WINDOW (window);
|
||||
ComPtr<IDXGISwapChain1> new_swapchain;
|
||||
GstD3D11Device *device = window->device;
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, };
|
||||
|
||||
desc1.Width = width;
|
||||
desc1.Height = height;
|
||||
desc1.Format = format;
|
||||
desc1.Stereo = FALSE;
|
||||
desc1.SampleDesc.Count = 1;
|
||||
desc1.SampleDesc.Quality = 0;
|
||||
desc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc1.BufferCount = 2;
|
||||
desc1.Scaling = DXGI_SCALING_NONE;
|
||||
desc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
desc1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
desc1.Flags = swapchain_flags;
|
||||
|
||||
new_swapchain =
|
||||
gst_d3d11_device_create_swap_chain_for_core_window (device,
|
||||
window->external_handle, &desc1, NULL);
|
||||
|
||||
if (!new_swapchain) {
|
||||
GST_ERROR_OBJECT (self, "Cannot create swapchain");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
new_swapchain.CopyTo (swap_chain);
|
||||
|
||||
gst_d3d11_window_on_resize (GST_D3D11_WINDOW (self),
|
||||
window->surface_width, window->surface_height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d11_window_core_window_present (GstD3D11Window * window,
|
||||
guint present_flags)
|
||||
{
|
||||
GstD3D11WindowCoreWindow *self = GST_D3D11_WINDOW_CORE_WINDOW (window);
|
||||
HRESULT hr;
|
||||
DXGI_PRESENT_PARAMETERS present_params = { 0, };
|
||||
IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain;
|
||||
|
||||
/* the first present should not specify dirty-rect */
|
||||
if (!window->first_present) {
|
||||
present_params.DirtyRectsCount = 1;
|
||||
present_params.pDirtyRects = &window->render_rect;
|
||||
}
|
||||
|
||||
hr = swap_chain->Present1 (0, present_flags, &present_params);
|
||||
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
|
||||
(guint) hr);
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_update_swap_chain (GstD3D11Window * window)
|
||||
{
|
||||
gst_d3d11_window_on_resize (window,
|
||||
window->surface_width, window->surface_height);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_change_fullscreen_mode (GstD3D11Window * window)
|
||||
{
|
||||
GST_FIXME_OBJECT (window, "Implement fullscreen mode change");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_core_window_on_resize (GstD3D11WindowCoreWindow * self,
|
||||
guint width, guint height)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (self);
|
||||
|
||||
window->surface_width = width;
|
||||
window->surface_height = height;
|
||||
|
||||
GST_LOG_OBJECT (self, "New size %dx%d", width, height);
|
||||
|
||||
gst_d3d11_window_on_resize (GST_D3D11_WINDOW (self), width, height);
|
||||
}
|
||||
|
||||
GstD3D11Window *
|
||||
gst_d3d11_window_core_window_new (GstD3D11Device * device, guintptr handle)
|
||||
{
|
||||
GstD3D11Window *window;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
|
||||
g_return_val_if_fail (handle, NULL);
|
||||
|
||||
window = (GstD3D11Window *)
|
||||
g_object_new (GST_TYPE_D3D11_WINDOW_CORE_WINDOW,
|
||||
"d3d11device", device, "window-handle", handle, NULL);
|
||||
|
||||
if (!window->initialized) {
|
||||
gst_object_unref (window);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_ref_sink (window);
|
||||
|
||||
return window;
|
||||
}
|
40
sys/d3d11/gstd3d11window_corewindow.h
Normal file
40
sys/d3d11/gstd3d11window_corewindow.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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.
|
||||
*/
|
||||
|
||||
#ifndef __GST_D3D11_WINDOW_CORE_WINDOW_H__
|
||||
#define __GST_D3D11_WINDOW_CORE_WINDOW_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include "gstd3d11_fwd.h"
|
||||
#include "gstd3d11window.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D11_WINDOW_CORE_WINDOW (gst_d3d11_window_core_window_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstD3D11WindowCoreWindow, gst_d3d11_window_core_window,
|
||||
GST, D3D11_WINDOW_CORE_WINDOW, GstD3D11Window);
|
||||
|
||||
GstD3D11Window * gst_d3d11_window_core_window_new (GstD3D11Device * device,
|
||||
guintptr handle);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_D3D11_WINDOW_CORE_WINDOW_H__ */
|
499
sys/d3d11/gstd3d11window_swapchainpanel.cpp
Normal file
499
sys/d3d11/gstd3d11window_swapchainpanel.cpp
Normal file
|
@ -0,0 +1,499 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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 "gstd3d11window.h"
|
||||
#include "gstd3d11device.h"
|
||||
#include "gstd3d11memory.h"
|
||||
#include "gstd3d11utils.h"
|
||||
#include "gstd3d11window_swapchainpanel.h"
|
||||
|
||||
/* workaround for GetCurrentTime collision */
|
||||
#ifdef GetCurrentTime
|
||||
#undef GetCurrentTime
|
||||
#endif
|
||||
#include <windows.ui.xaml.h>
|
||||
#include <windows.ui.xaml.media.dxinterop.h>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace Microsoft::WRL::Wrappers;
|
||||
using namespace ABI::Windows::UI;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
|
||||
extern "C" {
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
|
||||
#define GST_CAT_DEFAULT gst_d3d11_window_debug
|
||||
}
|
||||
|
||||
/* timeout to wait busy UI thread */
|
||||
#define DEFAULT_ASYNC_TIMEOUT (5 * 1000)
|
||||
|
||||
typedef struct _SwapChainPanelWinRTStorage
|
||||
{
|
||||
ComPtr<Xaml::Controls::ISwapChainPanel> panel;
|
||||
ComPtr<Core::ICoreDispatcher> dispatcher;
|
||||
ComPtr<IDXGISwapChain1> swapchain;
|
||||
HANDLE cancellable;
|
||||
EventRegistrationToken event_token;
|
||||
} SwapChainPanelWinRTStorage;
|
||||
|
||||
struct _GstD3D11WindowSwapChainPanel
|
||||
{
|
||||
GstD3D11Window parent;
|
||||
|
||||
SwapChainPanelWinRTStorage *storage;
|
||||
};
|
||||
|
||||
#define gst_d3d11_window_swap_chain_panel_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstD3D11WindowSwapChainPanel,
|
||||
gst_d3d11_window_swap_chain_panel, GST_TYPE_D3D11_WINDOW);
|
||||
|
||||
static void gst_d3d11_window_swap_chain_panel_constructed (GObject * object);
|
||||
static void gst_d3d11_window_swap_chain_panel_dispose (GObject * object);
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_update_swap_chain (GstD3D11Window * window);
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_change_fullscreen_mode (GstD3D11Window *
|
||||
window);
|
||||
static gboolean
|
||||
gst_d3d11_window_swap_chain_panel_create_swap_chain (GstD3D11Window * window,
|
||||
DXGI_FORMAT format, guint width, guint height, guint swapchain_flags,
|
||||
IDXGISwapChain ** swap_chain);
|
||||
static GstFlowReturn
|
||||
gst_d3d11_window_swap_chain_panel_present (GstD3D11Window * window,
|
||||
guint present_flags);
|
||||
static gboolean
|
||||
gst_d3d11_window_swap_chain_panel_unlock (GstD3D11Window * window);
|
||||
static gboolean
|
||||
gst_d3d11_window_swap_chain_panel_unlock_stop (GstD3D11Window * window);
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_on_resize (GstD3D11WindowSwapChainPanel *
|
||||
self, guint width, guint height);
|
||||
|
||||
class PanelResizeHandler
|
||||
: public RuntimeClass<RuntimeClassFlags<ClassicCom>,
|
||||
Xaml::ISizeChangedEventHandler>
|
||||
{
|
||||
public:
|
||||
PanelResizeHandler () {}
|
||||
HRESULT RuntimeClassInitialize (GstD3D11WindowSwapChainPanel * listener)
|
||||
{
|
||||
if (!listener)
|
||||
return E_INVALIDARG;
|
||||
|
||||
window = listener;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHOD(Invoke)
|
||||
(IInspectable * sender, Xaml::ISizeChangedEventArgs * args)
|
||||
{
|
||||
if (window) {
|
||||
Size new_size;
|
||||
HRESULT hr = args->get_NewSize(&new_size);
|
||||
if (SUCCEEDED(hr)) {
|
||||
gst_d3d11_window_swap_chain_panel_on_resize (window,
|
||||
new_size.Width, new_size.Height);
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
GstD3D11WindowSwapChainPanel * window;
|
||||
};
|
||||
|
||||
template <typename CB>
|
||||
static HRESULT
|
||||
run_async (const ComPtr<Core::ICoreDispatcher> &dispatcher, HANDLE cancellable,
|
||||
DWORD timeout, CB &&cb)
|
||||
{
|
||||
ComPtr<IAsyncAction> async_action;
|
||||
HRESULT hr;
|
||||
HRESULT async_hr;
|
||||
boolean can_now;
|
||||
DWORD wait_ret;
|
||||
HANDLE event_handle[2];
|
||||
|
||||
hr = dispatcher->get_HasThreadAccess (&can_now);
|
||||
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
return hr;
|
||||
|
||||
if (can_now)
|
||||
return cb ();
|
||||
|
||||
Event event (CreateEventEx (NULL, NULL, CREATE_EVENT_MANUAL_RESET,
|
||||
EVENT_ALL_ACCESS));
|
||||
|
||||
if (!event.IsValid())
|
||||
return E_FAIL;
|
||||
|
||||
auto handler =
|
||||
Callback<Implements<RuntimeClassFlags<ClassicCom>,
|
||||
Core::IDispatchedHandler, FtmBase>>([&async_hr, &cb, &event] {
|
||||
async_hr = cb ();
|
||||
SetEvent (event.Get());
|
||||
return S_OK;
|
||||
});
|
||||
|
||||
hr = dispatcher->RunAsync (Core::CoreDispatcherPriority_Normal, handler.Get(),
|
||||
async_action.GetAddressOf());
|
||||
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
return hr;
|
||||
|
||||
event_handle[0] = event.Get();
|
||||
event_handle[1] = cancellable;
|
||||
|
||||
wait_ret = WaitForMultipleObjects (2, event_handle, FALSE, timeout);
|
||||
if (wait_ret != WAIT_OBJECT_0)
|
||||
return E_FAIL;
|
||||
|
||||
return async_hr;
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
get_panel_size (const ComPtr<Core::ICoreDispatcher> &dispatcher,
|
||||
HANDLE cancellable,
|
||||
const ComPtr<Xaml::Controls::ISwapChainPanel> &panel, Size *size)
|
||||
{
|
||||
ComPtr<Xaml::IUIElement> ui;
|
||||
HRESULT hr = panel.As (&ui);
|
||||
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
return hr;
|
||||
|
||||
hr = run_async (dispatcher, cancellable, DEFAULT_ASYNC_TIMEOUT,
|
||||
[ui, size] {
|
||||
return ui->get_RenderSize (size);
|
||||
});
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_class_init (GstD3D11WindowSwapChainPanelClass
|
||||
* klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstD3D11WindowClass *window_class = GST_D3D11_WINDOW_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = gst_d3d11_window_swap_chain_panel_constructed;
|
||||
gobject_class->dispose = gst_d3d11_window_swap_chain_panel_dispose;
|
||||
|
||||
window_class->update_swap_chain =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_swap_chain_panel_update_swap_chain);
|
||||
window_class->change_fullscreen_mode =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_swap_chain_panel_change_fullscreen_mode);
|
||||
window_class->create_swap_chain =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_swap_chain_panel_create_swap_chain);
|
||||
window_class->present =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_swap_chain_panel_present);
|
||||
window_class->unlock =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_swap_chain_panel_unlock);
|
||||
window_class->unlock_stop =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_swap_chain_panel_unlock_stop);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_init (GstD3D11WindowSwapChainPanel * self)
|
||||
{
|
||||
self->storage = new SwapChainPanelWinRTStorage;
|
||||
self->storage->cancellable = CreateEvent (NULL, TRUE, FALSE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_constructed (GObject * object)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (object);
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (object);
|
||||
SwapChainPanelWinRTStorage *storage = self->storage;
|
||||
HRESULT hr;
|
||||
ComPtr<IInspectable> inspectable;
|
||||
ComPtr<Xaml::IDependencyObject> dependency_obj;
|
||||
Size size;
|
||||
ComPtr<Xaml::ISizeChangedEventHandler> resize_handler;
|
||||
ComPtr<Xaml::IFrameworkElement> framework;
|
||||
|
||||
if (!window->external_handle) {
|
||||
GST_ERROR_OBJECT (self, "No external window handle");
|
||||
return;
|
||||
}
|
||||
|
||||
inspectable = reinterpret_cast<IInspectable*> (window->external_handle);
|
||||
|
||||
hr = inspectable.As (&storage->panel);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = storage->panel.As (&dependency_obj);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = dependency_obj->get_Dispatcher(storage->dispatcher.GetAddressOf());
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = get_panel_size (storage->dispatcher,
|
||||
storage->cancellable, storage->panel, &size);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "client size %dx%d", size.Width, size.Height);
|
||||
window->surface_width = size.Width;
|
||||
window->surface_height = size.Height;
|
||||
|
||||
hr = MakeAndInitialize<PanelResizeHandler>(&resize_handler, self);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = storage->panel.As (&framework);
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
hr = run_async (storage->dispatcher,
|
||||
storage->cancellable, DEFAULT_ASYNC_TIMEOUT,
|
||||
[self, framework, resize_handler] {
|
||||
return framework->add_SizeChanged (resize_handler.Get(),
|
||||
&self->storage->event_token);
|
||||
});
|
||||
if (!gst_d3d11_result (hr, NULL))
|
||||
goto error;
|
||||
|
||||
window->initialized = TRUE;
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
GST_ERROR_OBJECT (self, "Invalid window handle");
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_dispose (GObject * object)
|
||||
{
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (object);
|
||||
SwapChainPanelWinRTStorage *storage = self->storage;
|
||||
|
||||
if (storage) {
|
||||
if (storage->panel && storage->dispatcher) {
|
||||
ComPtr<Xaml::IFrameworkElement> framework;
|
||||
HRESULT hr;
|
||||
|
||||
hr = storage->panel.As (&framework);
|
||||
if (SUCCEEDED (hr)) {
|
||||
run_async (storage->dispatcher,
|
||||
storage->cancellable, DEFAULT_ASYNC_TIMEOUT,
|
||||
[self, framework] {
|
||||
return framework->remove_SizeChanged (self->storage->event_token);
|
||||
});
|
||||
}
|
||||
|
||||
CloseHandle (storage->cancellable);
|
||||
}
|
||||
|
||||
delete storage;
|
||||
}
|
||||
|
||||
self->storage = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_swap_chain_panel_create_swap_chain (GstD3D11Window * window,
|
||||
DXGI_FORMAT format, guint width, guint height, guint swapchain_flags,
|
||||
IDXGISwapChain ** swap_chain)
|
||||
{
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (window);
|
||||
SwapChainPanelWinRTStorage *storage = self->storage;
|
||||
ComPtr<IDXGISwapChain1> new_swapchain;
|
||||
ComPtr<ISwapChainPanelNative> panel_native;
|
||||
GstD3D11Device *device = window->device;
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, };
|
||||
HRESULT hr;
|
||||
|
||||
desc1.Width = width;
|
||||
desc1.Height = height;
|
||||
desc1.Format = format;
|
||||
desc1.Stereo = FALSE;
|
||||
desc1.SampleDesc.Count = 1;
|
||||
desc1.SampleDesc.Quality = 0;
|
||||
desc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc1.BufferCount = 2;
|
||||
desc1.Scaling = DXGI_SCALING_STRETCH;
|
||||
desc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
desc1.AlphaMode = DXGI_ALPHA_MODE_PREMULTIPLIED;
|
||||
desc1.Flags = swapchain_flags;
|
||||
|
||||
new_swapchain =
|
||||
gst_d3d11_device_create_swap_chain_for_composition (device, &desc1, NULL);
|
||||
|
||||
if (!new_swapchain) {
|
||||
GST_ERROR_OBJECT (self, "Cannot create swapchain");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
hr = storage->panel.As (&panel_native);
|
||||
if (!gst_d3d11_result (hr, device))
|
||||
return FALSE;
|
||||
|
||||
hr = run_async (storage->dispatcher,
|
||||
storage->cancellable, DEFAULT_ASYNC_TIMEOUT,
|
||||
[panel_native, new_swapchain] {
|
||||
return panel_native->SetSwapChain(new_swapchain.Get());
|
||||
});
|
||||
|
||||
if (!gst_d3d11_result (hr, device))
|
||||
return FALSE;
|
||||
|
||||
new_swapchain.CopyTo (swap_chain);
|
||||
|
||||
run_async (storage->dispatcher, storage->cancellable, DEFAULT_ASYNC_TIMEOUT,
|
||||
[window] {
|
||||
gst_d3d11_window_on_resize (window,
|
||||
window->surface_width, window->surface_height);
|
||||
return S_OK;
|
||||
});
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d11_window_swap_chain_panel_present (GstD3D11Window * window,
|
||||
guint present_flags)
|
||||
{
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (window);
|
||||
HRESULT hr;
|
||||
DXGI_PRESENT_PARAMETERS present_params = { 0, };
|
||||
IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain;
|
||||
|
||||
/* the first present should not specify dirty-rect */
|
||||
if (!window->first_present) {
|
||||
present_params.DirtyRectsCount = 1;
|
||||
present_params.pDirtyRects = &window->render_rect;
|
||||
}
|
||||
|
||||
hr = swap_chain->Present1 (0, present_flags, &present_params);
|
||||
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
|
||||
(guint) hr);
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_swap_chain_panel_unlock (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (window);
|
||||
SwapChainPanelWinRTStorage *storage = self->storage;
|
||||
|
||||
SetEvent (storage->cancellable);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_swap_chain_panel_unlock_stop (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (window);
|
||||
SwapChainPanelWinRTStorage *storage = self->storage;
|
||||
|
||||
ResetEvent (storage->cancellable);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_update_swap_chain (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowSwapChainPanel *self =
|
||||
GST_D3D11_WINDOW_SWAP_CHAIN_PANEL (window);
|
||||
SwapChainPanelWinRTStorage *storage = self->storage;
|
||||
|
||||
run_async (storage->dispatcher, storage->cancellable, DEFAULT_ASYNC_TIMEOUT,
|
||||
[window] {
|
||||
gst_d3d11_window_on_resize (window,
|
||||
window->surface_width, window->surface_height);
|
||||
return S_OK;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_change_fullscreen_mode (GstD3D11Window *
|
||||
window)
|
||||
{
|
||||
GST_FIXME_OBJECT (window, "Implement fullscreen mode change");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_swap_chain_panel_on_resize (GstD3D11WindowSwapChainPanel *
|
||||
self, guint width, guint height)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (self);
|
||||
window->surface_width = width;
|
||||
window->surface_height = height;
|
||||
|
||||
GST_LOG_OBJECT (self, "New size %dx%d", width, height);
|
||||
|
||||
gst_d3d11_window_on_resize (GST_D3D11_WINDOW (self), width, height);
|
||||
}
|
||||
|
||||
GstD3D11Window *
|
||||
gst_d3d11_window_swap_chain_panel_new (GstD3D11Device * device, guintptr handle)
|
||||
{
|
||||
GstD3D11Window *window;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
|
||||
g_return_val_if_fail (handle, NULL);
|
||||
|
||||
window = (GstD3D11Window *)
|
||||
g_object_new (GST_TYPE_D3D11_WINDOW_SWAP_CHAIN_PANEL,
|
||||
"d3d11device", device, "window-handle", handle, NULL);
|
||||
if (!window->initialized) {
|
||||
gst_object_unref (window);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_ref_sink (window);
|
||||
|
||||
return window;
|
||||
}
|
41
sys/d3d11/gstd3d11window_swapchainpanel.h
Normal file
41
sys/d3d11/gstd3d11window_swapchainpanel.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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.
|
||||
*/
|
||||
|
||||
#ifndef __GST_D3D11_WINDOW_SWAP_CHAIN_PANEL_H__
|
||||
#define __GST_D3D11_WINDOW_SWAP_CHAIN_PANEL_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include "gstd3d11_fwd.h"
|
||||
#include "gstd3d11window.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D11_WINDOW_SWAP_CHAIN_PANEL (gst_d3d11_window_swap_chain_panel_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstD3D11WindowSwapChainPanel,
|
||||
gst_d3d11_window_swap_chain_panel,
|
||||
GST, D3D11_WINDOW_SWAP_CHAIN_PANEL, GstD3D11Window);
|
||||
|
||||
GstD3D11Window * gst_d3d11_window_swap_chain_panel_new (GstD3D11Device * device,
|
||||
guintptr handle);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_D3D11_WINDOW_SWAP_CHAIN_PANEL_H__ */
|
924
sys/d3d11/gstd3d11window_win32.cpp
Normal file
924
sys/d3d11/gstd3d11window_win32.cpp
Normal file
|
@ -0,0 +1,924 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
|
||||
* Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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 "gstd3d11device.h"
|
||||
#include "gstd3d11memory.h"
|
||||
#include "gstd3d11utils.h"
|
||||
#include "gstd3d11window_win32.h"
|
||||
|
||||
extern "C" {
|
||||
GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
|
||||
#define GST_CAT_DEFAULT gst_d3d11_window_debug
|
||||
}
|
||||
|
||||
G_LOCK_DEFINE_STATIC (create_lock);
|
||||
|
||||
#define EXTERNAL_PROC_PROP_NAME "d3d11_window_external_proc"
|
||||
#define D3D11_WINDOW_PROP_NAME "gst_d3d11_window_win32_object"
|
||||
|
||||
#define WM_GST_D3D11_FULLSCREEN (WM_USER + 1)
|
||||
|
||||
static LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
static LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE = 0,
|
||||
GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED,
|
||||
GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED,
|
||||
} GstD3D11WindowWin32OverlayState;
|
||||
|
||||
struct _GstD3D11WindowWin32
|
||||
{
|
||||
GstD3D11Window parent;
|
||||
|
||||
GMutex lock;
|
||||
GCond cond;
|
||||
|
||||
GMainContext *main_context;
|
||||
GMainLoop *loop;
|
||||
|
||||
gboolean visible;
|
||||
|
||||
GSource *msg_source;
|
||||
GIOChannel *msg_io_channel;
|
||||
|
||||
GThread *thread;
|
||||
|
||||
HWND internal_hwnd;
|
||||
HWND external_hwnd;
|
||||
GstD3D11WindowWin32OverlayState overlay_state;
|
||||
|
||||
HDC device_handle;
|
||||
gboolean first_present;
|
||||
gboolean have_swapchain1;
|
||||
|
||||
/* atomic */
|
||||
volatile gint pending_fullscreen_count;
|
||||
|
||||
/* fullscreen related */
|
||||
RECT restore_rect;
|
||||
LONG restore_style;
|
||||
};
|
||||
|
||||
#define gst_d3d11_window_win32_parent_class parent_class
|
||||
G_DEFINE_TYPE (GstD3D11WindowWin32, gst_d3d11_window_win32,
|
||||
GST_TYPE_D3D11_WINDOW);
|
||||
|
||||
static void gst_d3d11_window_win32_constructed (GObject * object);
|
||||
static void gst_d3d11_window_win32_dispose (GObject * object);
|
||||
static void gst_d3d11_window_win32_finalize (GObject * object);
|
||||
|
||||
static void gst_d3d11_window_win32_show (GstD3D11Window * window);
|
||||
static void gst_d3d11_window_win32_update_swap_chain (GstD3D11Window * window);
|
||||
static void
|
||||
gst_d3d11_window_win32_change_fullscreen_mode (GstD3D11Window * window);
|
||||
static gboolean
|
||||
gst_d3d11_window_win32_create_swap_chain (GstD3D11Window * window,
|
||||
DXGI_FORMAT format, guint width, guint height,
|
||||
guint swapchain_flags, IDXGISwapChain ** swap_chain);
|
||||
static GstFlowReturn gst_d3d11_window_win32_present (GstD3D11Window * window,
|
||||
guint present_flags);
|
||||
|
||||
static gpointer gst_d3d11_window_win32_thread_func (gpointer data);
|
||||
static gboolean
|
||||
gst_d3d11_window_win32_create_internal_window (GstD3D11WindowWin32 * self);
|
||||
static void gst_d3d11_window_win32_close_internal_window (GstD3D11WindowWin32 *
|
||||
self);
|
||||
static void gst_d3d11_window_win32_release_external_handle (GstD3D11WindowWin32
|
||||
* self);
|
||||
static void
|
||||
gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
|
||||
guintptr handle);
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_class_init (GstD3D11WindowWin32Class * klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
GstD3D11WindowClass *window_class = GST_D3D11_WINDOW_CLASS (klass);
|
||||
|
||||
gobject_class->constructed = gst_d3d11_window_win32_constructed;
|
||||
gobject_class->dispose = gst_d3d11_window_win32_dispose;
|
||||
gobject_class->finalize = gst_d3d11_window_win32_finalize;
|
||||
|
||||
window_class->show = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_show);
|
||||
window_class->update_swap_chain =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_update_swap_chain);
|
||||
window_class->change_fullscreen_mode =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_change_fullscreen_mode);
|
||||
window_class->create_swap_chain =
|
||||
GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_create_swap_chain);
|
||||
window_class->present = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_present);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_init (GstD3D11WindowWin32 * self)
|
||||
{
|
||||
g_mutex_init (&self->lock);
|
||||
g_cond_init (&self->cond);
|
||||
|
||||
self->main_context = g_main_context_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_constructed (GObject * object)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (object);
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
self->loop = g_main_loop_new (self->main_context, FALSE);
|
||||
self->thread = g_thread_new ("GstD3D11WindowWin32Win32",
|
||||
(GThreadFunc) gst_d3d11_window_win32_thread_func, self);
|
||||
while (!g_main_loop_is_running (self->loop))
|
||||
g_cond_wait (&self->cond, &self->lock);
|
||||
g_mutex_unlock (&self->lock);
|
||||
|
||||
if (window->external_handle)
|
||||
gst_d3d11_window_win32_set_window_handle (self, window->external_handle);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_dispose (GObject * object)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
|
||||
|
||||
gst_d3d11_window_win32_release_external_handle (self);
|
||||
|
||||
if (self->loop) {
|
||||
g_main_loop_quit (self->loop);
|
||||
}
|
||||
|
||||
if (self->thread) {
|
||||
g_thread_join (self->thread);
|
||||
self->thread = NULL;
|
||||
}
|
||||
|
||||
if (self->loop) {
|
||||
g_main_loop_unref (self->loop);
|
||||
self->loop = NULL;
|
||||
}
|
||||
|
||||
if (self->main_context) {
|
||||
g_main_context_unref (self->main_context);
|
||||
self->main_context = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_finalize (GObject * object)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
|
||||
|
||||
g_mutex_clear (&self->lock);
|
||||
g_cond_clear (&self->cond);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
running_cb (gpointer user_data)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (user_data);
|
||||
|
||||
GST_TRACE_OBJECT (self, "Main loop running now");
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
g_cond_signal (&self->cond);
|
||||
g_mutex_unlock (&self->lock);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gst_d3d11_window_win32_thread_func (gpointer data)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (data);
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (data);
|
||||
GSource *source;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Enter loop");
|
||||
g_main_context_push_thread_default (self->main_context);
|
||||
|
||||
window->initialized = gst_d3d11_window_win32_create_internal_window (self);
|
||||
|
||||
source = g_idle_source_new ();
|
||||
g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
|
||||
g_source_attach (source, self->main_context);
|
||||
g_source_unref (source);
|
||||
|
||||
g_main_loop_run (self->loop);
|
||||
|
||||
gst_d3d11_window_win32_close_internal_window (self);
|
||||
|
||||
g_main_context_pop_thread_default (self->main_context);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Exit loop");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
msg_cb (GIOChannel * source, GIOCondition condition, gpointer data)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_close_internal_window (GstD3D11WindowWin32 * self)
|
||||
{
|
||||
if (self->internal_hwnd) {
|
||||
RemoveProp (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
|
||||
ShowWindow (self->internal_hwnd, SW_HIDE);
|
||||
SetParent (self->internal_hwnd, NULL);
|
||||
if (!DestroyWindow (self->internal_hwnd))
|
||||
GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
|
||||
", 0x%x", (guintptr) self->internal_hwnd, (guint) GetLastError ());
|
||||
self->internal_hwnd = NULL;
|
||||
}
|
||||
|
||||
if (self->msg_source) {
|
||||
g_source_destroy (self->msg_source);
|
||||
g_source_unref (self->msg_source);
|
||||
self->msg_source = NULL;
|
||||
}
|
||||
|
||||
if (self->msg_io_channel) {
|
||||
g_io_channel_unref (self->msg_io_channel);
|
||||
self->msg_io_channel = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_set_external_handle (GstD3D11WindowWin32 * self)
|
||||
{
|
||||
WNDPROC external_window_proc;
|
||||
RECT rect;
|
||||
|
||||
if (!self->external_hwnd) {
|
||||
/* no parent so the internal window needs borders and system menu */
|
||||
SetWindowLongPtr (self->internal_hwnd, GWL_STYLE,
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
|
||||
SetParent (self->internal_hwnd, NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
external_window_proc =
|
||||
(WNDPROC) GetWindowLongPtr (self->external_hwnd, GWLP_WNDPROC);
|
||||
|
||||
GST_DEBUG ("set external window %" G_GUINTPTR_FORMAT,
|
||||
(guintptr) self->external_hwnd);
|
||||
|
||||
SetProp (self->external_hwnd, EXTERNAL_PROC_PROP_NAME,
|
||||
(HANDLE) external_window_proc);
|
||||
SetProp (self->external_hwnd, D3D11_WINDOW_PROP_NAME, self);
|
||||
SetWindowLongPtr (self->external_hwnd, GWLP_WNDPROC,
|
||||
(LONG_PTR) sub_class_proc);
|
||||
|
||||
SetWindowLongPtr (self->internal_hwnd, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
|
||||
SetParent (self->internal_hwnd, self->external_hwnd);
|
||||
|
||||
/* take changes into account: SWP_FRAMECHANGED */
|
||||
GetClientRect (self->external_hwnd, &rect);
|
||||
SetWindowPos (self->internal_hwnd, HWND_TOP, rect.left, rect.top,
|
||||
rect.right, rect.bottom,
|
||||
SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
|
||||
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
MoveWindow (self->internal_hwnd, rect.left, rect.top, rect.right,
|
||||
rect.bottom, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_release_external_handle (GstD3D11WindowWin32 * self)
|
||||
{
|
||||
WNDPROC external_proc;
|
||||
|
||||
if (!self->external_hwnd)
|
||||
return;
|
||||
|
||||
external_proc =
|
||||
(WNDPROC) GetProp (self->external_hwnd, EXTERNAL_PROC_PROP_NAME);
|
||||
if (!external_proc)
|
||||
return;
|
||||
|
||||
GST_DEBUG ("release external window %" G_GUINTPTR_FORMAT,
|
||||
(guintptr) self->external_hwnd);
|
||||
|
||||
SetWindowLongPtr (self->external_hwnd,
|
||||
GWLP_WNDPROC, (LONG_PTR) external_proc);
|
||||
|
||||
RemoveProp (self->external_hwnd, EXTERNAL_PROC_PROP_NAME);
|
||||
RemoveProp (self->external_hwnd, D3D11_WINDOW_PROP_NAME);
|
||||
self->external_hwnd = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_win32_create_internal_window (GstD3D11WindowWin32 * self)
|
||||
{
|
||||
WNDCLASSEX wc;
|
||||
ATOM atom = 0;
|
||||
HINSTANCE hinstance = GetModuleHandle (NULL);
|
||||
|
||||
GST_LOG_OBJECT (self, "Attempting to create a win32 window");
|
||||
|
||||
G_LOCK (create_lock);
|
||||
atom = GetClassInfoEx (hinstance, "GSTD3D11", &wc);
|
||||
if (atom == 0) {
|
||||
GST_LOG_OBJECT (self, "Register internal window class");
|
||||
ZeroMemory (&wc, sizeof (WNDCLASSEX));
|
||||
|
||||
wc.cbSize = sizeof (WNDCLASSEX);
|
||||
wc.lpfnWndProc = window_proc;
|
||||
wc.hInstance = hinstance;
|
||||
wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
|
||||
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
||||
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
|
||||
wc.lpszClassName = "GSTD3D11";
|
||||
|
||||
atom = RegisterClassEx (&wc);
|
||||
|
||||
if (atom == 0) {
|
||||
G_UNLOCK (create_lock);
|
||||
GST_ERROR_OBJECT (self, "Failed to register window class 0x%x",
|
||||
(unsigned int) GetLastError ());
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
GST_LOG_OBJECT (self, "window class was already registered");
|
||||
}
|
||||
|
||||
self->device_handle = 0;
|
||||
self->internal_hwnd = 0;
|
||||
self->visible = FALSE;
|
||||
|
||||
self->internal_hwnd = CreateWindowEx (0,
|
||||
"GSTD3D11",
|
||||
"Direct3D11 renderer",
|
||||
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
0, 0, (HWND) NULL, (HMENU) NULL, hinstance, self);
|
||||
|
||||
G_UNLOCK (create_lock);
|
||||
|
||||
if (!self->internal_hwnd) {
|
||||
GST_ERROR_OBJECT (self, "Failed to create d3d11 window");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "d3d11 window created: %" G_GUINTPTR_FORMAT,
|
||||
(guintptr) self->internal_hwnd);
|
||||
|
||||
/* device_handle is set in the window_proc */
|
||||
if (!self->device_handle) {
|
||||
GST_ERROR_OBJECT (self, "device handle is not available");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
GST_LOG_OBJECT (self,
|
||||
"Created a internal d3d11 window %p", self->internal_hwnd);
|
||||
|
||||
self->msg_io_channel =
|
||||
g_io_channel_win32_new_messages ((guintptr) self->internal_hwnd);
|
||||
self->msg_source = g_io_create_watch (self->msg_io_channel, G_IO_IN);
|
||||
g_source_set_callback (self->msg_source, (GSourceFunc) msg_cb, self, NULL);
|
||||
g_source_attach (self->msg_source, self->main_context);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* always called from window thread */
|
||||
static void
|
||||
gst_d3d11_window_win32_change_fullscreen_mode_internal (GstD3D11WindowWin32 *
|
||||
self)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (self);
|
||||
HWND hwnd = self->external_hwnd ? self->external_hwnd : self->internal_hwnd;
|
||||
|
||||
if (!window->swap_chain)
|
||||
return;
|
||||
|
||||
if (window->requested_fullscreen == window->fullscreen)
|
||||
return;
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Change mode to %s",
|
||||
window->requested_fullscreen ? "fullscreen" : "windowed");
|
||||
|
||||
window->fullscreen = !window->fullscreen;
|
||||
|
||||
if (!window->fullscreen) {
|
||||
/* Restore the window's attributes and size */
|
||||
SetWindowLong (hwnd, GWL_STYLE, self->restore_style);
|
||||
|
||||
SetWindowPos (hwnd, HWND_NOTOPMOST,
|
||||
self->restore_rect.left,
|
||||
self->restore_rect.top,
|
||||
self->restore_rect.right - self->restore_rect.left,
|
||||
self->restore_rect.bottom - self->restore_rect.top,
|
||||
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
|
||||
ShowWindow (hwnd, SW_NORMAL);
|
||||
} else {
|
||||
IDXGIOutput *output;
|
||||
DXGI_OUTPUT_DESC output_desc;
|
||||
IDXGISwapChain *swap_chain = window->swap_chain;
|
||||
|
||||
/* show window before change style */
|
||||
ShowWindow (hwnd, SW_SHOW);
|
||||
|
||||
/* Save the old window rect so we can restore it when exiting
|
||||
* fullscreen mode */
|
||||
GetWindowRect (hwnd, &self->restore_rect);
|
||||
self->restore_style = GetWindowLong (hwnd, GWL_STYLE);
|
||||
|
||||
/* Make the window borderless so that the client area can fill the screen */
|
||||
SetWindowLong (hwnd, GWL_STYLE,
|
||||
self->restore_style &
|
||||
~(WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
|
||||
WS_THICKFRAME));
|
||||
|
||||
swap_chain->GetContainingOutput (&output);
|
||||
output->GetDesc (&output_desc);
|
||||
output->Release ();
|
||||
|
||||
SetWindowPos (hwnd, HWND_TOPMOST,
|
||||
output_desc.DesktopCoordinates.left,
|
||||
output_desc.DesktopCoordinates.top,
|
||||
output_desc.DesktopCoordinates.right,
|
||||
output_desc.DesktopCoordinates.bottom,
|
||||
SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
||||
|
||||
ShowWindow (hwnd, SW_MAXIMIZE);
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Fullscreen mode change done");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_on_key_event (GstD3D11WindowWin32 * self,
|
||||
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (self);
|
||||
gunichar2 wcrep[128];
|
||||
const gchar *event;
|
||||
|
||||
if (!window->enable_navigation_events)
|
||||
return;
|
||||
|
||||
if (GetKeyNameTextW (lParam, (LPWSTR) wcrep, 128)) {
|
||||
gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
|
||||
if (utfrep) {
|
||||
if (uMsg == WM_KEYDOWN)
|
||||
event = "key-press";
|
||||
else
|
||||
event = "key-release";
|
||||
|
||||
gst_d3d11_window_on_key_event (window, event, utfrep);
|
||||
g_free (utfrep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_on_mouse_event (GstD3D11WindowWin32 * self,
|
||||
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (self);
|
||||
gint button;
|
||||
const gchar *event = NULL;
|
||||
|
||||
if (!window->enable_navigation_events)
|
||||
return;
|
||||
|
||||
/* FIXME: convert to render coordinate */
|
||||
switch (uMsg) {
|
||||
case WM_MOUSEMOVE:
|
||||
button = 0;
|
||||
event = "mouse-move";
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
button = 1;
|
||||
event = "mouse-button-press";
|
||||
break;
|
||||
case WM_LBUTTONUP:
|
||||
button = 1;
|
||||
event = "mouse-button-release";
|
||||
break;
|
||||
case WM_RBUTTONDOWN:
|
||||
button = 2;
|
||||
event = "mouse-button-press";
|
||||
break;
|
||||
case WM_RBUTTONUP:
|
||||
button = 2;
|
||||
event = "mouse-button-release";
|
||||
break;
|
||||
case WM_MBUTTONDOWN:
|
||||
button = 3;
|
||||
event = "mouse-button-press";
|
||||
break;
|
||||
case WM_MBUTTONUP:
|
||||
button = 3;
|
||||
event = "mouse-button-release";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (event)
|
||||
gst_d3d11_window_on_mouse_event (window,
|
||||
event, button, (gdouble) LOWORD (lParam), (gdouble) HIWORD (lParam));
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_handle_window_proc (GstD3D11WindowWin32 * self,
|
||||
HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
GstD3D11Window *window = GST_D3D11_WINDOW (self);
|
||||
|
||||
switch (uMsg) {
|
||||
case WM_SIZE:
|
||||
gst_d3d11_window_on_resize (window, 0, 0);
|
||||
break;
|
||||
case WM_CLOSE:
|
||||
if (self->internal_hwnd) {
|
||||
ShowWindow (self->internal_hwnd, SW_HIDE);
|
||||
gst_d3d11_window_win32_close_internal_window (self);
|
||||
}
|
||||
break;
|
||||
case WM_KEYDOWN:
|
||||
case WM_KEYUP:
|
||||
gst_d3d11_window_win32_on_key_event (self, hWnd, uMsg, wParam, lParam);
|
||||
break;
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_LBUTTONUP:
|
||||
case WM_RBUTTONDOWN:
|
||||
case WM_RBUTTONUP:
|
||||
case WM_MBUTTONDOWN:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MOUSEMOVE:
|
||||
gst_d3d11_window_win32_on_mouse_event (self, hWnd, uMsg, wParam, lParam);
|
||||
break;
|
||||
case WM_SYSKEYDOWN:
|
||||
if ((window->fullscreen_toggle_mode &
|
||||
GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER)
|
||||
== GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER) {
|
||||
WORD state = GetKeyState (VK_RETURN);
|
||||
BYTE high = HIBYTE (state);
|
||||
|
||||
if (high & 0x1) {
|
||||
window->requested_fullscreen = !window->fullscreen;
|
||||
gst_d3d11_window_win32_change_fullscreen_mode_internal (self);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_GST_D3D11_FULLSCREEN:
|
||||
if (g_atomic_int_get (&self->pending_fullscreen_count)) {
|
||||
g_atomic_int_dec_and_test (&self->pending_fullscreen_count);
|
||||
if ((window->fullscreen_toggle_mode &
|
||||
GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
|
||||
== GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
|
||||
gst_d3d11_window_win32_change_fullscreen_mode_internal (self);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK
|
||||
window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
GstD3D11WindowWin32 *self;
|
||||
|
||||
if (uMsg == WM_CREATE) {
|
||||
self = GST_D3D11_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams);
|
||||
|
||||
GST_LOG_OBJECT (self, "WM_CREATE");
|
||||
|
||||
self->device_handle = GetDC (hWnd);
|
||||
/* Do this, otherwise we hang on exit. We can still use it (due to the
|
||||
* CS_OWNDC flag in the WindowClass) after we have Released.
|
||||
*/
|
||||
ReleaseDC (hWnd, self->device_handle);
|
||||
|
||||
SetProp (hWnd, D3D11_WINDOW_PROP_NAME, self);
|
||||
} else if (GetProp (hWnd, D3D11_WINDOW_PROP_NAME)) {
|
||||
self = GST_D3D11_WINDOW_WIN32 (GetProp (hWnd, D3D11_WINDOW_PROP_NAME));
|
||||
|
||||
g_assert (self->internal_hwnd == hWnd);
|
||||
|
||||
gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
|
||||
lParam);
|
||||
}
|
||||
|
||||
if (uMsg == WM_SIZE)
|
||||
return 0;
|
||||
|
||||
return DefWindowProc (hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT FAR PASCAL
|
||||
sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
WNDPROC external_window_proc =
|
||||
(WNDPROC) GetProp (hWnd, EXTERNAL_PROC_PROP_NAME);
|
||||
GstD3D11WindowWin32 *self =
|
||||
(GstD3D11WindowWin32 *) GetProp (hWnd, D3D11_WINDOW_PROP_NAME);
|
||||
|
||||
if (uMsg == WM_SIZE) {
|
||||
MoveWindow (self->internal_hwnd, 0, 0, LOWORD (lParam), HIWORD (lParam),
|
||||
FALSE);
|
||||
} else if (uMsg == WM_CLOSE || uMsg == WM_DESTROY) {
|
||||
g_mutex_lock (&self->lock);
|
||||
GST_WARNING_OBJECT (self, "external window is closing");
|
||||
gst_d3d11_window_win32_release_external_handle (self);
|
||||
self->external_hwnd = NULL;
|
||||
self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED;
|
||||
g_mutex_unlock (&self->lock);
|
||||
} else {
|
||||
gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
|
||||
lParam);
|
||||
}
|
||||
|
||||
return CallWindowProc (external_window_proc, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_disable_alt_enter (GstD3D11WindowWin32 * self,
|
||||
GstD3D11Device * device, IDXGISwapChain * swap_chain, HWND hwnd)
|
||||
{
|
||||
IDXGIFactory1 *factory = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
hr = swap_chain->GetParent (IID_IDXGIFactory1, (void **) &factory);
|
||||
if (!gst_d3d11_result (hr, device) || !factory) {
|
||||
GST_WARNING_OBJECT (self,
|
||||
"Cannot get parent dxgi factory for swapchain %p, hr: 0x%x",
|
||||
swap_chain, (guint) hr);
|
||||
return;
|
||||
}
|
||||
|
||||
hr = factory->MakeWindowAssociation (hwnd, DXGI_MWA_NO_ALT_ENTER);
|
||||
if (!gst_d3d11_result (hr, device)) {
|
||||
GST_WARNING_OBJECT (self,
|
||||
"MakeWindowAssociation failure, hr: 0x%x", (guint) hr);
|
||||
}
|
||||
|
||||
factory->Release ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_d3d11_window_win32_create_swap_chain (GstD3D11Window * window,
|
||||
DXGI_FORMAT format, guint width, guint height,
|
||||
guint swapchain_flags, IDXGISwapChain ** swap_chain)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
|
||||
DXGI_SWAP_CHAIN_DESC desc = { 0, };
|
||||
DXGI_SWAP_EFFECT swap_effect = DXGI_SWAP_EFFECT_DISCARD;
|
||||
IDXGISwapChain *new_swapchain = NULL;
|
||||
GstD3D11Device *device = window->device;
|
||||
|
||||
if (gst_d3d11_is_windows_8_or_greater ())
|
||||
swap_effect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||
|
||||
self->have_swapchain1 = FALSE;
|
||||
|
||||
#if (DXGI_HEADER_VERSION >= 2)
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, };
|
||||
desc1.Width = 0;
|
||||
desc1.Height = 0;
|
||||
desc1.Format = format;
|
||||
/* FIXME: add support stereo */
|
||||
desc1.Stereo = FALSE;
|
||||
desc1.SampleDesc.Count = 1;
|
||||
desc1.SampleDesc.Quality = 0;
|
||||
desc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc1.BufferCount = 2;
|
||||
desc1.Scaling = DXGI_SCALING_STRETCH;
|
||||
|
||||
/* scaling-stretch would break aspect-ratio so we prefer to use scaling-none,
|
||||
* but Windows7 does not support this method */
|
||||
if (gst_d3d11_is_windows_8_or_greater ())
|
||||
desc1.Scaling = DXGI_SCALING_NONE;
|
||||
desc1.SwapEffect = swap_effect;
|
||||
desc1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
|
||||
desc1.Flags = swapchain_flags;
|
||||
|
||||
new_swapchain = (IDXGISwapChain *)
|
||||
gst_d3d11_device_create_swap_chain_for_hwnd (device,
|
||||
self->internal_hwnd, &desc1, NULL, NULL);
|
||||
|
||||
if (!new_swapchain) {
|
||||
GST_WARNING_OBJECT (self, "Failed to create swapchain1");
|
||||
} else {
|
||||
self->have_swapchain1 = TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!new_swapchain) {
|
||||
/* we will get client area at on_resize */
|
||||
desc.BufferDesc.Width = 0;
|
||||
desc.BufferDesc.Height = 0;
|
||||
/* don't care refresh rate */
|
||||
desc.BufferDesc.RefreshRate.Numerator = 0;
|
||||
desc.BufferDesc.RefreshRate.Denominator = 1;
|
||||
desc.BufferDesc.Format = format;
|
||||
desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||
desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc.BufferCount = 2;
|
||||
desc.SwapEffect = swap_effect;
|
||||
desc.OutputWindow = self->internal_hwnd;
|
||||
desc.Windowed = TRUE;
|
||||
desc.Flags = swapchain_flags;
|
||||
|
||||
new_swapchain = gst_d3d11_device_create_swap_chain (device, &desc);
|
||||
}
|
||||
|
||||
if (!new_swapchain) {
|
||||
GST_ERROR_OBJECT (self, "Cannot create swapchain");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* disable alt+enter here. It should be manually handled */
|
||||
gst_d3d11_device_lock (device);
|
||||
gst_d3d11_window_win32_disable_alt_enter (self,
|
||||
device, new_swapchain, desc.OutputWindow);
|
||||
gst_d3d11_device_unlock (device);
|
||||
|
||||
*swap_chain = new_swapchain;
|
||||
|
||||
gst_d3d11_window_on_resize (window, width, height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
|
||||
guintptr handle)
|
||||
{
|
||||
self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE;
|
||||
|
||||
if (self->visible) {
|
||||
ShowWindow (self->internal_hwnd, SW_HIDE);
|
||||
self->visible = FALSE;
|
||||
}
|
||||
|
||||
gst_d3d11_window_win32_release_external_handle (self);
|
||||
self->external_hwnd = (HWND) handle;
|
||||
gst_d3d11_window_win32_set_external_handle (self);
|
||||
|
||||
if (self->external_hwnd)
|
||||
self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_show (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
|
||||
gint width, height;
|
||||
|
||||
width = window->width;
|
||||
height = window->height;
|
||||
|
||||
if (!self->visible) {
|
||||
/* if no parent the real size has to be set now because this has not been done
|
||||
* when at window creation */
|
||||
if (!self->external_hwnd) {
|
||||
RECT rect;
|
||||
GetClientRect (self->internal_hwnd, &rect);
|
||||
width += 2 * GetSystemMetrics (SM_CXSIZEFRAME);
|
||||
height +=
|
||||
2 * GetSystemMetrics (SM_CYSIZEFRAME) +
|
||||
GetSystemMetrics (SM_CYCAPTION);
|
||||
MoveWindow (self->internal_hwnd, rect.left, rect.top, width,
|
||||
height, FALSE);
|
||||
}
|
||||
|
||||
ShowWindow (self->internal_hwnd, SW_SHOW);
|
||||
self->visible = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_d3d11_window_win32_present (GstD3D11Window * window, guint present_flags)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
|
||||
HRESULT hr;
|
||||
|
||||
if ((!self->external_hwnd &&
|
||||
self->overlay_state == GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED)
|
||||
|| !self->internal_hwnd) {
|
||||
GST_ERROR_OBJECT (self, "Output window was closed");
|
||||
|
||||
return GST_D3D11_WINDOW_FLOW_CLOSED;
|
||||
}
|
||||
|
||||
#if (DXGI_HEADER_VERSION >= 2)
|
||||
if (self->have_swapchain1) {
|
||||
IDXGISwapChain1 *swap_chain1 = (IDXGISwapChain1 *) window->swap_chain;
|
||||
DXGI_PRESENT_PARAMETERS present_params = { 0, };
|
||||
|
||||
/* the first present should not specify dirty-rect */
|
||||
if (!window->first_present) {
|
||||
present_params.DirtyRectsCount = 1;
|
||||
present_params.pDirtyRects = &window->render_rect;
|
||||
}
|
||||
|
||||
hr = swap_chain1->Present1 (0, present_flags, &present_params);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
hr = window->swap_chain->Present (0, present_flags);
|
||||
}
|
||||
|
||||
if (!gst_d3d11_result (hr, window->device)) {
|
||||
GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
|
||||
(guint) hr);
|
||||
}
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_update_swap_chain (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
|
||||
|
||||
if (self->internal_hwnd)
|
||||
PostMessage (self->internal_hwnd, WM_SIZE, 0, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_d3d11_window_win32_change_fullscreen_mode (GstD3D11Window * window)
|
||||
{
|
||||
GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
|
||||
|
||||
if (self->internal_hwnd) {
|
||||
g_atomic_int_add (&self->pending_fullscreen_count, 1);
|
||||
PostMessage (self->internal_hwnd, WM_GST_D3D11_FULLSCREEN, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
GstD3D11Window *
|
||||
gst_d3d11_window_win32_new (GstD3D11Device * device, guintptr handle)
|
||||
{
|
||||
GstD3D11Window *window;
|
||||
|
||||
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
|
||||
|
||||
window = (GstD3D11Window *) g_object_new (GST_TYPE_D3D11_WINDOW_WIN32,
|
||||
"d3d11device", device, "window-handle", handle, NULL);
|
||||
if (!window->initialized) {
|
||||
gst_object_unref (window);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_ref_sink (window);
|
||||
|
||||
return window;
|
||||
}
|
40
sys/d3d11/gstd3d11window_win32.h
Normal file
40
sys/d3d11/gstd3d11window_win32.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* GStreamer
|
||||
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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.
|
||||
*/
|
||||
|
||||
#ifndef __GST_D3D11_WINDOW_WIN32_H__
|
||||
#define __GST_D3D11_WINDOW_WIN32_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/video/video.h>
|
||||
#include "gstd3d11_fwd.h"
|
||||
#include "gstd3d11window.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_D3D11_WINDOW_WIN32 (gst_d3d11_window_win32_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstD3D11WindowWin32,
|
||||
gst_d3d11_window_win32, GST, D3D11_WINDOW_WIN32, GstD3D11Window);
|
||||
|
||||
GstD3D11Window * gst_d3d11_window_win32_new (GstD3D11Device * device,
|
||||
guintptr handle);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_D3D11_WINDOW_WIN32_H__ */
|
|
@ -4,7 +4,7 @@ d3d11_sources = [
|
|||
'gstd3d11memory.c',
|
||||
'gstd3d11utils.c',
|
||||
'gstd3d11videosink.c',
|
||||
'gstd3d11window.c',
|
||||
'gstd3d11window.cpp',
|
||||
'plugin.c',
|
||||
'gstd3d11format.c',
|
||||
'gstd3d11basefilter.c',
|
||||
|
@ -44,6 +44,8 @@ extra_c_args = ['-DCOBJMACROS']
|
|||
have_dxgi_header = false
|
||||
have_d3d11sdk_h = false
|
||||
have_dxgidebug_h = false
|
||||
winapi_desktop = false
|
||||
winapi_app = false
|
||||
extra_dep = []
|
||||
d3d11_conf = configuration_data()
|
||||
|
||||
|
@ -55,6 +57,7 @@ endif
|
|||
d3d11_lib = cc.find_library('d3d11', required : d3d11_option)
|
||||
dxgi_lib = cc.find_library('dxgi', required : d3d11_option)
|
||||
d3dcompiler_lib = cc.find_library('d3dcompiler', required: d3d11_option)
|
||||
runtimeobject_lib = cc.find_library('runtimeobject', required : false)
|
||||
|
||||
foreach dxgi_h: dxgi_headers
|
||||
if not have_dxgi_header and cc.has_header(dxgi_h[0])
|
||||
|
@ -112,14 +115,52 @@ if cc.has_header('dxva.h') and cc.has_header('d3d9.h')
|
|||
extra_dep += [gstcodecparsers_dep]
|
||||
endif
|
||||
|
||||
winapi_desktop = cxx.compiles('''#include <winapifamily.h>
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
#error "not win32"
|
||||
#endif''',
|
||||
dependencies: [d3d11_lib, dxgi_lib],
|
||||
name: 'checking if building for Win32')
|
||||
|
||||
if runtimeobject_lib.found()
|
||||
winapi_app = cxx.compiles('''#include <winapifamily.h>
|
||||
#include <windows.applicationmodel.core.h>
|
||||
#include <wrl.h>
|
||||
#include <wrl/wrappers/corewrappers.h>
|
||||
#include <d3d11.h>
|
||||
#include <dxgi1_2.h>
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
#error "not winrt"
|
||||
#endif''',
|
||||
dependencies: [d3d11_lib, dxgi_lib, runtimeobject_lib],
|
||||
name: 'checking if building for WinRT')
|
||||
endif
|
||||
|
||||
if not winapi_desktop and not winapi_app
|
||||
error('Neither Desktop partition nor App partition')
|
||||
endif
|
||||
|
||||
winapi_app_only = winapi_app and not winapi_desktop
|
||||
|
||||
if winapi_app_only
|
||||
d3d11_sources += ['gstd3d11window_corewindow.cpp',
|
||||
'gstd3d11window_swapchainpanel.cpp']
|
||||
extra_dep += [runtimeobject_lib]
|
||||
else
|
||||
d3d11_sources += ['gstd3d11window_win32.cpp']
|
||||
endif
|
||||
|
||||
d3d11_conf.set10('GST_D3D11_WINAPI_ONLY_APP', winapi_app_only)
|
||||
|
||||
configure_file(
|
||||
output: 'd3d11config.h',
|
||||
output: 'gstd3d11config.h',
|
||||
configuration: d3d11_conf,
|
||||
)
|
||||
|
||||
gstd3d11 = library('gstd3d11',
|
||||
d3d11_sources,
|
||||
c_args : gst_plugins_bad_args + extra_c_args,
|
||||
cpp_args: gst_plugins_bad_args,
|
||||
include_directories : [configinc],
|
||||
dependencies : [gstbase_dep, gstvideo_dep, d3d11_lib, dxgi_lib, d3dcompiler_lib] + extra_dep,
|
||||
install : true,
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "d3d11config.h"
|
||||
#include "gstd3d11config.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "gstd3d11videosink.h"
|
||||
|
@ -42,6 +42,7 @@ GST_DEBUG_CATEGORY (gst_d3d11_utils_debug);
|
|||
GST_DEBUG_CATEGORY (gst_d3d11_format_debug);
|
||||
GST_DEBUG_CATEGORY (gst_d3d11_device_debug);
|
||||
GST_DEBUG_CATEGORY (gst_d3d11_overlay_compositor_debug);
|
||||
GST_DEBUG_CATEGORY (gst_d3d11_window_debug);
|
||||
|
||||
#if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H)
|
||||
GST_DEBUG_CATEGORY (gst_d3d11_debug_layer_debug);
|
||||
|
@ -68,6 +69,8 @@ plugin_init (GstPlugin * plugin)
|
|||
"d3d11device", 0, "d3d11 device object");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_d3d11_overlay_compositor_debug,
|
||||
"d3d11overlaycompositor", 0, "d3d11overlaycompositor");
|
||||
GST_DEBUG_CATEGORY_INIT (gst_d3d11_window_debug,
|
||||
"d3d11window", 0, "d3d11window");
|
||||
|
||||
#if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H)
|
||||
/* NOTE: enabled only for debug build */
|
||||
|
|
Loading…
Reference in a new issue