1 /*
2 * GStreamer
3 * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstd3d11window.h"
26 #include "gstd3d11pluginutils.h"
27
28 #if GST_D3D11_WINAPI_APP
29 /* workaround for GetCurrentTime collision */
30 #ifdef GetCurrentTime
31 #undef GetCurrentTime
32 #endif
33 #include <windows.ui.xaml.h>
34 #include <windows.applicationmodel.core.h>
35 #endif
36
37 #include <wrl.h>
38
39 /* *INDENT-OFF* */
40 using namespace Microsoft::WRL;
41 /* *INDENT-ON* */
42
43 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
44 #define GST_CAT_DEFAULT gst_d3d11_window_debug
45
46
47 enum
48 {
49 PROP_0,
50 PROP_D3D11_DEVICE,
51 PROP_FORCE_ASPECT_RATIO,
52 PROP_ENABLE_NAVIGATION_EVENTS,
53 PROP_FULLSCREEN_TOGGLE_MODE,
54 PROP_FULLSCREEN,
55 PROP_WINDOW_HANDLE,
56 PROP_RENDER_STATS,
57 };
58
59 #define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
60 #define DEFAULT_FORCE_ASPECT_RATIO TRUE
61 #define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
62 #define DEFAULT_FULLSCREEN FALSE
63 #define DEFAULT_RENDER_STATS FALSE
64
65 enum
66 {
67 SIGNAL_KEY_EVENT,
68 SIGNAL_MOUSE_EVENT,
69 SIGNAL_LAST
70 };
71
72 static guint d3d11_window_signals[SIGNAL_LAST] = { 0, };
73
74 GType
gst_d3d11_window_fullscreen_toggle_mode_type(void)75 gst_d3d11_window_fullscreen_toggle_mode_type (void)
76 {
77 static gsize mode_type = 0;
78
79 if (g_once_init_enter (&mode_type)) {
80 static const GFlagsValue mode_types[] = {
81 {GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE,
82 "GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE", "none"},
83 {GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER,
84 "GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER", "alt-enter"},
85 {GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY,
86 "GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY", "property"},
87 {0, NULL, NULL},
88 };
89 GType tmp = g_flags_register_static ("GstD3D11WindowFullscreenToggleMode",
90 mode_types);
91 g_once_init_leave (&mode_type, tmp);
92 }
93
94 return (GType) mode_type;
95 }
96
97 #define gst_d3d11_window_parent_class parent_class
98 G_DEFINE_ABSTRACT_TYPE (GstD3D11Window, gst_d3d11_window, GST_TYPE_OBJECT);
99
100 static void gst_d3d11_window_set_property (GObject * object, guint prop_id,
101 const GValue * value, GParamSpec * pspec);
102 static void gst_d3d11_window_get_property (GObject * object, guint prop_id,
103 GValue * value, GParamSpec * pspec);
104 static void gst_d3d11_window_dispose (GObject * object);
105 static GstFlowReturn gst_d3d111_window_present (GstD3D11Window * self,
106 GstBuffer * buffer, ID3D11VideoProcessorOutputView * pov,
107 ID3D11RenderTargetView * rtv);
108 static void gst_d3d11_window_on_resize_default (GstD3D11Window * window,
109 guint width, guint height);
110 static gboolean gst_d3d11_window_prepare_default (GstD3D11Window * window,
111 guint display_width, guint display_height, GstCaps * caps,
112 gboolean * video_processor_available, GError ** error);
113
114 static void
gst_d3d11_window_class_init(GstD3D11WindowClass * klass)115 gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
116 {
117 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
118
119 gobject_class->set_property = gst_d3d11_window_set_property;
120 gobject_class->get_property = gst_d3d11_window_get_property;
121 gobject_class->dispose = gst_d3d11_window_dispose;
122
123 klass->on_resize = GST_DEBUG_FUNCPTR (gst_d3d11_window_on_resize_default);
124 klass->prepare = GST_DEBUG_FUNCPTR (gst_d3d11_window_prepare_default);
125
126 g_object_class_install_property (gobject_class, PROP_D3D11_DEVICE,
127 g_param_spec_object ("d3d11device", "D3D11 Device",
128 "GstD3D11Device object for creating swapchain",
129 GST_TYPE_D3D11_DEVICE,
130 (GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
131 G_PARAM_STATIC_STRINGS)));
132
133 g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
134 g_param_spec_boolean ("force-aspect-ratio",
135 "Force aspect ratio",
136 "When enabled, scaling will respect original aspect ratio",
137 DEFAULT_FORCE_ASPECT_RATIO,
138 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
139
140 g_object_class_install_property (gobject_class, PROP_ENABLE_NAVIGATION_EVENTS,
141 g_param_spec_boolean ("enable-navigation-events",
142 "Enable navigation events",
143 "When enabled, signals for navigation events are emitted",
144 DEFAULT_ENABLE_NAVIGATION_EVENTS,
145 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
146
147 g_object_class_install_property (gobject_class, PROP_FULLSCREEN_TOGGLE_MODE,
148 g_param_spec_flags ("fullscreen-toggle-mode",
149 "Full screen toggle mode",
150 "Full screen toggle mode used to trigger fullscreen mode change",
151 GST_D3D11_WINDOW_TOGGLE_MODE_GET_TYPE, DEFAULT_FULLSCREEN_TOGGLE_MODE,
152 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
153
154 g_object_class_install_property (gobject_class, PROP_FULLSCREEN,
155 g_param_spec_boolean ("fullscreen",
156 "fullscreen",
157 "Ignored when \"fullscreen-toggle-mode\" does not include \"property\"",
158 DEFAULT_FULLSCREEN,
159 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
160
161 g_object_class_install_property (gobject_class, PROP_WINDOW_HANDLE,
162 g_param_spec_pointer ("window-handle",
163 "Window Handle", "External Window Handle",
164 (GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
165 G_PARAM_STATIC_STRINGS)));
166
167 d3d11_window_signals[SIGNAL_KEY_EVENT] =
168 g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass),
169 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
170 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
171
172 d3d11_window_signals[SIGNAL_MOUSE_EVENT] =
173 g_signal_new ("mouse-event", G_TYPE_FROM_CLASS (klass),
174 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
175 G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
176 }
177
178 static void
gst_d3d11_window_init(GstD3D11Window * self)179 gst_d3d11_window_init (GstD3D11Window * self)
180 {
181 self->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
182 self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
183 self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE;
184 self->fullscreen = DEFAULT_FULLSCREEN;
185 self->render_stats = DEFAULT_RENDER_STATS;
186 }
187
188 static void
gst_d3d11_window_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)189 gst_d3d11_window_set_property (GObject * object, guint prop_id,
190 const GValue * value, GParamSpec * pspec)
191 {
192 GstD3D11Window *self = GST_D3D11_WINDOW (object);
193 GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (object);
194
195 switch (prop_id) {
196 case PROP_D3D11_DEVICE:
197 self->device = (GstD3D11Device *) g_value_dup_object (value);
198 break;
199 case PROP_FORCE_ASPECT_RATIO:
200 {
201 self->force_aspect_ratio = g_value_get_boolean (value);
202 if (self->swap_chain)
203 klass->update_swap_chain (self);
204 break;
205 }
206 case PROP_ENABLE_NAVIGATION_EVENTS:
207 self->enable_navigation_events = g_value_get_boolean (value);
208 break;
209 case PROP_FULLSCREEN_TOGGLE_MODE:
210 self->fullscreen_toggle_mode =
211 (GstD3D11WindowFullscreenToggleMode) g_value_get_flags (value);
212 break;
213 case PROP_FULLSCREEN:
214 {
215 self->requested_fullscreen = g_value_get_boolean (value);
216 if (self->swap_chain)
217 klass->change_fullscreen_mode (self);
218 break;
219 }
220 case PROP_WINDOW_HANDLE:
221 self->external_handle = (guintptr) g_value_get_pointer (value);
222 break;
223 default:
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 break;
226 }
227 }
228
229 static void
gst_d3d11_window_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)230 gst_d3d11_window_get_property (GObject * object, guint prop_id,
231 GValue * value, GParamSpec * pspec)
232 {
233 GstD3D11Window *self = GST_D3D11_WINDOW (object);
234
235 switch (prop_id) {
236 case PROP_ENABLE_NAVIGATION_EVENTS:
237 g_value_set_boolean (value, self->enable_navigation_events);
238 break;
239 case PROP_FORCE_ASPECT_RATIO:
240 g_value_set_boolean (value, self->force_aspect_ratio);
241 break;
242 case PROP_FULLSCREEN_TOGGLE_MODE:
243 g_value_set_flags (value, self->fullscreen_toggle_mode);
244 break;
245 case PROP_FULLSCREEN:
246 g_value_set_boolean (value, self->fullscreen);
247 break;
248 default:
249 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
250 break;
251 }
252 }
253
254 static void
gst_d3d11_window_release_resources(GstD3D11Device * device,GstD3D11Window * window)255 gst_d3d11_window_release_resources (GstD3D11Device * device,
256 GstD3D11Window * window)
257 {
258 GST_D3D11_CLEAR_COM (window->rtv);
259 GST_D3D11_CLEAR_COM (window->pov);
260 GST_D3D11_CLEAR_COM (window->swap_chain);
261 }
262
263 static void
gst_d3d11_window_dispose(GObject * object)264 gst_d3d11_window_dispose (GObject * object)
265 {
266 GstD3D11Window *self = GST_D3D11_WINDOW (object);
267
268 if (self->device) {
269 gst_d3d11_window_release_resources (self->device, self);
270 }
271
272 g_clear_pointer (&self->processor, gst_d3d11_video_processor_free);
273 g_clear_pointer (&self->converter, gst_d3d11_converter_free);
274 g_clear_pointer (&self->compositor, gst_d3d11_overlay_compositor_free);
275
276 gst_clear_buffer (&self->cached_buffer);
277 gst_clear_object (&self->device);
278
279 G_OBJECT_CLASS (parent_class)->dispose (object);
280 }
281
282 static void
gst_d3d11_window_on_resize_default(GstD3D11Window * window,guint width,guint height)283 gst_d3d11_window_on_resize_default (GstD3D11Window * window, guint width,
284 guint height)
285 {
286 HRESULT hr;
287 ID3D11Device *device_handle;
288 D3D11_TEXTURE2D_DESC desc;
289 DXGI_SWAP_CHAIN_DESC swap_desc;
290 ID3D11Texture2D *backbuffer = NULL;
291 GstVideoRectangle src_rect, dst_rect, rst_rect;
292 IDXGISwapChain *swap_chain;
293
294 gst_d3d11_device_lock (window->device);
295 if (!window->swap_chain)
296 goto done;
297
298 device_handle = gst_d3d11_device_get_device_handle (window->device);
299 swap_chain = window->swap_chain;
300
301 GST_D3D11_CLEAR_COM (window->rtv);
302 GST_D3D11_CLEAR_COM (window->pov);
303
304 swap_chain->GetDesc (&swap_desc);
305 hr = swap_chain->ResizeBuffers (0, width, height, window->dxgi_format,
306 swap_desc.Flags);
307 if (!gst_d3d11_result (hr, window->device)) {
308 GST_ERROR_OBJECT (window, "Couldn't resize buffers, hr: 0x%x", (guint) hr);
309 goto done;
310 }
311
312 hr = swap_chain->GetBuffer (0, IID_PPV_ARGS (&backbuffer));
313 if (!gst_d3d11_result (hr, window->device)) {
314 GST_ERROR_OBJECT (window,
315 "Cannot get backbuffer from swapchain, hr: 0x%x", (guint) hr);
316 goto done;
317 }
318
319 backbuffer->GetDesc (&desc);
320 window->surface_width = desc.Width;
321 window->surface_height = desc.Height;
322
323 {
324 dst_rect.x = 0;
325 dst_rect.y = 0;
326 dst_rect.w = window->surface_width;
327 dst_rect.h = window->surface_height;
328
329 if (window->force_aspect_ratio) {
330 src_rect.x = 0;
331 src_rect.y = 0;
332 src_rect.w = GST_VIDEO_INFO_WIDTH (&window->render_info);
333 src_rect.h = GST_VIDEO_INFO_HEIGHT (&window->render_info);
334
335 gst_video_sink_center_rect (src_rect, dst_rect, &rst_rect, TRUE);
336 } else {
337 rst_rect = dst_rect;
338 }
339 }
340
341 window->render_rect.left = rst_rect.x;
342 window->render_rect.top = rst_rect.y;
343 window->render_rect.right = rst_rect.x + rst_rect.w;
344 window->render_rect.bottom = rst_rect.y + rst_rect.h;
345
346 GST_LOG_OBJECT (window,
347 "New client area %dx%d, render rect x: %d, y: %d, %dx%d",
348 desc.Width, desc.Height, rst_rect.x, rst_rect.y, rst_rect.w, rst_rect.h);
349
350 hr = device_handle->CreateRenderTargetView (backbuffer, NULL, &window->rtv);
351 if (!gst_d3d11_result (hr, window->device)) {
352 GST_ERROR_OBJECT (window, "Cannot create render target view, hr: 0x%x",
353 (guint) hr);
354
355 goto done;
356 }
357
358 if (window->processor) {
359 D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC pov_desc;
360
361 pov_desc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
362 pov_desc.Texture2D.MipSlice = 0;
363
364 if (!gst_d3d11_video_processor_create_output_view (window->processor,
365 &pov_desc, backbuffer, &window->pov))
366 goto done;
367 }
368
369 window->first_present = TRUE;
370
371 /* redraw the last scene if cached buffer exits */
372 if (window->cached_buffer) {
373 gst_d3d111_window_present (window, window->cached_buffer,
374 window->pov, window->rtv);
375 }
376
377 done:
378 GST_D3D11_CLEAR_COM (backbuffer);
379
380 gst_d3d11_device_unlock (window->device);
381 }
382
383 void
gst_d3d11_window_on_key_event(GstD3D11Window * window,const gchar * event,const gchar * key)384 gst_d3d11_window_on_key_event (GstD3D11Window * window, const gchar * event,
385 const gchar * key)
386 {
387 g_return_if_fail (GST_IS_D3D11_WINDOW (window));
388
389 if (!window->enable_navigation_events)
390 return;
391
392 g_signal_emit (window, d3d11_window_signals[SIGNAL_KEY_EVENT], 0, event, key);
393 }
394
395 void
gst_d3d11_window_on_mouse_event(GstD3D11Window * window,const gchar * event,gint button,gdouble x,gdouble y)396 gst_d3d11_window_on_mouse_event (GstD3D11Window * window, const gchar * event,
397 gint button, gdouble x, gdouble y)
398 {
399 g_return_if_fail (GST_IS_D3D11_WINDOW (window));
400
401 if (!window->enable_navigation_events)
402 return;
403
404 g_signal_emit (window, d3d11_window_signals[SIGNAL_MOUSE_EVENT], 0,
405 event, button, x, y);
406 }
407
408 typedef struct
409 {
410 DXGI_FORMAT dxgi_format;
411 GstVideoFormat gst_format;
412 gboolean supported;
413 } GstD3D11WindowDisplayFormat;
414
415 gboolean
gst_d3d11_window_prepare(GstD3D11Window * window,guint display_width,guint display_height,GstCaps * caps,gboolean * video_processor_available,GError ** error)416 gst_d3d11_window_prepare (GstD3D11Window * window, guint display_width,
417 guint display_height, GstCaps * caps, gboolean * video_processor_available,
418 GError ** error)
419 {
420 GstD3D11WindowClass *klass;
421
422 g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
423
424 klass = GST_D3D11_WINDOW_GET_CLASS (window);
425 g_assert (klass->prepare != NULL);
426
427 GST_DEBUG_OBJECT (window, "Prepare window, display resolution %dx%d, caps %"
428 GST_PTR_FORMAT, display_width, display_height, caps);
429
430 return klass->prepare (window, display_width, display_height, caps,
431 video_processor_available, error);
432 }
433
434 static gboolean
gst_d3d11_window_prepare_default(GstD3D11Window * window,guint display_width,guint display_height,GstCaps * caps,gboolean * video_processor_available,GError ** error)435 gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width,
436 guint display_height, GstCaps * caps, gboolean * video_processor_available,
437 GError ** error)
438 {
439 GstD3D11WindowClass *klass;
440 guint swapchain_flags = 0;
441 ID3D11Device *device_handle;
442 guint i;
443 guint num_supported_format = 0;
444 HRESULT hr;
445 UINT display_flags =
446 D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_DISPLAY;
447 UINT supported_flags = 0;
448 GstD3D11WindowDisplayFormat formats[] = {
449 {DXGI_FORMAT_R8G8B8A8_UNORM, GST_VIDEO_FORMAT_RGBA, FALSE},
450 {DXGI_FORMAT_B8G8R8A8_UNORM, GST_VIDEO_FORMAT_BGRA, FALSE},
451 {DXGI_FORMAT_R10G10B10A2_UNORM, GST_VIDEO_FORMAT_RGB10A2_LE, FALSE},
452 };
453 const GstD3D11WindowDisplayFormat *chosen_format = NULL;
454 const GstDxgiColorSpace *chosen_colorspace = NULL;
455 #if (GST_D3D11_DXGI_HEADER_VERSION >= 4)
456 gboolean have_hdr10 = FALSE;
457 DXGI_COLOR_SPACE_TYPE native_colorspace_type =
458 DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
459 #endif
460 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
461 DXGI_HDR_METADATA_HDR10 hdr10_metadata = { 0, };
462 #endif
463
464 /* Step 1: Clear old resources and objects */
465 gst_clear_buffer (&window->cached_buffer);
466 g_clear_pointer (&window->processor, gst_d3d11_video_processor_free);
467 g_clear_pointer (&window->converter, gst_d3d11_converter_free);
468 g_clear_pointer (&window->compositor, gst_d3d11_overlay_compositor_free);
469
470 window->processor_in_use = FALSE;
471
472 /* Step 2: Decide display color format
473 * If upstream format is 10bits, try DXGI_FORMAT_R10G10B10A2_UNORM first
474 * Otherwise, use DXGI_FORMAT_B8G8R8A8_UNORM or DXGI_FORMAT_B8G8R8A8_UNORM
475 */
476 gst_video_info_from_caps (&window->info, caps);
477 device_handle = gst_d3d11_device_get_device_handle (window->device);
478 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
479 hr = device_handle->CheckFormatSupport (formats[i].dxgi_format,
480 &supported_flags);
481 if (SUCCEEDED (hr) && (supported_flags & display_flags) == display_flags) {
482 GST_DEBUG_OBJECT (window, "Device supports format %s (DXGI_FORMAT %d)",
483 gst_video_format_to_string (formats[i].gst_format),
484 formats[i].dxgi_format);
485 formats[i].supported = TRUE;
486 num_supported_format++;
487 }
488 }
489
490 if (num_supported_format == 0) {
491 GST_ERROR_OBJECT (window, "Cannot determine render format");
492 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
493 "Cannot determine render format");
494 return FALSE;
495 }
496
497 for (i = 0; i < GST_VIDEO_INFO_N_COMPONENTS (&window->info); i++) {
498 if (GST_VIDEO_INFO_COMP_DEPTH (&window->info, i) > 8) {
499 if (formats[2].supported) {
500 chosen_format = &formats[2];
501 }
502 break;
503 }
504 }
505
506 if (!chosen_format) {
507 /* prefer native format over conversion */
508 for (i = 0; i < 2; i++) {
509 if (formats[i].supported &&
510 formats[i].gst_format == GST_VIDEO_INFO_FORMAT (&window->info)) {
511 chosen_format = &formats[i];
512 break;
513 }
514 }
515
516 /* choose any color space then */
517 if (!chosen_format) {
518 for (i = 0; i < G_N_ELEMENTS (formats); i++) {
519 if (formats[i].supported) {
520 chosen_format = &formats[i];
521 break;
522 }
523 }
524 }
525 }
526
527 g_assert (chosen_format != NULL);
528
529 GST_DEBUG_OBJECT (window, "chosen render format %s (DXGI_FORMAT %d)",
530 gst_video_format_to_string (chosen_format->gst_format),
531 chosen_format->dxgi_format);
532
533 /* Step 3: Create swapchain
534 * (or reuse old swapchain if the format is not changed) */
535 window->allow_tearing = FALSE;
536
537 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
538 {
539 ComPtr < IDXGIFactory5 > factory5;
540 IDXGIFactory1 *factory_handle;
541 BOOL allow_tearing = FALSE;
542
543 factory_handle = gst_d3d11_device_get_dxgi_factory_handle (window->device);
544 hr = factory_handle->QueryInterface (IID_PPV_ARGS (&factory5));
545 if (SUCCEEDED (hr)) {
546 hr = factory5->CheckFeatureSupport (DXGI_FEATURE_PRESENT_ALLOW_TEARING,
547 (void *) &allow_tearing, sizeof (allow_tearing));
548 }
549
550 if (SUCCEEDED (hr) && allow_tearing)
551 window->allow_tearing = allow_tearing;
552 }
553 #endif
554
555 if (window->allow_tearing) {
556 GST_DEBUG_OBJECT (window, "device support tearning");
557 swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
558 }
559
560 gst_d3d11_device_lock (window->device);
561 window->dxgi_format = chosen_format->dxgi_format;
562
563 klass = GST_D3D11_WINDOW_GET_CLASS (window);
564 if (!window->swap_chain &&
565 !klass->create_swap_chain (window, window->dxgi_format,
566 display_width, display_height, swapchain_flags,
567 &window->swap_chain)) {
568 GST_ERROR_OBJECT (window, "Cannot create swapchain");
569 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
570 "Cannot create swapchain");
571 goto error;
572 }
573
574 /* this rect struct will be used to calculate render area */
575 window->render_rect.left = 0;
576 window->render_rect.top = 0;
577 window->render_rect.right = display_width;
578 window->render_rect.bottom = display_height;
579
580 window->input_rect.left = 0;
581 window->input_rect.top = 0;
582 window->input_rect.right = GST_VIDEO_INFO_WIDTH (&window->info);
583 window->input_rect.bottom = GST_VIDEO_INFO_HEIGHT (&window->info);
584
585 /* Step 4: Decide render color space and set it on converter/processor */
586 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
587 {
588 GstVideoMasteringDisplayInfo minfo;
589 GstVideoContentLightLevel cll;
590
591 if (gst_video_mastering_display_info_from_caps (&minfo, caps) &&
592 gst_video_content_light_level_from_caps (&cll, caps)) {
593 ComPtr < IDXGISwapChain4 > swapchain4;
594 HRESULT hr;
595
596 hr = window->swap_chain->QueryInterface (IID_PPV_ARGS (&swapchain4));
597 if (gst_d3d11_result (hr, window->device)) {
598 GST_DEBUG_OBJECT (window, "Have HDR metadata, set to DXGI swapchain");
599
600 gst_d3d11_hdr_meta_data_to_dxgi (&minfo, &cll, &hdr10_metadata);
601
602 hr = swapchain4->SetHDRMetaData (DXGI_HDR_METADATA_TYPE_HDR10,
603 sizeof (DXGI_HDR_METADATA_HDR10), &hdr10_metadata);
604 if (!gst_d3d11_result (hr, window->device)) {
605 GST_WARNING_OBJECT (window, "Couldn't set HDR metadata, hr 0x%x",
606 (guint) hr);
607 } else {
608 have_hdr10 = TRUE;
609 }
610 }
611 }
612 }
613 #endif
614
615 /* Step 5: Choose display color space */
616 gst_video_info_set_format (&window->render_info,
617 chosen_format->gst_format, display_width, display_height);
618
619 /* preserve upstream colorimetry */
620 window->render_info.colorimetry.primaries =
621 window->info.colorimetry.primaries;
622 window->render_info.colorimetry.transfer = window->info.colorimetry.transfer;
623 /* prefer FULL range RGB. STUDIO range doesn't seem to be well supported
624 * color space by GPUs and we don't need to preserve color range for
625 * target display color space type */
626 window->render_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
627
628 #if (GST_D3D11_DXGI_HEADER_VERSION >= 4)
629 {
630 ComPtr < IDXGISwapChain3 > swapchain3;
631 HRESULT hr;
632
633 hr = window->swap_chain->QueryInterface (IID_PPV_ARGS (&swapchain3));
634
635 if (gst_d3d11_result (hr, window->device)) {
636 chosen_colorspace =
637 gst_d3d11_find_swap_chain_color_space (&window->render_info,
638 swapchain3.Get ());
639 if (chosen_colorspace) {
640 native_colorspace_type =
641 (DXGI_COLOR_SPACE_TYPE) chosen_colorspace->dxgi_color_space_type;
642 hr = swapchain3->SetColorSpace1 (native_colorspace_type);
643 if (!gst_d3d11_result (hr, window->device)) {
644 GST_WARNING_OBJECT (window, "Failed to set colorspace %d, hr: 0x%x",
645 native_colorspace_type, (guint) hr);
646 chosen_colorspace = NULL;
647 native_colorspace_type = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
648 } else {
649 GST_DEBUG_OBJECT (window,
650 "Set colorspace %d", native_colorspace_type);
651
652 /* update with selected display color space */
653 window->render_info.colorimetry.primaries =
654 chosen_colorspace->primaries;
655 window->render_info.colorimetry.transfer =
656 chosen_colorspace->transfer;
657 window->render_info.colorimetry.range = chosen_colorspace->range;
658 window->render_info.colorimetry.matrix = chosen_colorspace->matrix;
659 }
660 }
661 }
662 }
663 #endif
664
665 /* otherwise, use most common DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
666 * color space */
667 if (!chosen_colorspace) {
668 GST_DEBUG_OBJECT (window, "No selected render color space, use BT709");
669 window->render_info.colorimetry.primaries = GST_VIDEO_COLOR_PRIMARIES_BT709;
670 window->render_info.colorimetry.transfer = GST_VIDEO_TRANSFER_BT709;
671 window->render_info.colorimetry.range = GST_VIDEO_COLOR_RANGE_0_255;
672 }
673 #if (GST_D3D11_DXGI_HEADER_VERSION >= 4)
674 if (chosen_colorspace) {
675 const GstDxgiColorSpace *in_color_space =
676 gst_d3d11_video_info_to_dxgi_color_space (&window->info);
677 const GstD3D11Format *in_format =
678 gst_d3d11_device_format_from_gst (window->device,
679 GST_VIDEO_INFO_FORMAT (&window->info));
680 gboolean hardware = FALSE;
681 GstD3D11VideoProcessor *processor = NULL;
682
683 if (in_color_space && in_format &&
684 in_format->dxgi_format != DXGI_FORMAT_UNKNOWN) {
685 g_object_get (window->device, "hardware", &hardware, NULL);
686 }
687
688 if (hardware) {
689 processor =
690 gst_d3d11_video_processor_new (window->device,
691 GST_VIDEO_INFO_WIDTH (&window->info),
692 GST_VIDEO_INFO_HEIGHT (&window->info), display_width, display_height);
693 }
694
695 if (processor) {
696 DXGI_FORMAT in_dxgi_format = in_format->dxgi_format;
697 DXGI_FORMAT out_dxgi_format = chosen_format->dxgi_format;
698 DXGI_COLOR_SPACE_TYPE in_dxgi_color_space =
699 (DXGI_COLOR_SPACE_TYPE) in_color_space->dxgi_color_space_type;
700 DXGI_COLOR_SPACE_TYPE out_dxgi_color_space = native_colorspace_type;
701
702 if (!gst_d3d11_video_processor_check_format_conversion (processor,
703 in_dxgi_format, in_dxgi_color_space, out_dxgi_format,
704 out_dxgi_color_space)) {
705 GST_DEBUG_OBJECT (window, "Conversion is not supported by device");
706 gst_d3d11_video_processor_free (processor);
707 processor = NULL;
708 } else {
709 GST_DEBUG_OBJECT (window, "video processor supports conversion");
710 gst_d3d11_video_processor_set_input_dxgi_color_space (processor,
711 in_dxgi_color_space);
712 gst_d3d11_video_processor_set_output_dxgi_color_space (processor,
713 out_dxgi_color_space);
714
715 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
716 if (have_hdr10) {
717 GST_DEBUG_OBJECT (window, "Set HDR metadata on video processor");
718 gst_d3d11_video_processor_set_input_hdr10_metadata (processor,
719 &hdr10_metadata);
720 gst_d3d11_video_processor_set_output_hdr10_metadata (processor,
721 &hdr10_metadata);
722 }
723 #endif
724 }
725
726 window->processor = processor;
727 }
728 }
729 #endif
730 *video_processor_available = !!window->processor;
731
732 /* configure shader even if video processor is available for fallback */
733 window->converter =
734 gst_d3d11_converter_new (window->device, &window->info,
735 &window->render_info, nullptr);
736
737 if (!window->converter) {
738 GST_ERROR_OBJECT (window, "Cannot create converter");
739 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
740 "Cannot create converter");
741 goto error;
742 }
743
744 window->compositor =
745 gst_d3d11_overlay_compositor_new (window->device, &window->render_info);
746 if (!window->compositor) {
747 GST_ERROR_OBJECT (window, "Cannot create overlay compositor");
748 g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_FAILED,
749 "Cannot create overlay compositor");
750 goto error;
751 }
752 gst_d3d11_device_unlock (window->device);
753
754 /* call resize to allocated resources */
755 klass->on_resize (window, display_width, display_height);
756
757 if (window->requested_fullscreen != window->fullscreen) {
758 klass->change_fullscreen_mode (window);
759 }
760
761 GST_DEBUG_OBJECT (window, "New swap chain 0x%p created", window->swap_chain);
762
763 return TRUE;
764
765 error:
766 gst_d3d11_device_unlock (window->device);
767
768 return FALSE;
769 }
770
771 void
gst_d3d11_window_show(GstD3D11Window * window)772 gst_d3d11_window_show (GstD3D11Window * window)
773 {
774 GstD3D11WindowClass *klass;
775
776 g_return_if_fail (GST_IS_D3D11_WINDOW (window));
777
778 klass = GST_D3D11_WINDOW_GET_CLASS (window);
779
780 if (klass->show)
781 klass->show (window);
782 }
783
784 void
gst_d3d11_window_set_render_rectangle(GstD3D11Window * window,const GstVideoRectangle * rect)785 gst_d3d11_window_set_render_rectangle (GstD3D11Window * window,
786 const GstVideoRectangle * rect)
787 {
788 GstD3D11WindowClass *klass;
789
790 g_return_if_fail (GST_IS_D3D11_WINDOW (window));
791
792 klass = GST_D3D11_WINDOW_GET_CLASS (window);
793
794 if (klass->set_render_rectangle)
795 klass->set_render_rectangle (window, rect);
796 }
797
798 void
gst_d3d11_window_set_title(GstD3D11Window * window,const gchar * title)799 gst_d3d11_window_set_title (GstD3D11Window * window, const gchar * title)
800 {
801 GstD3D11WindowClass *klass;
802
803 g_return_if_fail (GST_IS_D3D11_WINDOW (window));
804
805 klass = GST_D3D11_WINDOW_GET_CLASS (window);
806
807 if (klass->set_title)
808 klass->set_title (window, title);
809 }
810
811 static gboolean
gst_d3d11_window_buffer_ensure_processor_input(GstD3D11Window * self,GstBuffer * buffer,ID3D11VideoProcessorInputView ** in_view)812 gst_d3d11_window_buffer_ensure_processor_input (GstD3D11Window * self,
813 GstBuffer * buffer, ID3D11VideoProcessorInputView ** in_view)
814 {
815 GstD3D11Memory *mem;
816 ID3D11VideoProcessorInputView *piv;
817
818 if (!self->processor)
819 return FALSE;
820
821 if (gst_buffer_n_memory (buffer) != 1)
822 return FALSE;
823
824 mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
825 piv = gst_d3d11_video_processor_get_input_view (self->processor, mem);
826 if (!piv) {
827 GST_LOG_OBJECT (self, "Failed to get processor input view");
828 return FALSE;
829 }
830
831 *in_view = piv;
832
833 return TRUE;
834 }
835
836 static gboolean
gst_d3d11_window_do_processor(GstD3D11Window * self,ID3D11VideoProcessorInputView * piv,ID3D11VideoProcessorOutputView * pov,RECT * input_rect)837 gst_d3d11_window_do_processor (GstD3D11Window * self,
838 ID3D11VideoProcessorInputView * piv, ID3D11VideoProcessorOutputView * pov,
839 RECT * input_rect)
840 {
841 gboolean ret;
842
843 ret = gst_d3d11_video_processor_render_unlocked (self->processor,
844 input_rect, piv, &self->render_rect, pov);
845 if (!ret) {
846 GST_ERROR_OBJECT (self, "Couldn't render to backbuffer using processor");
847 } else {
848 GST_TRACE_OBJECT (self, "Rendered using processor");
849 self->processor_in_use = TRUE;
850 }
851
852 return ret;
853 }
854
855 static gboolean
gst_d3d11_window_do_convert(GstD3D11Window * self,ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],ID3D11RenderTargetView * rtv,RECT * input_rect)856 gst_d3d11_window_do_convert (GstD3D11Window * self,
857 ID3D11ShaderResourceView * srv[GST_VIDEO_MAX_PLANES],
858 ID3D11RenderTargetView * rtv, RECT * input_rect)
859 {
860 if (!gst_d3d11_converter_update_src_rect (self->converter, input_rect)) {
861 GST_ERROR_OBJECT (self, "Failed to update src rect");
862 return FALSE;
863 }
864
865 if (!gst_d3d11_converter_convert_unlocked (self->converter,
866 srv, &rtv, NULL, NULL)) {
867 GST_ERROR_OBJECT (self, "Couldn't render to backbuffer using converter");
868 return FALSE;
869 } else {
870 GST_TRACE_OBJECT (self, "Rendered using converter");
871 }
872
873 return TRUE;
874 }
875
876 static GstFlowReturn
gst_d3d111_window_present(GstD3D11Window * self,GstBuffer * buffer,ID3D11VideoProcessorOutputView * pov,ID3D11RenderTargetView * rtv)877 gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
878 ID3D11VideoProcessorOutputView * pov, ID3D11RenderTargetView * rtv)
879 {
880 GstD3D11WindowClass *klass = GST_D3D11_WINDOW_GET_CLASS (self);
881 GstFlowReturn ret = GST_FLOW_OK;
882 guint present_flags = 0;
883
884 if (!buffer)
885 return GST_FLOW_OK;
886
887 {
888 GstMapInfo infos[GST_VIDEO_MAX_PLANES];
889 ID3D11ShaderResourceView *srv[GST_VIDEO_MAX_PLANES];
890 ID3D11VideoProcessorInputView *piv = NULL;
891 ID3D11Device *device_handle =
892 gst_d3d11_device_get_device_handle (self->device);
893 gboolean can_convert = FALSE;
894 gboolean can_process = FALSE;
895 gboolean convert_ret = FALSE;
896 RECT input_rect = self->input_rect;
897 GstVideoCropMeta *crop_meta;
898
899 /* Map memory in any case so that we can upload pending stage texture */
900 if (!gst_d3d11_buffer_map (buffer, device_handle, infos, GST_MAP_READ)) {
901 GST_ERROR_OBJECT (self, "Couldn't map buffer");
902 return GST_FLOW_ERROR;
903 }
904
905 can_convert = gst_d3d11_buffer_get_shader_resource_view (buffer, srv);
906 if (pov) {
907 can_process = gst_d3d11_window_buffer_ensure_processor_input (self,
908 buffer, &piv);
909 }
910
911 if (!can_convert && !can_process) {
912 GST_ERROR_OBJECT (self, "Input texture cannot be used for converter");
913 return GST_FLOW_ERROR;
914 }
915
916 crop_meta = gst_buffer_get_video_crop_meta (buffer);
917 /* Do minimal validate */
918 if (crop_meta) {
919 ID3D11Texture2D *texture = (ID3D11Texture2D *) infos[0].data;
920 D3D11_TEXTURE2D_DESC desc = { 0, };
921
922 texture->GetDesc (&desc);
923
924 if (desc.Width < crop_meta->x + crop_meta->width ||
925 desc.Height < crop_meta->y + crop_meta->height) {
926 GST_WARNING_OBJECT (self, "Invalid crop meta, ignore");
927
928 crop_meta = nullptr;
929 }
930 }
931
932 if (crop_meta) {
933 input_rect.left = crop_meta->x;
934 input_rect.right = crop_meta->x + crop_meta->width;
935 input_rect.top = crop_meta->y;
936 input_rect.bottom = crop_meta->y + crop_meta->height;
937 }
938
939 if (self->first_present) {
940 D3D11_VIEWPORT viewport;
941
942 viewport.TopLeftX = self->render_rect.left;
943 viewport.TopLeftY = self->render_rect.top;
944 viewport.Width = self->render_rect.right - self->render_rect.left;
945 viewport.Height = self->render_rect.bottom - self->render_rect.top;
946 viewport.MinDepth = 0.0f;
947 viewport.MaxDepth = 1.0f;
948 gst_d3d11_converter_update_viewport (self->converter, &viewport);
949 gst_d3d11_overlay_compositor_update_viewport (self->compositor,
950 &viewport);
951 }
952
953 /* Converter preference order
954 * 1) If this texture can be converted via processor, and we used processor
955 * previously, use processor
956 * 2) If SRV is available, use converter
957 * 3) otherwise, use processor
958 */
959 if (can_process && self->processor_in_use) {
960 convert_ret = gst_d3d11_window_do_processor (self, piv, pov, &input_rect);
961 } else if (can_convert) {
962 convert_ret = gst_d3d11_window_do_convert (self, srv, rtv, &input_rect);
963 } else if (can_process) {
964 convert_ret = gst_d3d11_window_do_processor (self, piv, pov, &input_rect);
965 } else {
966 g_assert_not_reached ();
967 ret = GST_FLOW_ERROR;
968 goto unmap_and_out;
969 }
970
971 if (!convert_ret) {
972 ret = GST_FLOW_ERROR;
973 goto unmap_and_out;
974 }
975
976 gst_d3d11_overlay_compositor_upload (self->compositor, buffer);
977 gst_d3d11_overlay_compositor_draw_unlocked (self->compositor, &rtv);
978
979 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
980 if (self->allow_tearing && self->fullscreen) {
981 present_flags |= DXGI_PRESENT_ALLOW_TEARING;
982 }
983 #endif
984
985 if (klass->present)
986 ret = klass->present (self, present_flags);
987
988 self->first_present = FALSE;
989
990 unmap_and_out:
991 gst_d3d11_buffer_unmap (buffer, infos);
992 }
993
994 return ret;
995 }
996
997 GstFlowReturn
gst_d3d11_window_render(GstD3D11Window * window,GstBuffer * buffer)998 gst_d3d11_window_render (GstD3D11Window * window, GstBuffer * buffer)
999 {
1000 GstMemory *mem;
1001 GstFlowReturn ret;
1002
1003 g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
1004
1005 if (buffer) {
1006 mem = gst_buffer_peek_memory (buffer, 0);
1007 if (!gst_is_d3d11_memory (mem)) {
1008 GST_ERROR_OBJECT (window, "Invalid buffer");
1009
1010 return GST_FLOW_ERROR;
1011 }
1012 }
1013
1014 gst_d3d11_device_lock (window->device);
1015 if (buffer)
1016 gst_buffer_replace (&window->cached_buffer, buffer);
1017
1018 ret = gst_d3d111_window_present (window, window->cached_buffer,
1019 window->pov, window->rtv);
1020 gst_d3d11_device_unlock (window->device);
1021
1022 return ret;
1023 }
1024
1025 GstFlowReturn
gst_d3d11_window_render_on_shared_handle(GstD3D11Window * window,GstBuffer * buffer,HANDLE shared_handle,guint texture_misc_flags,guint64 acquire_key,guint64 release_key)1026 gst_d3d11_window_render_on_shared_handle (GstD3D11Window * window,
1027 GstBuffer * buffer, HANDLE shared_handle, guint texture_misc_flags,
1028 guint64 acquire_key, guint64 release_key)
1029 {
1030 GstD3D11WindowClass *klass;
1031 GstMemory *mem;
1032 GstFlowReturn ret = GST_FLOW_OK;
1033 GstD3D11WindowSharedHandleData data = { NULL, };
1034 ID3D11VideoProcessorOutputView *pov = NULL;
1035 ID3D11RenderTargetView *rtv = NULL;
1036
1037 g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), GST_FLOW_ERROR);
1038
1039 klass = GST_D3D11_WINDOW_GET_CLASS (window);
1040
1041 g_assert (klass->open_shared_handle != NULL);
1042 g_assert (klass->release_shared_handle != NULL);
1043
1044 mem = gst_buffer_peek_memory (buffer, 0);
1045 if (!gst_is_d3d11_memory (mem)) {
1046 GST_ERROR_OBJECT (window, "Invalid buffer");
1047
1048 return GST_FLOW_ERROR;
1049 }
1050
1051 data.shared_handle = shared_handle;
1052 data.texture_misc_flags = texture_misc_flags;
1053 data.acquire_key = acquire_key;
1054 data.release_key = release_key;
1055
1056 gst_d3d11_device_lock (window->device);
1057 if (!klass->open_shared_handle (window, &data)) {
1058 GST_ERROR_OBJECT (window, "Couldn't open shared handle");
1059 gst_d3d11_device_unlock (window->device);
1060 return GST_FLOW_OK;
1061 }
1062
1063 if (data.fallback_rtv) {
1064 rtv = data.fallback_rtv;
1065 pov = data.fallback_pov;
1066 } else {
1067 rtv = data.rtv;
1068 pov = data.pov;
1069 }
1070
1071 ret = gst_d3d111_window_present (window, buffer, pov, rtv);
1072
1073 klass->release_shared_handle (window, &data);
1074 gst_d3d11_device_unlock (window->device);
1075
1076 return ret;
1077 }
1078
1079 gboolean
gst_d3d11_window_unlock(GstD3D11Window * window)1080 gst_d3d11_window_unlock (GstD3D11Window * window)
1081 {
1082 GstD3D11WindowClass *klass;
1083 gboolean ret = TRUE;
1084
1085 g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
1086
1087 klass = GST_D3D11_WINDOW_GET_CLASS (window);
1088
1089 if (klass->unlock)
1090 ret = klass->unlock (window);
1091
1092 return ret;
1093 }
1094
1095 gboolean
gst_d3d11_window_unlock_stop(GstD3D11Window * window)1096 gst_d3d11_window_unlock_stop (GstD3D11Window * window)
1097 {
1098 GstD3D11WindowClass *klass;
1099 gboolean ret = TRUE;
1100
1101 g_return_val_if_fail (GST_IS_D3D11_WINDOW (window), FALSE);
1102
1103 klass = GST_D3D11_WINDOW_GET_CLASS (window);
1104
1105 if (klass->unlock_stop)
1106 ret = klass->unlock_stop (window);
1107
1108 gst_d3d11_device_lock (window->device);
1109 gst_clear_buffer (&window->cached_buffer);
1110 gst_d3d11_device_unlock (window->device);
1111
1112 return ret;
1113 }
1114
1115 void
gst_d3d11_window_unprepare(GstD3D11Window * window)1116 gst_d3d11_window_unprepare (GstD3D11Window * window)
1117 {
1118 GstD3D11WindowClass *klass;
1119
1120 g_return_if_fail (GST_IS_D3D11_WINDOW (window));
1121
1122 klass = GST_D3D11_WINDOW_GET_CLASS (window);
1123
1124 if (klass->unprepare)
1125 klass->unprepare (window);
1126 }
1127
1128 GstD3D11WindowNativeType
gst_d3d11_window_get_native_type_from_handle(guintptr handle)1129 gst_d3d11_window_get_native_type_from_handle (guintptr handle)
1130 {
1131 if (!handle)
1132 return GST_D3D11_WINDOW_NATIVE_TYPE_NONE;
1133
1134 #if (!GST_D3D11_WINAPI_ONLY_APP)
1135 if (IsWindow ((HWND) handle))
1136 return GST_D3D11_WINDOW_NATIVE_TYPE_HWND;
1137 #endif
1138 #if GST_D3D11_WINAPI_ONLY_APP
1139 {
1140 /* *INDENT-OFF* */
1141 ComPtr<IInspectable> window = reinterpret_cast<IInspectable*> (handle);
1142 ComPtr<ABI::Windows::UI::Core::ICoreWindow> core_window;
1143 ComPtr<ABI::Windows::UI::Xaml::Controls::ISwapChainPanel> panel;
1144 /* *INDENT-ON* */
1145
1146 if (SUCCEEDED (window.As (&core_window)))
1147 return GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW;
1148
1149 if (SUCCEEDED (window.As (&panel)))
1150 return GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL;
1151 }
1152 #endif
1153
1154 return GST_D3D11_WINDOW_NATIVE_TYPE_NONE;
1155 }
1156
1157 const gchar *
gst_d3d11_window_get_native_type_to_string(GstD3D11WindowNativeType type)1158 gst_d3d11_window_get_native_type_to_string (GstD3D11WindowNativeType type)
1159 {
1160 switch (type) {
1161 case GST_D3D11_WINDOW_NATIVE_TYPE_NONE:
1162 return "none";
1163 case GST_D3D11_WINDOW_NATIVE_TYPE_HWND:
1164 return "hwnd";
1165 case GST_D3D11_WINDOW_NATIVE_TYPE_CORE_WINDOW:
1166 return "core-window";
1167 case GST_D3D11_WINDOW_NATIVE_TYPE_SWAP_CHAIN_PANEL:
1168 return "swap-chain-panel";
1169 default:
1170 break;
1171 }
1172
1173 return "none";
1174 }
1175