• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
4  * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
5  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 #include "gstd3d11window_win32.h"
28 #include <wrl.h>
29 
30 /* *INDENT-OFF* */
31 using namespace Microsoft::WRL;
32 /* *INDENT-ON* */
33 
34 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
35 #define GST_CAT_DEFAULT gst_d3d11_window_debug
36 
37 G_LOCK_DEFINE_STATIC (create_lock);
38 
39 #define EXTERNAL_PROC_PROP_NAME "d3d11_window_external_proc"
40 #define D3D11_WINDOW_PROP_NAME "gst_d3d11_window_win32_object"
41 
42 #define WM_GST_D3D11_FULLSCREEN (WM_USER + 1)
43 #define WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW (WM_USER + 2)
44 #define WM_GST_D3D11_DESTROY_INTERNAL_WINDOW (WM_USER + 3)
45 #define WM_GST_D3D11_MOVE_WINDOW (WM_USER + 4)
46 
47 static LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
48     LPARAM lParam);
49 static LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
50     LPARAM lParam);
51 
52 typedef enum
53 {
54   GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE = 0,
55   GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED,
56   GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED,
57 } GstD3D11WindowWin32OverlayState;
58 
59 struct _GstD3D11WindowWin32
60 {
61   GstD3D11Window parent;
62 
63   GMutex lock;
64   GCond cond;
65 
66   GMainContext *main_context;
67   GMainLoop *loop;
68 
69   gboolean visible;
70 
71   GSource *msg_source;
72   GIOChannel *msg_io_channel;
73 
74   GThread *thread;
75 
76   GThread *internal_hwnd_thread;
77 
78   HWND internal_hwnd;
79   HWND external_hwnd;
80   GstD3D11WindowWin32OverlayState overlay_state;
81 
82   HDC device_handle;
83   gboolean first_present;
84   gboolean have_swapchain1;
85 
86   /* atomic */
87   gint pending_fullscreen_count;
88   gint pending_move_window;
89 
90   /* fullscreen related */
91   RECT restore_rect;
92   LONG restore_style;
93 
94   /* Handle set_render_rectangle */
95   GstVideoRectangle render_rect;
96 };
97 
98 #define gst_d3d11_window_win32_parent_class parent_class
99 G_DEFINE_TYPE (GstD3D11WindowWin32, gst_d3d11_window_win32,
100     GST_TYPE_D3D11_WINDOW);
101 
102 static void gst_d3d11_window_win32_constructed (GObject * object);
103 static void gst_d3d11_window_win32_dispose (GObject * object);
104 static void gst_d3d11_window_win32_finalize (GObject * object);
105 
106 static void gst_d3d11_window_win32_show (GstD3D11Window * window);
107 static void gst_d3d11_window_win32_update_swap_chain (GstD3D11Window * window);
108 static void
109 gst_d3d11_window_win32_change_fullscreen_mode (GstD3D11Window * window);
110 static gboolean
111 gst_d3d11_window_win32_create_swap_chain (GstD3D11Window * window,
112     DXGI_FORMAT format, guint width, guint height,
113     guint swapchain_flags, IDXGISwapChain ** swap_chain);
114 static GstFlowReturn gst_d3d11_window_win32_present (GstD3D11Window * window,
115     guint present_flags);
116 
117 static gpointer gst_d3d11_window_win32_thread_func (gpointer data);
118 static gboolean
119 gst_d3d11_window_win32_create_internal_window (GstD3D11WindowWin32 * self);
120 static void gst_d3d11_window_win32_destroy_internal_window (HWND hwnd);
121 static void gst_d3d11_window_win32_release_external_handle (HWND hwnd);
122 static void
123 gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
124     guintptr handle);
125 static void
126 gst_d3d11_window_win32_on_resize (GstD3D11Window * window,
127     guint width, guint height);
128 static void gst_d3d11_window_win32_unprepare (GstD3D11Window * window);
129 static void
130 gst_d3d11_window_win32_set_render_rectangle (GstD3D11Window * window,
131     const GstVideoRectangle * rect);
132 static void gst_d3d11_window_win32_set_title (GstD3D11Window * window,
133     const gchar * title);
134 
135 static void
gst_d3d11_window_win32_class_init(GstD3D11WindowWin32Class * klass)136 gst_d3d11_window_win32_class_init (GstD3D11WindowWin32Class * klass)
137 {
138   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
139   GstD3D11WindowClass *window_class = GST_D3D11_WINDOW_CLASS (klass);
140 
141   gobject_class->constructed = gst_d3d11_window_win32_constructed;
142   gobject_class->dispose = gst_d3d11_window_win32_dispose;
143   gobject_class->finalize = gst_d3d11_window_win32_finalize;
144 
145   window_class->show = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_show);
146   window_class->update_swap_chain =
147       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_update_swap_chain);
148   window_class->change_fullscreen_mode =
149       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_change_fullscreen_mode);
150   window_class->create_swap_chain =
151       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_create_swap_chain);
152   window_class->present = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_present);
153   window_class->on_resize =
154       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_on_resize);
155   window_class->unprepare =
156       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_unprepare);
157   window_class->set_render_rectangle =
158       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_set_render_rectangle);
159   window_class->set_title =
160       GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_set_title);
161 }
162 
163 static void
gst_d3d11_window_win32_init(GstD3D11WindowWin32 * self)164 gst_d3d11_window_win32_init (GstD3D11WindowWin32 * self)
165 {
166   g_mutex_init (&self->lock);
167   g_cond_init (&self->cond);
168 
169   self->main_context = g_main_context_new ();
170 }
171 
172 static void
gst_d3d11_window_win32_constructed(GObject * object)173 gst_d3d11_window_win32_constructed (GObject * object)
174 {
175   GstD3D11Window *window = GST_D3D11_WINDOW (object);
176   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
177 
178   if (window->external_handle) {
179     gst_d3d11_window_win32_set_window_handle (self, window->external_handle);
180     goto done;
181   }
182 
183   g_mutex_lock (&self->lock);
184   self->loop = g_main_loop_new (self->main_context, FALSE);
185   self->thread = g_thread_new ("GstD3D11WindowWin32",
186       (GThreadFunc) gst_d3d11_window_win32_thread_func, self);
187   while (!g_main_loop_is_running (self->loop))
188     g_cond_wait (&self->cond, &self->lock);
189   g_mutex_unlock (&self->lock);
190 
191 done:
192   G_OBJECT_CLASS (parent_class)->constructed (object);
193 }
194 
195 static void
gst_d3d11_window_win32_dispose(GObject * object)196 gst_d3d11_window_win32_dispose (GObject * object)
197 {
198   gst_d3d11_window_win32_unprepare (GST_D3D11_WINDOW (object));
199 
200   G_OBJECT_CLASS (parent_class)->dispose (object);
201 }
202 
203 static void
gst_d3d11_window_win32_unprepare(GstD3D11Window * window)204 gst_d3d11_window_win32_unprepare (GstD3D11Window * window)
205 {
206   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
207 
208   if (self->external_hwnd) {
209     gst_d3d11_window_win32_release_external_handle (self->external_hwnd);
210     RemovePropA (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
211 
212     if (self->internal_hwnd_thread == g_thread_self ()) {
213       /* State changing thread is identical to internal window thread.
214        * window can be closed here */
215 
216       GST_INFO_OBJECT (self, "Closing internal window immediately");
217       gst_d3d11_window_win32_destroy_internal_window (self->internal_hwnd);
218     } else {
219       /* We cannot destroy internal window from non-window thread.
220        * and we cannot use synchronously SendMessage() method at this point
221        * since window thread might be wait for current thread and SendMessage()
222        * will be blocked until it's called from window thread.
223        * Instead, posts message so that it can be closed from window thread
224        * asynchronously */
225       GST_INFO_OBJECT (self, "Posting custom destory message");
226       PostMessageA (self->internal_hwnd, WM_GST_D3D11_DESTROY_INTERNAL_WINDOW,
227           0, 0);
228     }
229 
230     self->external_hwnd = NULL;
231     self->internal_hwnd = NULL;
232     self->internal_hwnd_thread = NULL;
233   }
234 
235   if (self->loop) {
236     g_main_loop_quit (self->loop);
237   }
238 
239   if (self->thread) {
240     g_thread_join (self->thread);
241     self->thread = NULL;
242   }
243 
244   if (self->loop) {
245     g_main_loop_unref (self->loop);
246     self->loop = NULL;
247   }
248 
249   if (self->main_context) {
250     g_main_context_unref (self->main_context);
251     self->main_context = NULL;
252   }
253 }
254 
255 static void
gst_d3d11_window_win32_set_render_rectangle(GstD3D11Window * window,const GstVideoRectangle * rect)256 gst_d3d11_window_win32_set_render_rectangle (GstD3D11Window * window,
257     const GstVideoRectangle * rect)
258 {
259   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
260 
261   if (self->external_hwnd && self->internal_hwnd) {
262     g_atomic_int_add (&self->pending_move_window, 1);
263     self->render_rect = *rect;
264 
265     if (self->internal_hwnd_thread == g_thread_self ()) {
266       /* We are on message pumping thread already, handle this synchroniously */
267       SendMessageA (self->internal_hwnd, WM_GST_D3D11_MOVE_WINDOW, 0, 0);
268     } else {
269       /* Post message to message pumping thread. Handling HWND specific message
270        * on message pumping thread is not a worst idea in generall */
271       PostMessageA (self->internal_hwnd, WM_GST_D3D11_MOVE_WINDOW, 0, 0);
272     }
273   } else {
274     /* XXX: Not sure what's expected behavior if we are drawing on internal
275      * HWND but user wants to specify rectangle.
276      *
277      * - Should we move window to corresponding desktop coordinates ?
278      * - Or should crop correspondingly by modifying viewport of
279      *   render target view of swapchian's backbuffer or so ?
280      * - Or should we ignore set_render_rectangle if we are drawing on
281      *   internal HWND without external HWND ?
282      */
283   }
284 }
285 
286 static void
gst_d3d11_window_win32_set_title(GstD3D11Window * window,const gchar * title)287 gst_d3d11_window_win32_set_title (GstD3D11Window * window, const gchar * title)
288 {
289   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
290 
291   /* Do this only when we are rendring on our own HWND */
292   if (!self->external_hwnd && self->internal_hwnd) {
293     gunichar2 *str = g_utf8_to_utf16 (title, -1, nullptr, nullptr, nullptr);
294 
295     if (str) {
296       SetWindowTextW (self->internal_hwnd, (LPCWSTR) str);
297       g_free (str);
298     }
299   }
300 }
301 
302 static void
gst_d3d11_window_win32_finalize(GObject * object)303 gst_d3d11_window_win32_finalize (GObject * object)
304 {
305   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
306 
307   g_mutex_clear (&self->lock);
308   g_cond_clear (&self->cond);
309 
310   G_OBJECT_CLASS (parent_class)->finalize (object);
311 }
312 
313 static gboolean
running_cb(gpointer user_data)314 running_cb (gpointer user_data)
315 {
316   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (user_data);
317 
318   GST_TRACE_OBJECT (self, "Main loop running now");
319 
320   g_mutex_lock (&self->lock);
321   g_cond_signal (&self->cond);
322   g_mutex_unlock (&self->lock);
323 
324   return G_SOURCE_REMOVE;
325 }
326 
327 static gboolean
msg_cb(GIOChannel * source,GIOCondition condition,gpointer data)328 msg_cb (GIOChannel * source, GIOCondition condition, gpointer data)
329 {
330   MSG msg;
331 
332   if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
333     return G_SOURCE_CONTINUE;
334 
335   TranslateMessage (&msg);
336   DispatchMessage (&msg);
337 
338   return G_SOURCE_CONTINUE;
339 }
340 
341 static gpointer
gst_d3d11_window_win32_thread_func(gpointer data)342 gst_d3d11_window_win32_thread_func (gpointer data)
343 {
344   GstD3D11Window *window = GST_D3D11_WINDOW (data);
345   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (data);
346   GSource *source;
347 
348   GST_DEBUG_OBJECT (self, "Enter loop");
349   g_main_context_push_thread_default (self->main_context);
350 
351   window->initialized = gst_d3d11_window_win32_create_internal_window (self);
352 
353   self->msg_io_channel =
354       g_io_channel_win32_new_messages ((guintptr) self->internal_hwnd);
355   self->msg_source = g_io_create_watch (self->msg_io_channel, G_IO_IN);
356   g_source_set_callback (self->msg_source, (GSourceFunc) msg_cb, self, NULL);
357   g_source_attach (self->msg_source, self->main_context);
358 
359   source = g_idle_source_new ();
360   g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
361   g_source_attach (source, self->main_context);
362   g_source_unref (source);
363 
364   g_main_loop_run (self->loop);
365 
366   RemovePropA (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
367   gst_d3d11_window_win32_destroy_internal_window (self->internal_hwnd);
368   self->internal_hwnd = NULL;
369   self->internal_hwnd_thread = NULL;
370 
371   if (self->msg_source) {
372     g_source_destroy (self->msg_source);
373     g_source_unref (self->msg_source);
374     self->msg_source = NULL;
375   }
376 
377   if (self->msg_io_channel) {
378     g_io_channel_unref (self->msg_io_channel);
379     self->msg_io_channel = NULL;
380   }
381 
382   g_main_context_pop_thread_default (self->main_context);
383 
384   GST_DEBUG_OBJECT (self, "Exit loop");
385 
386   return NULL;
387 }
388 
389 static void
gst_d3d11_window_win32_destroy_internal_window(HWND hwnd)390 gst_d3d11_window_win32_destroy_internal_window (HWND hwnd)
391 {
392   if (!hwnd)
393     return;
394 
395   SetParent (hwnd, NULL);
396 
397   GST_INFO ("Destroying internal window %" G_GUINTPTR_FORMAT, (guintptr) hwnd);
398 
399   if (!DestroyWindow (hwnd))
400     GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
401         ", 0x%x", (guintptr) hwnd, (guint) GetLastError ());
402 }
403 
404 static void
gst_d3d11_window_win32_set_external_handle(GstD3D11WindowWin32 * self)405 gst_d3d11_window_win32_set_external_handle (GstD3D11WindowWin32 * self)
406 {
407   WNDPROC external_window_proc;
408 
409   external_window_proc =
410       (WNDPROC) GetWindowLongPtrA (self->external_hwnd, GWLP_WNDPROC);
411 
412   GST_DEBUG_OBJECT (self, "set external window %" G_GUINTPTR_FORMAT
413       ", original window procedure %p", (guintptr) self->external_hwnd,
414       external_window_proc);
415 
416   SetPropA (self->external_hwnd, EXTERNAL_PROC_PROP_NAME,
417       (HANDLE) external_window_proc);
418   SetPropA (self->external_hwnd, D3D11_WINDOW_PROP_NAME, self);
419   SetWindowLongPtrA (self->external_hwnd, GWLP_WNDPROC,
420       (LONG_PTR) sub_class_proc);
421 
422   /* Will create our internal window on parent window's thread */
423   SendMessageA (self->external_hwnd, WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW,
424       0, 0);
425 }
426 
427 static void
gst_d3d11_window_win32_release_external_handle(HWND hwnd)428 gst_d3d11_window_win32_release_external_handle (HWND hwnd)
429 {
430   WNDPROC external_proc;
431 
432   if (!hwnd)
433     return;
434 
435   external_proc = (WNDPROC) GetPropA (hwnd, EXTERNAL_PROC_PROP_NAME);
436   if (!external_proc) {
437     GST_WARNING ("Failed to get original window procedure");
438     return;
439   }
440 
441   GST_DEBUG ("release external window %" G_GUINTPTR_FORMAT
442       ", original window procedure %p", (guintptr) hwnd, external_proc);
443 
444   RemovePropA (hwnd, EXTERNAL_PROC_PROP_NAME);
445   RemovePropA (hwnd, D3D11_WINDOW_PROP_NAME);
446 
447   if (!SetWindowLongPtrA (hwnd, GWLP_WNDPROC, (LONG_PTR) external_proc))
448     GST_WARNING ("Couldn't restore original window procedure");
449 }
450 
451 static gboolean
gst_d3d11_window_win32_create_internal_window(GstD3D11WindowWin32 * self)452 gst_d3d11_window_win32_create_internal_window (GstD3D11WindowWin32 * self)
453 {
454   WNDCLASSEXA wc;
455   ATOM atom = 0;
456   HINSTANCE hinstance = GetModuleHandleA (NULL);
457 
458   GST_LOG_OBJECT (self, "Attempting to create a win32 window");
459 
460   G_LOCK (create_lock);
461   atom = GetClassInfoExA (hinstance, "GSTD3D11", &wc);
462   if (atom == 0) {
463     GST_LOG_OBJECT (self, "Register internal window class");
464     ZeroMemory (&wc, sizeof (WNDCLASSEXA));
465 
466     wc.cbSize = sizeof (WNDCLASSEXA);
467     wc.lpfnWndProc = window_proc;
468     wc.hInstance = hinstance;
469     wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
470     wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
471     wc.hCursor = LoadCursor (NULL, IDC_ARROW);
472     wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
473     wc.lpszClassName = "GSTD3D11";
474 
475     atom = RegisterClassExA (&wc);
476 
477     if (atom == 0) {
478       G_UNLOCK (create_lock);
479       GST_ERROR_OBJECT (self, "Failed to register window class 0x%x",
480           (unsigned int) GetLastError ());
481       return FALSE;
482     }
483   } else {
484     GST_LOG_OBJECT (self, "window class was already registered");
485   }
486 
487   self->device_handle = 0;
488   self->internal_hwnd = 0;
489   self->visible = FALSE;
490 
491   self->internal_hwnd = CreateWindowExA (0,
492       "GSTD3D11",
493       "Direct3D11 renderer",
494       WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
495       CW_USEDEFAULT, CW_USEDEFAULT,
496       0, 0, (HWND) NULL, (HMENU) NULL, hinstance, self);
497 
498   G_UNLOCK (create_lock);
499 
500   if (!self->internal_hwnd) {
501     GST_ERROR_OBJECT (self, "Failed to create d3d11 window");
502     return FALSE;
503   }
504 
505   GST_DEBUG_OBJECT (self, "d3d11 window created: %" G_GUINTPTR_FORMAT,
506       (guintptr) self->internal_hwnd);
507 
508   /* device_handle is set in the window_proc */
509   if (!self->device_handle) {
510     GST_ERROR_OBJECT (self, "device handle is not available");
511     return FALSE;
512   }
513 
514   GST_LOG_OBJECT (self,
515       "Created a internal d3d11 window %p", self->internal_hwnd);
516 
517   self->internal_hwnd_thread = g_thread_self ();
518 
519   return TRUE;
520 }
521 
522 /* always called from window thread */
523 static void
gst_d3d11_window_win32_change_fullscreen_mode_internal(GstD3D11WindowWin32 * self)524 gst_d3d11_window_win32_change_fullscreen_mode_internal (GstD3D11WindowWin32 *
525     self)
526 {
527   GstD3D11Window *window = GST_D3D11_WINDOW (self);
528   HWND hwnd = self->external_hwnd ? self->external_hwnd : self->internal_hwnd;
529 
530   if (!window->swap_chain)
531     return;
532 
533   if (window->requested_fullscreen == window->fullscreen)
534     return;
535 
536   GST_DEBUG_OBJECT (self, "Change mode to %s",
537       window->requested_fullscreen ? "fullscreen" : "windowed");
538 
539   window->fullscreen = !window->fullscreen;
540 
541   if (!window->fullscreen) {
542     /* Restore the window's attributes and size */
543     SetWindowLongA (hwnd, GWL_STYLE, self->restore_style);
544 
545     SetWindowPos (hwnd, HWND_NOTOPMOST,
546         self->restore_rect.left,
547         self->restore_rect.top,
548         self->restore_rect.right - self->restore_rect.left,
549         self->restore_rect.bottom - self->restore_rect.top,
550         SWP_FRAMECHANGED | SWP_NOACTIVATE);
551 
552     ShowWindow (hwnd, SW_NORMAL);
553   } else {
554     ComPtr < IDXGIOutput > output;
555     DXGI_OUTPUT_DESC output_desc;
556     IDXGISwapChain *swap_chain = window->swap_chain;
557 
558     /* show window before change style */
559     ShowWindow (hwnd, SW_SHOW);
560 
561     /* Save the old window rect so we can restore it when exiting
562      * fullscreen mode */
563     GetWindowRect (hwnd, &self->restore_rect);
564     self->restore_style = GetWindowLong (hwnd, GWL_STYLE);
565 
566     /* Make the window borderless so that the client area can fill the screen */
567     SetWindowLongA (hwnd, GWL_STYLE,
568         self->restore_style &
569         ~(WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
570             WS_THICKFRAME));
571 
572     swap_chain->GetContainingOutput (&output);
573     output->GetDesc (&output_desc);
574 
575     SetWindowPos (hwnd, HWND_TOPMOST,
576         output_desc.DesktopCoordinates.left,
577         output_desc.DesktopCoordinates.top,
578         output_desc.DesktopCoordinates.right,
579         output_desc.DesktopCoordinates.bottom,
580         SWP_FRAMECHANGED | SWP_NOACTIVATE);
581 
582     ShowWindow (hwnd, SW_MAXIMIZE);
583   }
584 
585   GST_DEBUG_OBJECT (self, "Fullscreen mode change done");
586 }
587 
588 static void
gst_d3d11_window_win32_on_key_event(GstD3D11WindowWin32 * self,HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)589 gst_d3d11_window_win32_on_key_event (GstD3D11WindowWin32 * self,
590     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
591 {
592   GstD3D11Window *window = GST_D3D11_WINDOW (self);
593   gunichar2 wcrep[128];
594   const gchar *event;
595 
596   if (!window->enable_navigation_events)
597     return;
598 
599   if (GetKeyNameTextW (lParam, (LPWSTR) wcrep, 128)) {
600     gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
601     if (utfrep) {
602       if (uMsg == WM_KEYDOWN)
603         event = "key-press";
604       else
605         event = "key-release";
606 
607       gst_d3d11_window_on_key_event (window, event, utfrep);
608       g_free (utfrep);
609     }
610   }
611 }
612 
613 static void
gst_d3d11_window_win32_on_mouse_event(GstD3D11WindowWin32 * self,HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)614 gst_d3d11_window_win32_on_mouse_event (GstD3D11WindowWin32 * self,
615     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
616 {
617   GstD3D11Window *window = GST_D3D11_WINDOW (self);
618   gint button;
619   const gchar *event = NULL;
620 
621   if (!window->enable_navigation_events)
622     return;
623 
624   /* FIXME: convert to render coordinate */
625   switch (uMsg) {
626     case WM_MOUSEMOVE:
627       button = 0;
628       event = "mouse-move";
629       break;
630     case WM_LBUTTONDOWN:
631       button = 1;
632       event = "mouse-button-press";
633       break;
634     case WM_LBUTTONUP:
635       button = 1;
636       event = "mouse-button-release";
637       break;
638     case WM_RBUTTONDOWN:
639       button = 2;
640       event = "mouse-button-press";
641       break;
642     case WM_RBUTTONUP:
643       button = 2;
644       event = "mouse-button-release";
645       break;
646     case WM_MBUTTONDOWN:
647       button = 3;
648       event = "mouse-button-press";
649       break;
650     case WM_MBUTTONUP:
651       button = 3;
652       event = "mouse-button-release";
653       break;
654     default:
655       break;
656   }
657 
658   if (event)
659     gst_d3d11_window_on_mouse_event (window,
660         event, button, (gdouble) LOWORD (lParam), (gdouble) HIWORD (lParam));
661 }
662 
663 static void
gst_d3d11_window_win32_handle_window_proc(GstD3D11WindowWin32 * self,HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)664 gst_d3d11_window_win32_handle_window_proc (GstD3D11WindowWin32 * self,
665     HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
666 {
667   GstD3D11Window *window = GST_D3D11_WINDOW (self);
668 
669   switch (uMsg) {
670     case WM_SIZE:
671       gst_d3d11_window_win32_on_resize (window, 0, 0);
672       break;
673     case WM_CLOSE:
674       if (self->internal_hwnd) {
675         RemovePropA (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
676         ShowWindow (self->internal_hwnd, SW_HIDE);
677         gst_d3d11_window_win32_destroy_internal_window (self->internal_hwnd);
678         self->internal_hwnd = NULL;
679         self->internal_hwnd_thread = NULL;
680       }
681       break;
682     case WM_KEYDOWN:
683     case WM_KEYUP:
684       gst_d3d11_window_win32_on_key_event (self, hWnd, uMsg, wParam, lParam);
685       break;
686     case WM_LBUTTONDOWN:
687     case WM_LBUTTONUP:
688     case WM_RBUTTONDOWN:
689     case WM_RBUTTONUP:
690     case WM_MBUTTONDOWN:
691     case WM_MBUTTONUP:
692     case WM_MOUSEMOVE:
693       gst_d3d11_window_win32_on_mouse_event (self, hWnd, uMsg, wParam, lParam);
694       break;
695     case WM_SYSKEYDOWN:
696       if ((window->fullscreen_toggle_mode &
697               GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER)
698           == GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER) {
699         WORD state = GetKeyState (VK_RETURN);
700         BYTE high = HIBYTE (state);
701 
702         if (high & 0x1) {
703           window->requested_fullscreen = !window->fullscreen;
704           gst_d3d11_window_win32_change_fullscreen_mode_internal (self);
705         }
706       }
707       break;
708     case WM_GST_D3D11_FULLSCREEN:
709       if (g_atomic_int_get (&self->pending_fullscreen_count)) {
710         g_atomic_int_dec_and_test (&self->pending_fullscreen_count);
711         if ((window->fullscreen_toggle_mode &
712                 GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
713             == GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
714           gst_d3d11_window_win32_change_fullscreen_mode_internal (self);
715       }
716       break;
717     case WM_GST_D3D11_MOVE_WINDOW:
718       if (g_atomic_int_get (&self->pending_move_window)) {
719         g_atomic_int_set (&self->pending_move_window, 0);
720 
721         if (self->internal_hwnd && self->external_hwnd) {
722           if (self->render_rect.w < 0 || self->render_rect.h < 0) {
723             RECT rect;
724 
725             /* Reset render rect and back to full-size window */
726             if (GetClientRect (self->external_hwnd, &rect)) {
727               MoveWindow (self->internal_hwnd, 0, 0,
728                   rect.right - rect.left, rect.bottom - rect.top, FALSE);
729             }
730           } else {
731             MoveWindow (self->internal_hwnd, self->render_rect.x,
732                 self->render_rect.y, self->render_rect.w, self->render_rect.h,
733                 FALSE);
734           }
735         }
736       }
737       break;
738     default:
739       break;
740   }
741 
742   return;
743 }
744 
745 static LRESULT CALLBACK
window_proc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)746 window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
747 {
748   GstD3D11WindowWin32 *self;
749 
750   if (uMsg == WM_CREATE) {
751     self = GST_D3D11_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams);
752 
753     GST_LOG_OBJECT (self, "WM_CREATE");
754 
755     self->device_handle = GetDC (hWnd);
756     /* Do this, otherwise we hang on exit. We can still use it (due to the
757      * CS_OWNDC flag in the WindowClass) after we have Released.
758      */
759     ReleaseDC (hWnd, self->device_handle);
760 
761     SetPropA (hWnd, D3D11_WINDOW_PROP_NAME, self);
762   } else if (GetPropA (hWnd, D3D11_WINDOW_PROP_NAME)) {
763     HANDLE handle = GetPropA (hWnd, D3D11_WINDOW_PROP_NAME);
764 
765     if (!GST_IS_D3D11_WINDOW_WIN32 (handle)) {
766       GST_WARNING ("%p is not d3d11window object", handle);
767       return DefWindowProcA (hWnd, uMsg, wParam, lParam);
768     }
769 
770     self = GST_D3D11_WINDOW_WIN32 (handle);
771 
772     g_assert (self->internal_hwnd == hWnd);
773 
774     gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
775         lParam);
776 
777     switch (uMsg) {
778       case WM_SIZE:
779         /* We handled this event already */
780         return 0;
781       case WM_NCHITTEST:
782         /* To passthrough mouse event if external window is used.
783          * Only hit-test succeeded window can receive/handle some mouse events
784          * and we want such events to be handled by parent (application) window
785          */
786         if (self->external_hwnd)
787           return (LRESULT) HTTRANSPARENT;
788         break;
789       default:
790         break;
791     }
792   } else if (uMsg == WM_GST_D3D11_DESTROY_INTERNAL_WINDOW) {
793     GST_INFO ("Handle destroy window message");
794     gst_d3d11_window_win32_destroy_internal_window (hWnd);
795 
796     return 0;
797   }
798 
799   return DefWindowProcA (hWnd, uMsg, wParam, lParam);
800 }
801 
802 static LRESULT FAR PASCAL
sub_class_proc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)803 sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
804 {
805   WNDPROC external_window_proc =
806       (WNDPROC) GetPropA (hWnd, EXTERNAL_PROC_PROP_NAME);
807   GstD3D11WindowWin32 *self =
808       (GstD3D11WindowWin32 *) GetPropA (hWnd, D3D11_WINDOW_PROP_NAME);
809 
810   if (uMsg == WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW) {
811     GstD3D11Window *window = GST_D3D11_WINDOW (self);
812     RECT rect;
813 
814     GST_DEBUG_OBJECT (self, "Create internal window");
815 
816     window->initialized = gst_d3d11_window_win32_create_internal_window (self);
817 
818     SetWindowLongPtrA (self->internal_hwnd, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
819     SetParent (self->internal_hwnd, self->external_hwnd);
820 
821     /* take changes into account: SWP_FRAMECHANGED */
822     GetClientRect (self->external_hwnd, &rect);
823     SetWindowPos (self->internal_hwnd, HWND_TOP, rect.left, rect.top,
824         rect.right, rect.bottom,
825         SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
826         SWP_FRAMECHANGED | SWP_NOACTIVATE);
827     MoveWindow (self->internal_hwnd, rect.left, rect.top, rect.right,
828         rect.bottom, FALSE);
829 
830     /* don't need to be chained up to parent window procedure,
831      * as this is our custom message */
832     return 0;
833   } else if (self) {
834     if (uMsg == WM_SIZE) {
835       MoveWindow (self->internal_hwnd, 0, 0, LOWORD (lParam), HIWORD (lParam),
836           FALSE);
837     } else if (uMsg == WM_CLOSE || uMsg == WM_DESTROY) {
838       g_mutex_lock (&self->lock);
839       GST_WARNING_OBJECT (self, "external window is closing");
840       gst_d3d11_window_win32_release_external_handle (self->external_hwnd);
841       self->external_hwnd = NULL;
842 
843       RemovePropA (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
844       ShowWindow (self->internal_hwnd, SW_HIDE);
845       gst_d3d11_window_win32_destroy_internal_window (self->internal_hwnd);
846       self->internal_hwnd = NULL;
847       self->internal_hwnd_thread = NULL;
848 
849       self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED;
850       g_mutex_unlock (&self->lock);
851     } else {
852       gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
853           lParam);
854     }
855   }
856 
857   return CallWindowProcA (external_window_proc, hWnd, uMsg, wParam, lParam);
858 }
859 
860 static void
gst_d3d11_window_win32_disable_alt_enter(GstD3D11WindowWin32 * self,GstD3D11Device * device,IDXGISwapChain * swap_chain,HWND hwnd)861 gst_d3d11_window_win32_disable_alt_enter (GstD3D11WindowWin32 * self,
862     GstD3D11Device * device, IDXGISwapChain * swap_chain, HWND hwnd)
863 {
864   ComPtr < IDXGIFactory1 > factory;
865   HRESULT hr;
866 
867   hr = swap_chain->GetParent (IID_PPV_ARGS (&factory));
868   if (!gst_d3d11_result (hr, device) || !factory) {
869     GST_WARNING_OBJECT (self,
870         "Cannot get parent dxgi factory for swapchain %p, hr: 0x%x",
871         swap_chain, (guint) hr);
872     return;
873   }
874 
875   hr = factory->MakeWindowAssociation (hwnd, DXGI_MWA_NO_ALT_ENTER);
876   if (!gst_d3d11_result (hr, device)) {
877     GST_WARNING_OBJECT (self,
878         "MakeWindowAssociation failure, hr: 0x%x", (guint) hr);
879   }
880 }
881 
882 static IDXGISwapChain *
create_swap_chain(GstD3D11WindowWin32 * self,GstD3D11Device * device,DXGI_SWAP_CHAIN_DESC * desc)883 create_swap_chain (GstD3D11WindowWin32 * self, GstD3D11Device * device,
884     DXGI_SWAP_CHAIN_DESC * desc)
885 {
886   HRESULT hr;
887   IDXGISwapChain *swap_chain = NULL;
888   ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
889   IDXGIFactory1 *factory = gst_d3d11_device_get_dxgi_factory_handle (device);
890 
891   gst_d3d11_device_lock (device);
892   hr = factory->CreateSwapChain (device_handle, desc, &swap_chain);
893   gst_d3d11_device_unlock (device);
894 
895   if (!gst_d3d11_result (hr, device)) {
896     GST_WARNING_OBJECT (self, "Cannot create SwapChain Object: 0x%x",
897         (guint) hr);
898     swap_chain = NULL;
899   }
900 
901   return swap_chain;
902 }
903 
904 #if (GST_D3D11_DXGI_HEADER_VERSION >= 2)
905 static IDXGISwapChain1 *
create_swap_chain_for_hwnd(GstD3D11WindowWin32 * self,GstD3D11Device * device,HWND hwnd,DXGI_SWAP_CHAIN_DESC1 * desc,DXGI_SWAP_CHAIN_FULLSCREEN_DESC * fullscreen_desc,IDXGIOutput * output)906 create_swap_chain_for_hwnd (GstD3D11WindowWin32 * self, GstD3D11Device * device,
907     HWND hwnd, DXGI_SWAP_CHAIN_DESC1 * desc,
908     DXGI_SWAP_CHAIN_FULLSCREEN_DESC * fullscreen_desc, IDXGIOutput * output)
909 {
910   HRESULT hr;
911   IDXGISwapChain1 *swap_chain = NULL;
912   ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
913   IDXGIFactory1 *factory = gst_d3d11_device_get_dxgi_factory_handle (device);
914   ComPtr < IDXGIFactory2 > factory2;
915 
916   hr = factory->QueryInterface (IID_PPV_ARGS (&factory2));
917   if (!gst_d3d11_result (hr, device)) {
918     GST_WARNING_OBJECT (self, "IDXGIFactory2 interface is unavailable");
919     return NULL;
920   }
921 
922   gst_d3d11_device_lock (device);
923   hr = factory2->CreateSwapChainForHwnd (device_handle, hwnd, desc,
924       fullscreen_desc, output, &swap_chain);
925   gst_d3d11_device_unlock (device);
926 
927   if (!gst_d3d11_result (hr, device)) {
928     GST_WARNING_OBJECT (self, "Cannot create SwapChain Object: 0x%x",
929         (guint) hr);
930     swap_chain = NULL;
931   }
932 
933   return swap_chain;
934 }
935 #endif
936 
937 static gboolean
gst_d3d11_window_win32_create_swap_chain(GstD3D11Window * window,DXGI_FORMAT format,guint width,guint height,guint swapchain_flags,IDXGISwapChain ** swap_chain)938 gst_d3d11_window_win32_create_swap_chain (GstD3D11Window * window,
939     DXGI_FORMAT format, guint width, guint height,
940     guint swapchain_flags, IDXGISwapChain ** swap_chain)
941 {
942   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
943   DXGI_SWAP_CHAIN_DESC desc = { 0, };
944   IDXGISwapChain *new_swapchain = NULL;
945   GstD3D11Device *device = window->device;
946 
947   self->have_swapchain1 = FALSE;
948 
949 #if (GST_D3D11_DXGI_HEADER_VERSION >= 2)
950   {
951     DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, };
952     desc1.Width = 0;
953     desc1.Height = 0;
954     desc1.Format = format;
955     /* FIXME: add support stereo */
956     desc1.Stereo = FALSE;
957     desc1.SampleDesc.Count = 1;
958     desc1.SampleDesc.Quality = 0;
959     desc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
960     desc1.BufferCount = 2;
961     desc1.Scaling = DXGI_SCALING_STRETCH;
962 
963     /* scaling-stretch would break aspect-ratio so we prefer to use scaling-none,
964      * but Windows7 does not support this method */
965     if (gst_d3d11_is_windows_8_or_greater ())
966       desc1.Scaling = DXGI_SCALING_NONE;
967     desc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
968     desc1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
969     desc1.Flags = swapchain_flags;
970 
971     new_swapchain = create_swap_chain_for_hwnd (self, device,
972         self->internal_hwnd, &desc1, NULL, NULL);
973 
974     if (!new_swapchain) {
975       GST_WARNING_OBJECT (self, "Failed to create swapchain1");
976     } else {
977       self->have_swapchain1 = TRUE;
978     }
979   }
980 #endif
981 
982   if (!new_swapchain) {
983     DXGI_SWAP_EFFECT swap_effect = DXGI_SWAP_EFFECT_DISCARD;
984 
985     if (gst_d3d11_is_windows_8_or_greater ())
986       swap_effect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
987 
988     /* we will get client area at on_resize */
989     desc.BufferDesc.Width = 0;
990     desc.BufferDesc.Height = 0;
991     /* don't care refresh rate */
992     desc.BufferDesc.RefreshRate.Numerator = 0;
993     desc.BufferDesc.RefreshRate.Denominator = 1;
994     desc.BufferDesc.Format = format;
995     desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
996     desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
997     desc.SampleDesc.Count = 1;
998     desc.SampleDesc.Quality = 0;
999     desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
1000     desc.BufferCount = 2;
1001     desc.SwapEffect = swap_effect;
1002     desc.OutputWindow = self->internal_hwnd;
1003     desc.Windowed = TRUE;
1004     desc.Flags = swapchain_flags;
1005 
1006     new_swapchain = create_swap_chain (self, device, &desc);
1007   }
1008 
1009   if (!new_swapchain) {
1010     GST_ERROR_OBJECT (self, "Cannot create swapchain");
1011     return FALSE;
1012   }
1013 
1014   /* disable alt+enter here. It should be manually handled */
1015   gst_d3d11_device_lock (device);
1016   gst_d3d11_window_win32_disable_alt_enter (self,
1017       device, new_swapchain, desc.OutputWindow);
1018   gst_d3d11_device_unlock (device);
1019 
1020   *swap_chain = new_swapchain;
1021 
1022   return TRUE;
1023 }
1024 
1025 static void
gst_d3d11_window_win32_set_window_handle(GstD3D11WindowWin32 * self,guintptr handle)1026 gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
1027     guintptr handle)
1028 {
1029   self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE;
1030 
1031   self->external_hwnd = (HWND) handle;
1032   gst_d3d11_window_win32_set_external_handle (self);
1033 
1034   self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED;
1035 }
1036 
1037 static void
gst_d3d11_window_win32_show(GstD3D11Window * window)1038 gst_d3d11_window_win32_show (GstD3D11Window * window)
1039 {
1040   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
1041   gint width, height;
1042 
1043   width = GST_VIDEO_INFO_WIDTH (&window->render_info);
1044   height = GST_VIDEO_INFO_HEIGHT (&window->render_info);
1045 
1046   if (!self->visible) {
1047     /* if no parent the real size has to be set now because this has not been done
1048      * when at window creation */
1049     if (!self->external_hwnd) {
1050       RECT rect;
1051       GetClientRect (self->internal_hwnd, &rect);
1052       width += 2 * GetSystemMetrics (SM_CXSIZEFRAME);
1053       height +=
1054           2 * GetSystemMetrics (SM_CYSIZEFRAME) +
1055           GetSystemMetrics (SM_CYCAPTION);
1056       MoveWindow (self->internal_hwnd, rect.left, rect.top, width,
1057           height, FALSE);
1058     }
1059 
1060     ShowWindow (self->internal_hwnd, SW_SHOW);
1061     self->visible = TRUE;
1062   }
1063 }
1064 
1065 static GstFlowReturn
gst_d3d11_window_win32_present(GstD3D11Window * window,guint present_flags)1066 gst_d3d11_window_win32_present (GstD3D11Window * window, guint present_flags)
1067 {
1068   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
1069   HRESULT hr;
1070 
1071   if ((!self->external_hwnd &&
1072           self->overlay_state == GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED)
1073       || !self->internal_hwnd) {
1074     GST_ERROR_OBJECT (self, "Output window was closed");
1075 
1076     return GST_D3D11_WINDOW_FLOW_CLOSED;
1077   }
1078 #if (GST_D3D11_DXGI_HEADER_VERSION >= 2)
1079   if (self->have_swapchain1) {
1080     IDXGISwapChain1 *swap_chain1 = (IDXGISwapChain1 *) window->swap_chain;
1081     DXGI_PRESENT_PARAMETERS present_params = { 0, };
1082 
1083     /* the first present should not specify dirty-rect */
1084     if (!window->first_present) {
1085       present_params.DirtyRectsCount = 1;
1086       present_params.pDirtyRects = &window->render_rect;
1087     }
1088 
1089     hr = swap_chain1->Present1 (0, present_flags, &present_params);
1090   } else
1091 #endif
1092   {
1093     hr = window->swap_chain->Present (0, present_flags);
1094   }
1095 
1096   if (!gst_d3d11_result (hr, window->device)) {
1097     GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
1098         (guint) hr);
1099   }
1100 
1101   return GST_FLOW_OK;
1102 }
1103 
1104 static void
gst_d3d11_window_win32_on_resize(GstD3D11Window * window,guint width,guint height)1105 gst_d3d11_window_win32_on_resize (GstD3D11Window * window,
1106     guint width, guint height)
1107 {
1108   /* Set zero width and height here. dxgi will decide client area by itself */
1109   GST_D3D11_WINDOW_CLASS (parent_class)->on_resize (window, 0, 0);
1110 }
1111 
1112 static void
gst_d3d11_window_win32_update_swap_chain(GstD3D11Window * window)1113 gst_d3d11_window_win32_update_swap_chain (GstD3D11Window * window)
1114 {
1115   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
1116 
1117   if (self->internal_hwnd)
1118     PostMessageA (self->internal_hwnd, WM_SIZE, 0, 0);
1119 
1120   return;
1121 }
1122 
1123 static void
gst_d3d11_window_win32_change_fullscreen_mode(GstD3D11Window * window)1124 gst_d3d11_window_win32_change_fullscreen_mode (GstD3D11Window * window)
1125 {
1126   GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
1127 
1128   if (self->internal_hwnd) {
1129     g_atomic_int_add (&self->pending_fullscreen_count, 1);
1130     PostMessageA (self->internal_hwnd, WM_GST_D3D11_FULLSCREEN, 0, 0);
1131   }
1132 }
1133 
1134 GstD3D11Window *
gst_d3d11_window_win32_new(GstD3D11Device * device,guintptr handle)1135 gst_d3d11_window_win32_new (GstD3D11Device * device, guintptr handle)
1136 {
1137   GstD3D11Window *window;
1138 
1139   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1140 
1141   window = (GstD3D11Window *) g_object_new (GST_TYPE_D3D11_WINDOW_WIN32,
1142       "d3d11device", device, "window-handle", handle, NULL);
1143   if (!window->initialized) {
1144     gst_object_unref (window);
1145     return NULL;
1146   }
1147 
1148   g_object_ref_sink (window);
1149 
1150   return window;
1151 }
1152