qsv: Update SDK version to v2022.2.4
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / qsv / gstqsvallocator_d3d11.cpp
1 /* GStreamer
2  * Copyright (C) 2021 Seungha Yang <seungha@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstqsvallocator_d3d11.h"
25 #include <string.h>
26 #include <wrl.h>
27
28 /* *INDENT-OFF* */
29 using namespace Microsoft::WRL;
30 /* *INDENT-ON* */
31
32 GST_DEBUG_CATEGORY_EXTERN (gst_qsv_allocator_debug);
33 #define GST_CAT_DEFAULT gst_qsv_allocator_debug
34
35 struct _GstQsvD3D11Allocator
36 {
37   GstQsvAllocator parent;
38
39   GstD3D11Device *device;
40   GstD3D11Fence *fence;
41 };
42
43 #define gst_qsv_d3d11_allocator_parent_class parent_class
44 G_DEFINE_TYPE (GstQsvD3D11Allocator, gst_qsv_d3d11_allocator,
45     GST_TYPE_QSV_ALLOCATOR);
46
47 static void gst_qsv_d3d11_allocator_dispose (GObject * object);
48 static mfxStatus gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
49     gboolean dummy_alloc, mfxFrameAllocRequest * request,
50     mfxFrameAllocResponse * response);
51 static GstBuffer *gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
52     const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool);
53 static GstBuffer *gst_qsv_d3d11_allocator_download (GstQsvAllocator * allocator,
54     const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
55     GstBufferPool * pool);
56
57 static void
58 gst_qsv_d3d11_allocator_class_init (GstQsvD3D11AllocatorClass * klass)
59 {
60   GObjectClass *object_class = G_OBJECT_CLASS (klass);
61   GstQsvAllocatorClass *alloc_class = GST_QSV_ALLOCATOR_CLASS (klass);
62
63   object_class->dispose = gst_qsv_d3d11_allocator_dispose;
64
65   alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_alloc);
66   alloc_class->upload = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_upload);
67   alloc_class->download = GST_DEBUG_FUNCPTR (gst_qsv_d3d11_allocator_download);
68 }
69
70 static void
71 gst_qsv_d3d11_allocator_init (GstQsvD3D11Allocator * self)
72 {
73 }
74
75 static void
76 gst_qsv_d3d11_allocator_dispose (GObject * object)
77 {
78   GstQsvD3D11Allocator *self = GST_QSV_D3D11_ALLOCATOR (object);
79
80   gst_clear_d3d11_fence (&self->fence);
81   gst_clear_object (&self->device);
82
83   G_OBJECT_CLASS (parent_class)->dispose (object);
84 }
85
86 static mfxStatus
87 gst_qsv_d3d11_allocator_alloc (GstQsvAllocator * allocator,
88     gboolean dummy_alloc, mfxFrameAllocRequest * request,
89     mfxFrameAllocResponse * response)
90 {
91   GstQsvD3D11Allocator *self = GST_QSV_D3D11_ALLOCATOR (allocator);
92   DXGI_FORMAT dxgi_format = DXGI_FORMAT_UNKNOWN;
93   GstQsvFrame **mids = nullptr;
94
95   /* Something unexpected and went wrong */
96   if ((request->Type & MFX_MEMTYPE_SYSTEM_MEMORY) != 0) {
97     GST_ERROR_OBJECT (self,
98         "MFX is requesting system memory, type 0x%x", request->Type);
99     return MFX_ERR_UNSUPPORTED;
100   }
101
102   switch (request->Info.FourCC) {
103     case MFX_FOURCC_NV12:
104       dxgi_format = DXGI_FORMAT_NV12;
105       break;
106     case MFX_FOURCC_P010:
107       dxgi_format = DXGI_FORMAT_P010;
108       break;
109     case MFX_FOURCC_AYUV:
110       dxgi_format = DXGI_FORMAT_AYUV;
111       break;
112     case MFX_FOURCC_Y410:
113       dxgi_format = DXGI_FORMAT_Y410;
114       break;
115     case MFX_FOURCC_RGB4:
116       dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM;
117       break;
118     case MFX_FOURCC_BGR4:
119       dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM;
120       break;
121     default:
122       /* TODO: add more formats */
123       break;
124   }
125
126   if (dxgi_format == DXGI_FORMAT_UNKNOWN &&
127       request->Info.FourCC != MFX_FOURCC_P8) {
128     GST_ERROR_OBJECT (self, "Failed to convert %d to DXGI format",
129         request->Info.FourCC);
130
131     return MFX_ERR_UNSUPPORTED;
132   }
133
134   if (request->Info.FourCC == MFX_FOURCC_P8) {
135     D3D11_BUFFER_DESC desc;
136     GstVideoInfo info;
137     GstMemory *mem;
138     GstBuffer *buffer;
139     gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
140     gint stride[GST_VIDEO_MAX_PLANES] = { 0, };
141     guint size;
142
143     memset (&desc, 0, sizeof (D3D11_BUFFER_DESC));
144
145     desc.ByteWidth = request->Info.Width * request->Info.Height;
146     desc.Usage = D3D11_USAGE_STAGING;
147     desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
148
149     mem = gst_d3d11_allocator_alloc_buffer (nullptr, self->device, &desc);
150     if (!mem) {
151       GST_ERROR_OBJECT (self, "Failed to allocate buffer");
152       return MFX_ERR_MEMORY_ALLOC;
153     }
154
155     size = request->Info.Width * request->Info.Height;
156     stride[0] = size;
157
158     gst_video_info_set_format (&info, GST_VIDEO_FORMAT_GRAY8, size, 1);
159
160     buffer = gst_buffer_new ();
161     gst_buffer_append_memory (buffer, mem);
162     gst_buffer_add_video_meta_full (buffer, GST_VIDEO_FRAME_FLAG_NONE,
163         GST_VIDEO_FORMAT_GRAY8, size, 1, 1, offset, stride);
164
165     mids = g_new0 (GstQsvFrame *, 1);
166     response->NumFrameActual = 1;
167     mids[0] = gst_qsv_allocator_acquire_frame (allocator,
168         GST_QSV_VIDEO_MEMORY | GST_QSV_ENCODER_IN_MEMORY, &info, buffer,
169         nullptr);
170   } else {
171     GstBufferPool *pool;
172     GstVideoFormat format;
173     GstVideoInfo info;
174     GstCaps *caps;
175     GstStructure *config;
176     GstD3D11AllocationParams *params;
177     guint bind_flags = 0;
178     GstVideoAlignment align;
179     GstQsvMemoryType mem_type = GST_QSV_VIDEO_MEMORY;
180
181     if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_ENCODER_TARGET) != 0) {
182       bind_flags |= D3D11_BIND_VIDEO_ENCODER;
183       mem_type |= GST_QSV_ENCODER_IN_MEMORY;
184     }
185
186     if ((request->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) != 0) {
187       bind_flags |= D3D11_BIND_DECODER;
188       mem_type |= GST_QSV_DECODER_OUT_MEMORY;
189     }
190
191     if (mem_type == GST_QSV_VIDEO_MEMORY) {
192       GST_ERROR_OBJECT (self, "Unknown read/write access");
193       return MFX_ERR_UNSUPPORTED;
194     }
195
196     mids = g_new0 (GstQsvFrame *, request->NumFrameSuggested);
197     response->NumFrameActual = request->NumFrameSuggested;
198
199     format = gst_d3d11_dxgi_format_to_gst (dxgi_format);
200     gst_video_info_set_format (&info,
201         format, request->Info.CropW, request->Info.CropH);
202
203     if (dummy_alloc) {
204       for (guint i = 0; i < request->NumFrameSuggested; i++) {
205         mids[i] = gst_qsv_allocator_acquire_frame (allocator,
206             mem_type, &info, nullptr, nullptr);
207       }
208
209       response->mids = (mfxMemId *) mids;
210
211       return MFX_ERR_NONE;
212     }
213
214     caps = gst_video_info_to_caps (&info);
215     gst_video_alignment_reset (&align);
216     align.padding_right = request->Info.Width - request->Info.CropW;
217     align.padding_bottom = request->Info.Height - request->Info.CropH;
218
219     pool = gst_d3d11_buffer_pool_new (self->device);
220     params = gst_d3d11_allocation_params_new (self->device, &info,
221         GST_D3D11_ALLOCATION_FLAG_DEFAULT, bind_flags, 0);
222
223     gst_d3d11_allocation_params_alignment (params, &align);
224
225     config = gst_buffer_pool_get_config (pool);
226     gst_buffer_pool_config_set_d3d11_allocation_params (config, params);
227     gst_d3d11_allocation_params_free (params);
228     gst_buffer_pool_config_set_params (config, caps,
229         GST_VIDEO_INFO_SIZE (&info), 0, 0);
230     gst_caps_unref (caps);
231     gst_buffer_pool_set_config (pool, config);
232     gst_buffer_pool_set_active (pool, TRUE);
233
234     for (guint i = 0; i < request->NumFrameSuggested; i++) {
235       GstBuffer *buffer;
236
237       if (gst_buffer_pool_acquire_buffer (pool, &buffer, nullptr) !=
238           GST_FLOW_OK) {
239         GST_ERROR_OBJECT (self, "Failed to allocate texture buffer");
240         gst_buffer_pool_set_active (pool, FALSE);
241         gst_object_unref (pool);
242         goto error;
243       }
244
245       mids[i] = gst_qsv_allocator_acquire_frame (allocator,
246           mem_type, &info, buffer, nullptr);
247     }
248
249     gst_buffer_pool_set_active (pool, FALSE);
250     gst_object_unref (pool);
251   }
252
253   response->mids = (mfxMemId *) mids;
254
255   return MFX_ERR_NONE;
256
257 error:
258   if (mids) {
259     for (guint i = 0; i < response->NumFrameActual; i++)
260       gst_clear_qsv_frame (&mids[i]);
261
262     g_free (mids);
263   }
264
265   response->NumFrameActual = 0;
266
267   return MFX_ERR_MEMORY_ALLOC;
268 }
269
270 static GstBuffer *
271 gst_qsv_frame_copy_d3d11 (GstQsvD3D11Allocator * self,
272     const GstVideoInfo * info, GstBuffer * src_buf, GstBuffer * dst_buf,
273     gboolean shared)
274 {
275   D3D11_TEXTURE2D_DESC src_desc, dst_desc;
276   D3D11_BOX src_box;
277   guint subresource_idx;
278   GstMemory *src_mem, *dst_mem;
279   GstMapInfo src_info, dst_info;
280   ID3D11Texture2D *src_tex, *dst_tex;
281   GstD3D11Device *device;
282   ID3D11Device *device_handle;
283   ID3D11DeviceContext *device_context;
284   ComPtr < IDXGIResource > dxgi_resource;
285   ComPtr < ID3D11Texture2D > shared_texture;
286   HANDLE shared_handle;
287   HRESULT hr;
288
289   GST_TRACE_OBJECT (self, "Copying D3D11 buffer %" GST_PTR_FORMAT, src_buf);
290
291   src_mem = gst_buffer_peek_memory (src_buf, 0);
292   dst_mem = gst_buffer_peek_memory (dst_buf, 0);
293
294   device = GST_D3D11_MEMORY_CAST (src_mem)->device;
295   device_handle = gst_d3d11_device_get_device_handle (device);
296   device_context = gst_d3d11_device_get_device_context_handle (device);
297
298   if (!gst_memory_map (src_mem,
299           &src_info, (GstMapFlags) (GST_MAP_READ | GST_MAP_D3D11))) {
300     GST_WARNING ("Failed to map src memory");
301     gst_buffer_unref (dst_buf);
302     return nullptr;
303   }
304
305   if (!gst_memory_map (dst_mem,
306           &dst_info, (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
307     GST_WARNING ("Failed to map dst memory");
308     gst_memory_unmap (src_mem, &src_info);
309     gst_buffer_unref (dst_buf);
310     return nullptr;
311   }
312
313   src_tex = (ID3D11Texture2D *) src_info.data;
314   dst_tex = (ID3D11Texture2D *) dst_info.data;
315
316   src_tex->GetDesc (&src_desc);
317   dst_tex->GetDesc (&dst_desc);
318
319   subresource_idx =
320       gst_d3d11_memory_get_subresource_index (GST_D3D11_MEMORY_CAST (src_mem));
321
322   if (shared) {
323     hr = dst_tex->QueryInterface (IID_PPV_ARGS (&dxgi_resource));
324     if (!gst_d3d11_result (hr, device)) {
325       GST_ERROR_OBJECT (self,
326           "IDXGIResource interface is not available, hr: 0x%x", (guint) hr);
327       goto error;
328     }
329
330     hr = dxgi_resource->GetSharedHandle (&shared_handle);
331     if (!gst_d3d11_result (hr, device)) {
332       GST_ERROR_OBJECT (self, "Failed to get shared handle, hr: 0x%x",
333           (guint) hr);
334       goto error;
335     }
336
337     hr = device_handle->OpenSharedResource (shared_handle,
338         IID_PPV_ARGS (&shared_texture));
339
340     if (!gst_d3d11_result (hr, device)) {
341       GST_ERROR_OBJECT (self, "Failed to get shared texture, hr: 0x%x",
342           (guint) hr);
343       goto error;
344     }
345
346     dst_tex = shared_texture.Get ();
347   }
348
349   src_box.left = 0;
350   src_box.top = 0;
351   src_box.front = 0;
352   src_box.back = 1;
353   src_box.right = MIN (src_desc.Width, dst_desc.Width);
354   src_box.bottom = MIN (src_desc.Height, dst_desc.Height);
355
356   gst_d3d11_device_lock (device);
357   if (shared) {
358     if (self->fence && self->fence->device != device)
359       gst_clear_d3d11_fence (&self->fence);
360
361     if (!self->fence)
362       self->fence = gst_d3d11_device_create_fence (device);
363
364     if (!self->fence) {
365       GST_ERROR_OBJECT (self, "Couldn't crete fence");
366       gst_d3d11_device_unlock (device);
367       goto error;
368     }
369   }
370
371   device_context->CopySubresourceRegion (dst_tex, 0,
372       0, 0, 0, src_tex, subresource_idx, &src_box);
373
374   if (shared) {
375     if (!gst_d3d11_fence_signal (self->fence) ||
376         !gst_d3d11_fence_wait (self->fence)) {
377       GST_ERROR_OBJECT (self, "Couldn't sync GPU operation");
378       gst_clear_d3d11_fence (&self->fence);
379       gst_d3d11_device_unlock (device);
380       goto error;
381     }
382   }
383
384   gst_d3d11_device_unlock (device);
385
386   gst_memory_unmap (dst_mem, &dst_info);
387   gst_memory_unmap (src_mem, &src_info);
388
389   return dst_buf;
390
391 error:
392   gst_memory_unmap (dst_mem, &dst_info);
393   gst_memory_unmap (src_mem, &src_info);
394   gst_buffer_unref (dst_buf);
395
396   return nullptr;
397 }
398
399 static GstBuffer *
400 gst_qsv_frame_upload_sysmem (const GstVideoInfo * info, GstBuffer * src_buf,
401     GstBuffer * dst_buf)
402 {
403   GstVideoFrame src_frame, dst_frame;
404
405   GST_TRACE ("Uploading sysmem buffer %" GST_PTR_FORMAT, src_buf);
406
407   if (!gst_video_frame_map (&src_frame, info, src_buf, GST_MAP_READ)) {
408     GST_WARNING ("Failed to map src frame");
409     gst_buffer_unref (dst_buf);
410     return nullptr;
411   }
412
413   if (!gst_video_frame_map (&dst_frame, info, dst_buf, GST_MAP_WRITE)) {
414     GST_WARNING ("Failed to map src frame");
415     gst_video_frame_unmap (&src_frame);
416     gst_buffer_unref (dst_buf);
417     return nullptr;
418   }
419
420   for (guint i = 0; i < GST_VIDEO_FRAME_N_PLANES (&src_frame); i++) {
421     guint src_width_in_bytes, src_height;
422     guint dst_width_in_bytes, dst_height;
423     guint width_in_bytes, height;
424     guint src_stride, dst_stride;
425     guint8 *src_data, *dst_data;
426
427     src_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&src_frame, i) *
428         GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
429     src_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
430     src_stride = GST_VIDEO_FRAME_COMP_STRIDE (&src_frame, i);
431
432     dst_width_in_bytes = GST_VIDEO_FRAME_COMP_WIDTH (&dst_frame, i) *
433         GST_VIDEO_FRAME_COMP_PSTRIDE (&src_frame, i);
434     dst_height = GST_VIDEO_FRAME_COMP_HEIGHT (&src_frame, i);
435     dst_stride = GST_VIDEO_FRAME_COMP_STRIDE (&dst_frame, i);
436
437     width_in_bytes = MIN (src_width_in_bytes, dst_width_in_bytes);
438     height = MIN (src_height, dst_height);
439
440     src_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&src_frame, i);
441     dst_data = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&dst_frame, i);
442
443     for (guint j = 0; j < height; j++) {
444       memcpy (dst_data, src_data, width_in_bytes);
445       dst_data += dst_stride;
446       src_data += src_stride;
447     }
448   }
449
450   gst_video_frame_unmap (&dst_frame);
451   gst_video_frame_unmap (&src_frame);
452
453   return dst_buf;
454 }
455
456 static GstBuffer *
457 gst_qsv_d3d11_allocator_upload (GstQsvAllocator * allocator,
458     const GstVideoInfo * info, GstBuffer * buffer, GstBufferPool * pool)
459 {
460   GstMemory *mem;
461   GstD3D11Memory *dmem;
462   D3D11_TEXTURE2D_DESC desc;
463   GstBuffer *dst_buf;
464   GstFlowReturn flow_ret;
465   gboolean shared_copy = FALSE;
466
467   /* 1) D3D11 buffer from the same d3d11device with ours
468    * 1-1) Same resolution
469    *      -> Increase refcount and wrap with GstQsvFrame
470    * 1-2) Different resolution
471    *      -> GPU copy
472    * 2) non-D3D11 buffer or from other d3d11 device
473    *    -> Always CPU copy
474    */
475
476   if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
477     GST_ERROR_OBJECT (allocator, "Not a d3d11 buffer pool");
478     return nullptr;
479   }
480
481   flow_ret = gst_buffer_pool_acquire_buffer (pool, &dst_buf, nullptr);
482   if (flow_ret != GST_FLOW_OK) {
483     GST_WARNING_OBJECT (allocator,
484         "Failed to acquire buffer from pool, return %s",
485         gst_flow_get_name (flow_ret));
486     return nullptr;
487   }
488
489   mem = gst_buffer_peek_memory (buffer, 0);
490   if (!gst_is_d3d11_memory (mem) || gst_buffer_n_memory (buffer) > 1) {
491     /* d3d11 buffer should hold single memory object */
492     return gst_qsv_frame_upload_sysmem (info, buffer, dst_buf);
493   }
494
495   /* FIXME: Add support for shared texture for GPU copy or wrapping
496    * texture from different device */
497   dmem = GST_D3D11_MEMORY_CAST (mem);
498   if (dmem->device != GST_D3D11_BUFFER_POOL (pool)->device) {
499     gint64 luid, other_luid;
500     g_object_get (dmem->device, "adapter-luid", &luid, nullptr);
501     g_object_get (GST_D3D11_BUFFER_POOL (pool)->device,
502         "adapter-luid", &other_luid, nullptr);
503     if (luid == other_luid) {
504       shared_copy = TRUE;
505     } else {
506       return gst_qsv_frame_upload_sysmem (info, buffer, dst_buf);
507     }
508   }
509
510   gst_d3d11_memory_get_texture_desc (dmem, &desc);
511
512   if (desc.Usage == D3D11_USAGE_DEFAULT && !shared_copy) {
513     GST_TRACE_OBJECT (allocator, "Wrapping D3D11 buffer without copy");
514     gst_buffer_unref (dst_buf);
515
516     return gst_buffer_ref (buffer);
517   }
518
519   return gst_qsv_frame_copy_d3d11 (GST_QSV_D3D11_ALLOCATOR (allocator), info,
520       buffer, dst_buf, shared_copy);
521 }
522
523 static GstBuffer *
524 gst_qsv_d3d11_allocator_download (GstQsvAllocator * allocator,
525     const GstVideoInfo * info, gboolean force_copy, GstQsvFrame * frame,
526     GstBufferPool * pool)
527 {
528   GstD3D11BufferPool *d3d11_pool;
529   GstBuffer *src_buf, *dst_buf;
530   GstMemory *mem;
531   GstD3D11Memory *dmem;
532   GstFlowReturn ret;
533
534   GST_TRACE_OBJECT (allocator, "Download");
535
536   src_buf = gst_qsv_frame_peek_buffer (frame);
537
538   if (!force_copy)
539     return gst_buffer_ref (src_buf);
540
541   mem = gst_buffer_peek_memory (src_buf, 0);
542   if (!gst_is_d3d11_memory (mem) || gst_buffer_n_memory (src_buf) != 1) {
543     GST_ERROR_OBJECT (allocator, "frame holds invalid d3d11 memory");
544     return nullptr;
545   }
546
547   if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
548     GST_TRACE_OBJECT (allocator, "Output is not d3d11 memory");
549     goto fallback;
550   }
551
552   dmem = GST_D3D11_MEMORY_CAST (mem);
553
554   /* both pool and qsvframe should hold the same d3d11 device already,
555    * but checking again */
556   d3d11_pool = GST_D3D11_BUFFER_POOL (pool);
557   if (d3d11_pool->device != dmem->device) {
558     GST_WARNING_OBJECT (allocator, "Pool holds different device");
559     goto fallback;
560   }
561
562   ret = gst_buffer_pool_acquire_buffer (pool, &dst_buf, nullptr);
563   if (ret != GST_FLOW_OK) {
564     GST_WARNING_OBJECT (allocator, "Failed to allocate output buffer");
565     return nullptr;
566   }
567
568   return gst_qsv_frame_copy_d3d11 (GST_QSV_D3D11_ALLOCATOR (allocator),
569       info, src_buf, dst_buf, FALSE);
570
571 fallback:
572   GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
573
574   return GST_QSV_ALLOCATOR_CLASS (parent_class)->download (allocator,
575       info, TRUE, frame, pool);
576 }
577
578 GstQsvAllocator *
579 gst_qsv_d3d11_allocator_new (GstD3D11Device * device)
580 {
581   GstQsvD3D11Allocator *self;
582
583   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
584
585   self = (GstQsvD3D11Allocator *)
586       g_object_new (GST_TYPE_QSV_D3D11_ALLOCATOR, nullptr);
587   self->device = (GstD3D11Device *) gst_object_ref (device);
588
589   gst_object_ref_sink (self);
590
591   return GST_QSV_ALLOCATOR (self);
592 }