From 64eb1d46b5d905541a2c2d65695d6f1fa54d09b4 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Mon, 16 Dec 2019 16:59:07 +0900 Subject: [PATCH] d3d11window: Always draw to internal window ... and use SetParent() WIN32 API when external window is used. Depending on DXGI swap effect, the external window might not be reusable by another backend. To preserve the external window's property and setting, drawing to internal window seems to be safer way. --- sys/d3d11/gstd3d11window.c | 122 ++++++++++++++++++++++++++------------------- sys/d3d11/gstd3d11window.h | 8 +++ 2 files changed, 78 insertions(+), 52 deletions(-) diff --git a/sys/d3d11/gstd3d11window.c b/sys/d3d11/gstd3d11window.c index ea33943..064b5f5 100644 --- a/sys/d3d11/gstd3d11window.c +++ b/sys/d3d11/gstd3d11window.c @@ -81,10 +81,11 @@ 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 _create_window (GstD3D11Window * self, GError ** error); +static gboolean _create_window (GstD3D11Window * self); static void _open_window (GstD3D11Window * self); static void _close_window (GstD3D11Window * self); static void release_external_win_id (GstD3D11Window * self); @@ -98,6 +99,7 @@ gst_d3d11_window_class_init (GstD3D11WindowClass * 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; @@ -209,6 +211,20 @@ gst_d3d11_window_get_property (GObject * object, guint prop_id, } 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) { @@ -295,23 +311,16 @@ running_cb (gpointer user_data) return G_SOURCE_REMOVE; } -typedef struct -{ - GstD3D11Window *self; - GError **error; -} GstD3D11ThreadFuncData; - static gpointer gst_d3d11_window_thread_func (gpointer data) { - GstD3D11ThreadFuncData *func_data = (GstD3D11ThreadFuncData *) data; - GstD3D11Window *self = func_data->self; + 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 = _create_window (self, func_data->error); + self->created = _create_window (self); source = g_idle_source_new (); g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL); @@ -385,8 +394,16 @@ static void set_external_win_id (GstD3D11Window * self) { WNDPROC external_window_proc; - if (!self->external_win_id) + 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); @@ -399,6 +416,18 @@ set_external_win_id (GstD3D11Window * self) 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 @@ -425,7 +454,7 @@ release_external_win_id (GstD3D11Window * self) } static gboolean -_create_window (GstD3D11Window * self, GError ** error) +_create_window (GstD3D11Window * self) { WNDCLASSEX wc; ATOM atom = 0; @@ -454,9 +483,6 @@ _create_window (GstD3D11Window * self, GError ** error) G_UNLOCK (create_lock); GST_ERROR_OBJECT (self, "Failed to register window class 0x%x", (unsigned int) GetLastError ()); - g_set_error (error, GST_RESOURCE_ERROR, - GST_RESOURCE_ERROR_FAILED, "Failed to register window class 0x%x", - (unsigned int) GetLastError ()); return FALSE; } } else { @@ -478,8 +504,6 @@ _create_window (GstD3D11Window * self, GError ** error) if (!self->internal_win_id) { GST_ERROR_OBJECT (self, "Failed to create d3d11 window"); - g_set_error (error, GST_RESOURCE_ERROR, - GST_RESOURCE_ERROR_FAILED, "Failed to create d3d11 window"); return FALSE; } @@ -492,8 +516,6 @@ _create_window (GstD3D11Window * self, GError ** error) /* device_handle is set in the window_proc */ if (!self->device_handle) { GST_ERROR_OBJECT (self, "device handle is not available"); - g_set_error (error, GST_RESOURCE_ERROR, - GST_RESOURCE_ERROR_FAILED, "device handle is not available"); return FALSE; } @@ -794,16 +816,22 @@ 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); - LRESULT ret = 0; - gst_d3d11_window_handle_window_proc (self, hWnd, uMsg, wParam, lParam); - - ret = CallWindowProc (external_window_proc, hWnd, uMsg, wParam, lParam); - - if (uMsg == WM_CLOSE) + if (uMsg == WM_SIZE) { + MoveWindow (self->internal_win_id, 0, 0, LOWORD (lParam), HIWORD (lParam), + FALSE); + } else if (uMsg == WM_CLOSE) { + 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 ret; + return CallWindowProc (external_window_proc, hWnd, uMsg, wParam, lParam); } GstD3D11Window * @@ -816,6 +844,9 @@ gst_d3d11_window_new (GstD3D11Device * device) 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; } @@ -986,7 +1017,6 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height, gboolean * do_convert, GError ** error) { DXGI_SWAP_CHAIN_DESC desc = { 0, }; - GstD3D11ThreadFuncData data; GstCaps *render_caps; #if defined(HAVE_DXGI_1_5_H) gboolean have_cll = FALSE; @@ -1057,27 +1087,6 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height, return FALSE; } } - - data.self = window; - data.error = error; - - g_mutex_lock (&window->lock); - if (!window->external_win_id && !window->created) { - window->loop = g_main_loop_new (window->main_context, FALSE); - window->thread = g_thread_new ("GstD3D11Window", - (GThreadFunc) gst_d3d11_window_thread_func, &data); - while (!g_main_loop_is_running (window->loop)) - g_cond_wait (&window->cond, &window->lock); - } - g_mutex_unlock (&window->lock); - - if (!window->external_win_id && !window->created) { - g_main_loop_quit (window->loop); - g_thread_join (window->thread); - g_main_loop_unref (window->loop); - window->loop = NULL; - window->thread = NULL; - } #if defined(HAVE_DXGI_1_5_H) if (!gst_video_content_light_level_from_caps (&window->content_light_level, caps)) { @@ -1143,9 +1152,7 @@ gst_d3d11_window_prepare (GstD3D11Window * window, guint width, guint height, if (swapchain4_available) desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; #endif - desc.OutputWindow = - window->external_win_id ? window->external_win_id : window-> - internal_win_id; + desc.OutputWindow = window->internal_win_id; desc.Windowed = TRUE; desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; @@ -1225,6 +1232,8 @@ 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; @@ -1233,6 +1242,9 @@ gst_d3d11_window_set_window_handle (GstD3D11Window * window, guintptr id) 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 @@ -1377,10 +1389,16 @@ gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer, return GST_FLOW_ERROR; } - if (!window->external_win_id && !window->internal_win_id) { + 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_OBJECT_LOCK (window); if (rect->w != window->width || rect->h != window->height || diff --git a/sys/d3d11/gstd3d11window.h b/sys/d3d11/gstd3d11window.h index c7b0431..ef84462 100644 --- a/sys/d3d11/gstd3d11window.h +++ b/sys/d3d11/gstd3d11window.h @@ -41,6 +41,13 @@ typedef struct _GstD3D11WindowClass GstD3D11WindowClass; #define GST_D3D11_WINDOW_FLOW_CLOSED GST_FLOW_CUSTOM_ERROR +typedef enum +{ + GST_D3D11_WINDOW_OVERLAY_STATE_NONE = 0, + GST_D3D11_WINDOW_OVERLAY_STATE_OPENED, + GST_D3D11_WINDOW_OVERLAY_STATE_CLOSED, +} GstD3D11WindowOverlayState; + struct _GstD3D11Window { GstObject parent; @@ -85,6 +92,7 @@ struct _GstD3D11Window HWND internal_win_id; HWND external_win_id; + GstD3D11WindowOverlayState overlay_state; HDC device_handle; IDXGISwapChain *swap_chain; -- 2.7.4