Initial UWP support via new window (CoreWindow and SwapChainPanel) implementation.
#define __GST_D3D11_FWD_H__
#include <gst/gst.h>
-#include "d3d11config.h"
+#include "gstd3d11config.h"
#ifndef INITGUID
#include <initguid.h>
#include "config.h"
#endif
-#include "d3d11config.h"
-
#include "gstd3d11device.h"
#include "gstd3d11utils.h"
#include "gmodule.h"
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
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,
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;
}
}
#if (DXGI_HEADER_VERSION >= 2)
+#if (!GST_D3D11_WINAPI_ONLY_APP)
/**
* gst_d3d11_device_create_swap_chain_for_hwnd:
* @device: a #GstD3D11Device
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:
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,
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);
#include "config.h"
#endif
-#include "d3d11config.h"
-
#include "gstd3d11utils.h"
#include "gstd3d11device.h"
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);
}
#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,
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);
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);
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;
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),
}
}
-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");
return FALSE;
}
- self->window = gst_d3d11_window_new (self->device);
- if (!self->window) {
- GST_ERROR_OBJECT (sink, "Cannot create d3d11window");
+ 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
- g_object_get (self->device, "hardware", &is_hardware, NULL);
+ 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 (!is_hardware) {
- GST_WARNING_OBJECT (self, "D3D11 device is running on software emulation");
- self->can_convert = FALSE;
- } else {
- self->can_convert = TRUE;
+ 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_signal_connect (self->window, "got-window-handle",
- G_CALLBACK (gst_d3d11_video_sink_got_window_handle), self);
+
+ g_object_get (self->device, "hardware", &is_hardware, NULL);
+
+ if (!is_hardware) {
+ GST_WARNING_OBJECT (self, "D3D11 device is running on software emulation");
+ self->can_convert = FALSE;
+ } else {
+ self->can_convert = TRUE;
+ }
return TRUE;
}
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;
}
+++ /dev/null
-/*
- * 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 "d3d11config.h"
-
-#include "gstd3d11window.h"
-#include "gstd3d11device.h"
-#include "gstd3d11memory.h"
-#include "gstd3d11utils.h"
-
-#include <windows.h>
-
-G_LOCK_DEFINE_STATIC (create_lock);
-
-enum
-{
- PROP_0,
- PROP_D3D11_DEVICE,
- PROP_FORCE_ASPECT_RATIO,
- PROP_ENABLE_NAVIGATION_EVENTS,
- PROP_FULLSCREEN_TOGGLE_MODE,
- PROP_FULLSCREEN,
-};
-
-#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_GOT_WINDOW_HANDLE,
- 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 EXTERNAL_PROC_PROP_NAME "d3d11_window_external_proc"
-#define D3D11_WINDOW_PROP_NAME "gst_d3d11_window_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);
-
-GST_DEBUG_CATEGORY_STATIC (gst_d3d11_window_debug);
-#define GST_CAT_DEFAULT gst_d3d11_window_debug
-
-#define gst_d3d11_window_parent_class parent_class
-G_DEFINE_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_constructed (GObject * object);
-static void gst_d3d11_window_dispose (GObject * object);
-static void gst_d3d11_window_finalize (GObject * object);
-static gpointer gst_d3d11_window_thread_func (gpointer data);
-static gboolean gst_d3d11_window_create_internal_window (GstD3D11Window * self);
-static void gst_d3d11_window_close_internal_window (GstD3D11Window * self);
-static void release_external_win_id (GstD3D11Window * self);
-static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
- GstBuffer * buffer);
-static void gst_d3d11_window_change_fullscreen_mode (GstD3D11Window * self);
-
-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->constructed = gst_d3d11_window_constructed;
- gobject_class->dispose = gst_d3d11_window_dispose;
- gobject_class->finalize = gst_d3d11_window_finalize;
-
- 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,
- 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,
- 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,
- 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,
- 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, G_PARAM_READWRITE | 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);
-
- d3d11_window_signals[SIGNAL_GOT_WINDOW_HANDLE] =
- g_signal_new ("got-window-handle", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_POINTER);
-
- GST_DEBUG_CATEGORY_INIT (gst_d3d11_window_debug, "d3d11window", 0,
- "d3d11 window");
-}
-
-static void
-gst_d3d11_window_init (GstD3D11Window * self)
-{
- g_mutex_init (&self->lock);
- g_cond_init (&self->cond);
-
- self->main_context = g_main_context_new ();
-
- 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;
-
- GST_TRACE_OBJECT (self, "Initialized");
-}
-
-static void
-gst_d3d11_window_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstD3D11Window *self = GST_D3D11_WINDOW (object);
-
- GST_OBJECT_LOCK (self);
- switch (prop_id) {
- case PROP_D3D11_DEVICE:
- self->device = g_value_dup_object (value);
- break;
- case PROP_FORCE_ASPECT_RATIO:
- {
- gboolean force_aspect_ratio;
-
- force_aspect_ratio = g_value_get_boolean (value);
- if (force_aspect_ratio != self->force_aspect_ratio) {
- self->force_aspect_ratio = force_aspect_ratio;
- PostMessage (self->internal_win_id, WM_SIZE, 0, 0);
- }
- 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 = g_value_get_flags (value);
- break;
- case PROP_FULLSCREEN:
- {
- self->requested_fullscreen = g_value_get_boolean (value);
- if (self->swap_chain) {
- g_atomic_int_add (&self->pending_fullscreen_count, 1);
- PostMessage (self->internal_win_id, WM_GST_D3D11_FULLSCREEN, 0, 0);
- }
- break;
- }
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-
- GST_OBJECT_UNLOCK (self);
-}
-
-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_constructed (GObject * object)
-{
- GstD3D11Window *self = GST_D3D11_WINDOW (object);
-
- g_mutex_lock (&self->lock);
- self->loop = g_main_loop_new (self->main_context, FALSE);
- self->thread = g_thread_new ("GstD3D11Window",
- (GThreadFunc) gst_d3d11_window_thread_func, self);
- while (!g_main_loop_is_running (self->loop))
- g_cond_wait (&self->cond, &self->lock);
- g_mutex_unlock (&self->lock);
-}
-
-static void
-gst_d3d11_window_release_resources (GstD3D11Device * device,
- GstD3D11Window * window)
-{
- if (window->rtv) {
- ID3D11RenderTargetView_Release (window->rtv);
- window->rtv = NULL;
- }
-
- if (window->swap_chain) {
- IDXGISwapChain_Release (window->swap_chain);
- window->swap_chain = NULL;
- }
-}
-
-static void
-gst_d3d11_window_dispose (GObject * object)
-{
- GstD3D11Window *self = GST_D3D11_WINDOW (object);
-
- release_external_win_id (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;
- }
-
- 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);
-}
-
-static void
-gst_d3d11_window_finalize (GObject * object)
-{
- GstD3D11Window *self = GST_D3D11_WINDOW (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)
-{
- GstD3D11Window *self = GST_D3D11_WINDOW (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_thread_func (gpointer data)
-{
- GstD3D11Window *self = GST_D3D11_WINDOW (data);
- GSource *source;
-
- GST_DEBUG_OBJECT (self, "Enter loop");
- g_main_context_push_thread_default (self->main_context);
-
- self->created = gst_d3d11_window_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_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_close_internal_window (GstD3D11Window * self)
-{
- if (self->internal_win_id) {
- RemoveProp (self->internal_win_id, D3D11_WINDOW_PROP_NAME);
- ShowWindow (self->internal_win_id, SW_HIDE);
- SetParent (self->internal_win_id, NULL);
- if (!DestroyWindow (self->internal_win_id))
- GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
- ", 0x%x", (guintptr) self->internal_win_id, (guint) GetLastError ());
- self->internal_win_id = 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
-set_external_win_id (GstD3D11Window * self)
-{
- WNDPROC external_window_proc;
- RECT rect;
-
- if (!self->external_win_id) {
- /* no parent so the internal window needs borders and system menu */
- SetWindowLongPtr (self->internal_win_id, GWL_STYLE,
- WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW);
- SetParent (self->internal_win_id, NULL);
-
- return;
- }
-
- external_window_proc =
- (WNDPROC) GetWindowLongPtr (self->external_win_id, GWLP_WNDPROC);
-
- GST_DEBUG ("set external window %" G_GUINTPTR_FORMAT,
- (guintptr) self->external_win_id);
-
- SetProp (self->external_win_id, EXTERNAL_PROC_PROP_NAME,
- (WNDPROC) external_window_proc);
- SetProp (self->external_win_id, D3D11_WINDOW_PROP_NAME, self);
- SetWindowLongPtr (self->external_win_id, GWLP_WNDPROC,
- (LONG_PTR) sub_class_proc);
-
- SetWindowLongPtr (self->internal_win_id, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
- SetParent (self->internal_win_id, self->external_win_id);
-
- /* take changes into account: SWP_FRAMECHANGED */
- GetClientRect (self->external_win_id, &rect);
- SetWindowPos (self->internal_win_id, 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_win_id, rect.left, rect.top, rect.right,
- rect.bottom, FALSE);
-}
-
-static void
-release_external_win_id (GstD3D11Window * self)
-{
- WNDPROC external_proc;
-
- if (!self->external_win_id)
- return;
-
- external_proc = GetProp (self->external_win_id, EXTERNAL_PROC_PROP_NAME);
- if (!external_proc)
- return;
-
- GST_DEBUG ("release external window %" G_GUINTPTR_FORMAT,
- (guintptr) self->external_win_id);
-
- SetWindowLongPtr (self->external_win_id,
- GWLP_WNDPROC, (LONG_PTR) external_proc);
-
- RemoveProp (self->external_win_id, EXTERNAL_PROC_PROP_NAME);
- RemoveProp (self->external_win_id, D3D11_WINDOW_PROP_NAME);
- self->external_win_id = NULL;
-}
-
-static gboolean
-gst_d3d11_window_create_internal_window (GstD3D11Window * 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_win_id = 0;
- self->visible = FALSE;
-
- self->internal_win_id = 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_win_id) {
- GST_ERROR_OBJECT (self, "Failed to create d3d11 window");
- return FALSE;
- }
-
- GST_DEBUG_OBJECT (self, "d3d11 window created: %" G_GUINTPTR_FORMAT,
- (guintptr) self->internal_win_id);
-
- g_signal_emit (self,
- d3d11_window_signals[SIGNAL_GOT_WINDOW_HANDLE], 0, self->internal_win_id);
-
- /* 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_win_id);
-
- self->msg_io_channel =
- g_io_channel_win32_new_messages ((guintptr) self->internal_win_id);
- 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;
-}
-
-static void
-gst_d3d11_window_on_resize (GstD3D11Window * window, gboolean redraw)
-{
- HRESULT hr;
- ID3D11Device *d3d11_dev;
- guint width, height;
- D3D11_TEXTURE2D_DESC desc;
- DXGI_SWAP_CHAIN_DESC swap_desc;
- ID3D11Texture2D *backbuffer = NULL;
- GstVideoRectangle src_rect, dst_rect, rst_rect;
-
- gst_d3d11_device_lock (window->device);
- if (!window->swap_chain)
- goto done;
-
- d3d11_dev = gst_d3d11_device_get_device_handle (window->device);
-
- if (window->rtv) {
- ID3D11RenderTargetView_Release (window->rtv);
- window->rtv = NULL;
- }
-
- /* Set zero width and height here. dxgi will decide client area by itself */
- IDXGISwapChain_GetDesc (window->swap_chain, &swap_desc);
- hr = IDXGISwapChain_ResizeBuffers (window->swap_chain,
- 0, 0, 0, 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 = IDXGISwapChain_GetBuffer (window->swap_chain,
- 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;
- }
-
- ID3D11Texture2D_GetDesc (backbuffer, &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 = ID3D11Device_CreateRenderTargetView (d3d11_dev,
- (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;
-
- if (redraw)
- gst_d3d111_window_present (window, NULL);
-
-done:
- if (backbuffer)
- ID3D11Texture2D_Release (backbuffer);
-
- gst_d3d11_device_unlock (window->device);
-}
-
-/* always called from window thread */
-static void
-gst_d3d11_window_change_fullscreen_mode (GstD3D11Window * self)
-{
- HWND hwnd = self->external_win_id ? self->external_win_id :
- self->internal_win_id;
-
- if (!self->swap_chain)
- return;
-
- if (self->requested_fullscreen == self->fullscreen)
- return;
-
- GST_DEBUG_OBJECT (self, "Change mode to %s",
- self->requested_fullscreen ? "fullscreen" : "windowed");
-
- self->fullscreen = !self->fullscreen;
-
- if (!self->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;
-
- /* 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));
-
- IDXGISwapChain_GetContainingOutput (self->swap_chain, &output);
- IDXGIOutput_GetDesc (output, &output_desc);
- IDXGIOutput_Release (output);
-
- 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_on_keyboard_event (GstD3D11Window * self,
- HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- gunichar2 wcrep[128];
- const gchar *event;
-
- if (!self->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";
-
- g_signal_emit (self, d3d11_window_signals[SIGNAL_KEY_EVENT], 0,
- event, utfrep);
- g_free (utfrep);
- }
- }
-}
-
-static void
-gst_d3d11_window_on_mouse_event (GstD3D11Window * self,
- HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- gint button;
- const gchar *event = NULL;
-
- if (!self->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)
- g_signal_emit (self, d3d11_window_signals[SIGNAL_MOUSE_EVENT], 0,
- event, button, (gdouble) LOWORD (lParam), (gdouble) HIWORD (lParam));
-}
-
-static void
-gst_d3d11_window_handle_window_proc (GstD3D11Window * self,
- HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- switch (uMsg) {
- case WM_SIZE:
- gst_d3d11_window_on_resize (self, TRUE);
- break;
- case WM_CLOSE:
- if (self->internal_win_id) {
- ShowWindow (self->internal_win_id, SW_HIDE);
- gst_d3d11_window_close_internal_window (self);
- }
- break;
- case WM_KEYDOWN:
- case WM_KEYUP:
- gst_d3d11_window_on_keyboard_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_on_mouse_event (self, hWnd, uMsg, wParam, lParam);
- break;
- case WM_SYSKEYDOWN:
- if ((self->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) {
- self->requested_fullscreen = !self->fullscreen;
- gst_d3d11_window_change_fullscreen_mode (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 ((self->fullscreen_toggle_mode &
- GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
- == GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
- gst_d3d11_window_change_fullscreen_mode (self);
- }
- break;
- default:
- break;
- }
-
- return;
-}
-
-static LRESULT CALLBACK
-window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
-{
- GstD3D11Window *self;
-
- if (uMsg == WM_CREATE) {
- self = GST_D3D11_WINDOW (((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 (GetProp (hWnd, D3D11_WINDOW_PROP_NAME));
-
- g_assert (self->internal_win_id == hWnd);
-
- gst_d3d11_window_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 = GetProp (hWnd, EXTERNAL_PROC_PROP_NAME);
- GstD3D11Window *self =
- (GstD3D11Window *) GetProp (hWnd, D3D11_WINDOW_PROP_NAME);
-
- if (uMsg == WM_SIZE) {
- MoveWindow (self->internal_win_id, 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");
- release_external_win_id (self);
- self->external_win_id = NULL;
- self->overlay_state = GST_D3D11_WINDOW_OVERLAY_STATE_CLOSED;
- g_mutex_unlock (&self->lock);
- } else {
- gst_d3d11_window_handle_window_proc (self, hWnd, uMsg, wParam, lParam);
- }
-
- return CallWindowProc (external_window_proc, hWnd, uMsg, wParam, lParam);
-}
-
-GstD3D11Window *
-gst_d3d11_window_new (GstD3D11Device * device)
-{
- GstD3D11Window *window;
-
- g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
-
- window = g_object_new (GST_TYPE_D3D11_WINDOW, "d3d11device", device, NULL);
- g_object_ref_sink (window);
-
- if (!window->created)
- gst_clear_object (&window);
-
- return window;
-}
-
-#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)
-{
- gint 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;
-
- if (transfer == GST_VIDEO_TRANSFER_BT2020_12)
- transfer = GST_VIDEO_TRANSFER_BT2020_10;
-
- hr = IDXGISwapChain4_CheckColorSpaceSupport (swapchain,
- colorspace_map[i].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", colorspace_map[i].type, score);
-
- if (score > best_score) {
- best_score = score;
- best_idx = i;
- }
- } else {
- GST_DEBUG_OBJECT (self,
- "colorspace %d not supported", colorspace_map[i].type);
- }
- }
-
- if (best_idx < 0)
- return FALSE;
-
- *dxgi_colorspace = colorspace_map[best_idx].type;
-
- return TRUE;
-}
-#endif
-
-static void
-gst_d3d11_window_disable_alt_enter (GstD3D11Window * window,
- IDXGISwapChain * swap_chain, HWND hwnd)
-{
- IDXGIFactory1 *factory = NULL;
- HRESULT hr;
-
- hr = IDXGISwapChain_GetParent (swap_chain, &IID_IDXGIFactory1,
- (void **) &factory);
- if (!gst_d3d11_result (hr, window->device) || !factory) {
- GST_WARNING_OBJECT (window,
- "Cannot get parent dxgi factory for swapchain %p, hr: 0x%x",
- swap_chain, (guint) hr);
- return;
- }
-
- hr = IDXGIFactory1_MakeWindowAssociation (factory,
- hwnd, DXGI_MWA_NO_ALT_ENTER);
- if (!gst_d3d11_result (hr, window->device)) {
- GST_WARNING_OBJECT (window,
- "MakeWindowAssociation failure, hr: 0x%x", (guint) hr);
- }
-
- IDXGIFactory1_Release (factory);
-}
-
-gboolean
-gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height,
- guint aspect_ratio_n, guint aspect_ratio_d, GstCaps * caps, GError ** error)
-{
- DXGI_SWAP_CHAIN_DESC desc = { 0, };
- GstCaps *render_caps;
- UINT swapchain_flags = 0;
- DXGI_SWAP_EFFECT swap_effect = DXGI_SWAP_EFFECT_DISCARD;
-#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);
-
- if (gst_d3d11_is_windows_8_or_greater ())
- swap_effect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
-
- 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_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;
- window->have_swapchain1 = 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) {
- gboolean allow_tearing = FALSE;
-
- GST_DEBUG_OBJECT (window, "DXGI 1.5 interface is available");
- swapchain4_available = TRUE;
-
- g_object_get (window->device, "allow-tearing", &allow_tearing, NULL);
- if (allow_tearing) {
- GST_DEBUG_OBJECT (window, "device support tearning");
- swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
- window->allow_tearing = TRUE;
- }
- }
-#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;
-
- if (window->external_win_id) {
- RECT client_rect = { 0, };
- GetClientRect (window->external_win_id, &client_rect);
-
- window->surface_width = client_rect.right - client_rect.left;
- window->surface_height = client_rect.bottom - client_rect.top;
- } else {
- window->surface_width = width;
- window->surface_height = height;
- }
-
- window->width = width;
- window->height = height;
-
-#if (DXGI_HEADER_VERSION >= 2)
- if (!window->swap_chain) {
- DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, };
- desc1.Width = 0;
- desc1.Height = 0;
- desc1.Format = window->render_format->dxgi_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;
- /* NOTE: for UWP app, this should be DXGI_SCALING_ASPECT_RATIO_STRETCH
- * with CreateSwapChainForComposition or CreateSwapChainForCoreWindow */
- 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;
- /* FIXME: might need to define for ovelay composition */
- desc1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
- desc1.Flags = swapchain_flags;
-
- window->swap_chain = (IDXGISwapChain *)
- gst_d3d11_device_create_swap_chain_for_hwnd (window->device,
- window->internal_win_id, &desc1, NULL, NULL);
-
- if (!window->swap_chain) {
- GST_WARNING_OBJECT (window, "Failed to create swapchain1");
- } else {
- window->have_swapchain1 = TRUE;
- }
- }
-#endif
-
- if (!window->swap_chain) {
- /* 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 = window->render_format->dxgi_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 = window->internal_win_id;
- desc.Windowed = TRUE;
- desc.Flags = swapchain_flags;
-
- window->swap_chain =
- gst_d3d11_device_create_swap_chain (window->device, &desc);
- }
-
- if (!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;
- }
-
- /* disable alt+enter here. It should be manually handled */
- gst_d3d11_device_lock (window->device);
- gst_d3d11_window_disable_alt_enter (window,
- window->swap_chain, desc.OutputWindow);
- gst_d3d11_device_unlock (window->device);
-
-#if (DXGI_HEADER_VERSION >= 5)
- if (swapchain4_available) {
- HRESULT hr;
- GST_DXGI_COLOR_SPACE_TYPE ctype;
-
- if (gst_d3d11_window_color_space_from_video_info (window,
- &window->render_info, (IDXGISwapChain4 *) window->swap_chain,
- &ctype)) {
- hr = IDXGISwapChain4_SetColorSpace1 ((IDXGISwapChain4 *)
- window->swap_chain, (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 = IDXGISwapChain4_SetHDRMetaData ((IDXGISwapChain4 *)
- window->swap_chain, 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
-
- gst_d3d11_window_on_resize (window, FALSE);
-
- if (!window->rtv) {
- gst_d3d11_window_release_resources (window->device, window);
- GST_ERROR_OBJECT (window, "Failed to setup internal resources");
- g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
- "Failed to setup internal resources");
-
- return FALSE;
- }
-
- if (window->requested_fullscreen != window->fullscreen) {
- g_atomic_int_add (&window->pending_fullscreen_count, 1);
- PostMessage (window->internal_win_id, WM_GST_D3D11_FULLSCREEN, 0, 0);
- }
-
- GST_DEBUG_OBJECT (window, "New swap chain 0x%p created", window->swap_chain);
-
- return TRUE;
-}
-
-void
-gst_d3d11_window_set_window_handle (GstD3D11Window * window, guintptr id)
-{
- g_return_if_fail (GST_IS_D3D11_WINDOW (window));
-
- window->overlay_state = GST_D3D11_WINDOW_OVERLAY_STATE_NONE;
-
- if (window->visible) {
- ShowWindow (window->internal_win_id, SW_HIDE);
- window->visible = FALSE;
- }
-
- release_external_win_id (window);
- window->external_win_id = (HWND) id;
- set_external_win_id (window);
-
- if (window->external_win_id)
- window->overlay_state = GST_D3D11_WINDOW_OVERLAY_STATE_OPENED;
-}
-
-void
-gst_d3d11_window_show (GstD3D11Window * window)
-{
- gint width, height;
-
- g_return_if_fail (GST_IS_D3D11_WINDOW (window));
-
- width = window->width;
- height = window->height;
-
- if (!window->visible) {
- /* if no parent the real size has to be set now because this has not been done
- * when at window creation */
- if (!window->external_win_id) {
- RECT rect;
- GetClientRect (window->internal_win_id, &rect);
- width += 2 * GetSystemMetrics (SM_CXSIZEFRAME);
- height +=
- 2 * GetSystemMetrics (SM_CYSIZEFRAME) +
- GetSystemMetrics (SM_CYCAPTION);
- MoveWindow (window->internal_win_id, rect.left, rect.top, width,
- height, FALSE);
- }
-
- ShowWindow (window->internal_win_id, SW_SHOW);
- window->visible = TRUE;
- }
-}
-
-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));
-
- if (x < 0 || y < 0) {
- x = y = 0;
- width = window->surface_width;
- height = window->surface_height;
- }
-
- if (x < 0 || y < 0 || width <= 0 || height <= 0)
- return;
-
- /* TODO: resize window and view */
-}
-
-static GstFlowReturn
-gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer)
-{
- HRESULT hr;
- UINT present_flags = 0;
-
- if (buffer) {
- gst_buffer_replace (&self->cached_buffer, buffer);
- }
-
- if (self->cached_buffer) {
- ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
- gint 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
-
-#if (DXGI_HEADER_VERSION >= 2)
- if (self->have_swapchain1) {
- DXGI_PRESENT_PARAMETERS present_params = { 0, };
- if (self->first_present) {
- /* the first present should not specify dirty-rect */
- hr = IDXGISwapChain1_Present1 ((IDXGISwapChain1 *) self->swap_chain,
- 0, present_flags, &present_params);
- } else {
- present_params.DirtyRectsCount = 1;
- present_params.pDirtyRects = &self->render_rect;
- hr = IDXGISwapChain1_Present1 ((IDXGISwapChain1 *) self->swap_chain,
- 0, present_flags, &present_params);
- }
- } else
-#endif
- {
- hr = IDXGISwapChain_Present (self->swap_chain, 0, present_flags);
- }
-
- self->first_present = FALSE;
-
- if (!gst_d3d11_result (hr, self->device)) {
- GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
- (guint) hr);
- }
- }
-
- return GST_FLOW_OK;
-}
-
-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;
- }
-
- g_mutex_lock (&window->lock);
- if ((!window->external_win_id &&
- window->overlay_state == GST_D3D11_WINDOW_OVERLAY_STATE_CLOSED)
- || !window->internal_win_id) {
- GST_ERROR_OBJECT (window, "Output window was closed");
- g_mutex_unlock (&window->lock);
-
- return GST_D3D11_WINDOW_FLOW_CLOSED;
- }
- g_mutex_unlock (&window->lock);
-
- 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_flush (GstD3D11Window * window)
-{
- g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
-
- gst_clear_buffer (&window->cached_buffer);
-
- return TRUE;
-}
--- /dev/null
+/*
+ * 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";
+}
\ No newline at end of file
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())
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,
GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER = (1 << 1),
GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY = (1 << 2),
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;
/* requested rect via gst_d3d11_window_render */
GstVideoRectangle rect;
- GMutex lock;
- GCond cond;
-
- GMainContext *main_context;
- GMainLoop *loop;
-
guint width;
guint height;
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);
+
+void gst_d3d11_window_show (GstD3D11Window * window);
+
+void gst_d3d11_window_set_render_rectangle (GstD3D11Window * window,
+ gint x, gint y,
+ gint width, gint height);
+
+gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
+ guint width,
+ guint height,
+ guint aspect_ratio_n,
+ guint aspect_ratio_d,
+ GstCaps * caps,
+ GError ** error);
+
+GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
+ GstBuffer * buffer,
+ GstVideoRectangle * src_rect);
+
+gboolean gst_d3d11_window_unlock (GstD3D11Window * window);
-GstD3D11Window * gst_d3d11_window_new (GstD3D11Device * device);
+gboolean gst_d3d11_window_unlock_stop (GstD3D11Window * window);
-void gst_d3d11_window_show (GstD3D11Window * window);
+void gst_d3d11_window_on_resize (GstD3D11Window * window,
+ guint width,
+ guint height);
-void gst_d3d11_window_set_window_handle (GstD3D11Window * window,
- guintptr id);
+void gst_d3d11_window_on_key_event (GstD3D11Window * window,
+ const gchar * event,
+ const gchar * key);
-void gst_d3d11_window_set_render_rectangle (GstD3D11Window * window,
- gint x, gint y,
- gint width, gint height);
+void gst_d3d11_window_on_mouse_event (GstD3D11Window * window,
+ const gchar * event,
+ gint button,
+ gdouble x,
+ gdouble y);
-gboolean gst_d3d11_window_prepare (GstD3D11Window * window,
- guint width,
- guint height,
- guint aspect_ratio_n,
- guint aspect_ratio_d,
- GstCaps * caps,
- GError ** error);
+/* utils */
+GstD3D11WindowNativeType gst_d3d11_window_get_native_type_from_handle (guintptr handle);
-GstFlowReturn gst_d3d11_window_render (GstD3D11Window * window,
- GstBuffer * buffer,
- GstVideoRectangle * src_rect);
+const gchar * gst_d3d11_window_get_native_type_to_string (GstD3D11WindowNativeType type);
-gboolean gst_d3d11_window_flush (GstD3D11Window * window);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstD3D11Window, gst_object_unref)
G_END_DECLS
--- /dev/null
+/*
+ * 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;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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__ */
'gstd3d11memory.c',
'gstd3d11utils.c',
'gstd3d11videosink.c',
- 'gstd3d11window.c',
+ 'gstd3d11window.cpp',
'plugin.c',
'gstd3d11format.c',
'gstd3d11basefilter.c',
have_dxgi_header = false
have_d3d11sdk_h = false
have_dxgidebug_h = false
+winapi_desktop = false
+winapi_app = false
extra_dep = []
d3d11_conf = configuration_data()
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])
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,
#include "config.h"
#endif
-#include "d3d11config.h"
+#include "gstd3d11config.h"
#include <gst/gst.h>
#include "gstd3d11videosink.h"
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);
"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 */