• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.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  * NOTE: some of implementations are copied/modified from Chromium code
20  *
21  * Copyright 2015 The Chromium Authors. All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions are
25  * met:
26  *
27  *    * Redistributions of source code must retain the above copyright
28  * notice, this list of conditions and the following disclaimer.
29  *    * Redistributions in binary form must reproduce the above
30  * copyright notice, this list of conditions and the following disclaimer
31  * in the documentation and/or other materials provided with the
32  * distribution.
33  *    * Neither the name of Google Inc. nor the names of its
34  * contributors may be used to endorse or promote products derived from
35  * this software without specific prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
38  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
39  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
40  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
41  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
44  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
45  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49 
50 #ifdef HAVE_CONFIG_H
51 #include <config.h>
52 #endif
53 
54 #include "gstd3d11decoder.h"
55 #include "gstd3d11converter.h"
56 #include "gstd3d11pluginutils.h"
57 #include <string.h>
58 #include <string>
59 
60 #ifdef HAVE_WINMM
61 #include <mmsystem.h>
62 #endif
63 
64 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_decoder_debug);
65 #define GST_CAT_DEFAULT gst_d3d11_decoder_debug
66 
67 /* GUID might not be defined in MinGW header */
68 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0x1b81be67, 0xa0c7,
69     0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
70 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT, 0x1b81be68, 0xa0c7,
71     0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
72 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT, 0x1b81be69, 0xa0c7,
73     0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
74 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
75     0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0);
76 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10,
77     0x107af0e0, 0xef1a, 0x4d19, 0xab, 0xa8, 0x67, 0xa1, 0x63, 0x07, 0x3d, 0x13);
78 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP8_VLD,
79     0x90b899ea, 0x3a62, 0x4705, 0x88, 0xb3, 0x8d, 0xf0, 0x4b, 0x27, 0x44, 0xe7);
80 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
81     0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e);
82 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2,
83     0xa4c749ef, 0x6ecf, 0x48aa, 0x84, 0x48, 0x50, 0xa7, 0xa1, 0x16, 0x5f, 0xf7);
84 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_MPEG2_VLD, 0xee27417f, 0x5e28,
85     0x4e65, 0xbe, 0xea, 0x1d, 0x26, 0xb5, 0x08, 0xad, 0xc9);
86 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_MPEG2and1_VLD, 0x86695f12, 0x340e,
87     0x4f04, 0x9f, 0xd3, 0x92, 0x53, 0xdd, 0x32, 0x74, 0x60);
88 DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_AV1_VLD_PROFILE0, 0xb8be4ccb,
89     0xcf53, 0x46ba, 0x8d, 0x59, 0xd6, 0xb8, 0xa6, 0xda, 0x5d, 0x2a);
90 
91 static const GUID *profile_h264_list[] = {
92   &GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT,
93   &GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
94   &GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT,
95 };
96 
97 static const GUID *profile_hevc_list[] = {
98   &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
99 };
100 
101 static const GUID *profile_hevc_10_list[] = {
102   &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10,
103 };
104 
105 static const GUID *profile_vp8_list[] = {
106   &GST_GUID_D3D11_DECODER_PROFILE_VP8_VLD,
107 };
108 
109 static const GUID *profile_vp9_list[] = {
110   &GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
111 };
112 
113 static const GUID *profile_vp9_10_list[] = {
114   &GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2,
115 };
116 
117 static const GUID *profile_mpeg2_list[] = {
118   &GST_GUID_D3D11_DECODER_PROFILE_MPEG2_VLD,
119   &GST_GUID_D3D11_DECODER_PROFILE_MPEG2and1_VLD
120 };
121 
122 static const GUID *profile_av1_list[] = {
123   &GST_GUID_D3D11_DECODER_PROFILE_AV1_VLD_PROFILE0,
124   /* TODO: add more profile */
125 };
126 
127 enum
128 {
129   PROP_0,
130   PROP_DEVICE,
131 };
132 
133 struct _GstD3D11Decoder
134 {
135   GstObject parent;
136 
137   gboolean configured;
138   gboolean opened;
139 
140   GstD3D11Device *device;
141 
142   ID3D11VideoDevice *video_device;
143   ID3D11VideoContext *video_context;
144 
145   ID3D11VideoDecoder *decoder_handle;
146 
147   GstVideoInfo info;
148   GstVideoInfo output_info;
149   GstDXVACodec codec;
150   gint coded_width;
151   gint coded_height;
152   DXGI_FORMAT decoder_format;
153   gboolean downstream_supports_d3d11;
154 
155   GstVideoCodecState *input_state;
156   GstVideoCodecState *output_state;
157 
158   /* Protect internal pool */
159   GMutex internal_pool_lock;
160 
161   GstBufferPool *internal_pool;
162   /* Internal pool params */
163   gint aligned_width;
164   gint aligned_height;
165   gboolean use_array_of_texture;
166   guint dpb_size;
167   guint downstream_min_buffers;
168   gboolean wait_on_pool_full;
169 
170   /* Used for array-of-texture */
171   guint8 next_view_id;
172 
173   /* for staging */
174   ID3D11Texture2D *staging;
175   gsize staging_texture_offset[GST_VIDEO_MAX_PLANES];
176   gint stating_texture_stride[GST_VIDEO_MAX_PLANES];
177 
178   GUID decoder_profile;
179 
180   /* For device specific workaround */
181   gboolean can_direct_rendering;
182 
183   /* For high precision clock */
184   guint timer_resolution;
185 };
186 
187 static void gst_d3d11_decoder_constructed (GObject * object);
188 static void gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
189     const GValue * value, GParamSpec * pspec);
190 static void gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
191     GValue * value, GParamSpec * pspec);
192 static void gst_d3d11_decoder_dispose (GObject * obj);
193 static void gst_d3d11_decoder_finalize (GObject * obj);
194 static gboolean gst_d3d11_decoder_can_direct_render (GstD3D11Decoder * decoder,
195     GstVideoDecoder * videodec, GstBuffer * view_buffer,
196     gint display_width, gint display_height);
197 
198 #define parent_class gst_d3d11_decoder_parent_class
199 G_DEFINE_TYPE (GstD3D11Decoder, gst_d3d11_decoder, GST_TYPE_OBJECT);
200 
201 static void
gst_d3d11_decoder_class_init(GstD3D11DecoderClass * klass)202 gst_d3d11_decoder_class_init (GstD3D11DecoderClass * klass)
203 {
204   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
205 
206   gobject_class->constructed = gst_d3d11_decoder_constructed;
207   gobject_class->set_property = gst_d3d11_decoder_set_property;
208   gobject_class->get_property = gst_d3d11_decoder_get_property;
209   gobject_class->dispose = gst_d3d11_decoder_dispose;
210   gobject_class->finalize = gst_d3d11_decoder_finalize;
211 
212   g_object_class_install_property (gobject_class, PROP_DEVICE,
213       g_param_spec_object ("device", "Device",
214           "D3D11 Devicd to use", GST_TYPE_D3D11_DEVICE,
215           (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
216               G_PARAM_STATIC_STRINGS)));
217 }
218 
219 static void
gst_d3d11_decoder_init(GstD3D11Decoder * self)220 gst_d3d11_decoder_init (GstD3D11Decoder * self)
221 {
222   g_mutex_init (&self->internal_pool_lock);
223 }
224 
225 static void
gst_d3d11_decoder_constructed(GObject * object)226 gst_d3d11_decoder_constructed (GObject * object)
227 {
228   GstD3D11Decoder *self = GST_D3D11_DECODER (object);
229   ID3D11VideoDevice *video_device;
230   ID3D11VideoContext *video_context;
231 
232   if (!self->device) {
233     GST_ERROR_OBJECT (self, "No D3D11Device available");
234     return;
235   }
236 
237   video_device = gst_d3d11_device_get_video_device_handle (self->device);
238   if (!video_device) {
239     GST_WARNING_OBJECT (self, "ID3D11VideoDevice is not available");
240     return;
241   }
242 
243   video_context = gst_d3d11_device_get_video_context_handle (self->device);
244   if (!video_context) {
245     GST_WARNING_OBJECT (self, "ID3D11VideoContext is not available");
246     return;
247   }
248 
249   self->video_device = video_device;
250   video_device->AddRef ();
251 
252   self->video_context = video_context;
253   video_context->AddRef ();
254 
255   return;
256 }
257 
258 static void
gst_d3d11_decoder_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)259 gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
260     const GValue * value, GParamSpec * pspec)
261 {
262   GstD3D11Decoder *self = GST_D3D11_DECODER (object);
263 
264   switch (prop_id) {
265     case PROP_DEVICE:
266       self->device = (GstD3D11Device *) g_value_dup_object (value);
267       break;
268     default:
269       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270       break;
271   }
272 }
273 
274 static void
gst_d3d11_decoder_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)275 gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
276     GValue * value, GParamSpec * pspec)
277 {
278   GstD3D11Decoder *self = GST_D3D11_DECODER (object);
279 
280   switch (prop_id) {
281     case PROP_DEVICE:
282       g_value_set_object (value, self->device);
283       break;
284     default:
285       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286       break;
287   }
288 }
289 
290 static void
gst_d3d11_decoder_clear_resource(GstD3D11Decoder * self)291 gst_d3d11_decoder_clear_resource (GstD3D11Decoder * self)
292 {
293   g_mutex_lock (&self->internal_pool_lock);
294   if (self->internal_pool) {
295     gst_buffer_pool_set_active (self->internal_pool, FALSE);
296     gst_clear_object (&self->internal_pool);
297   }
298   g_mutex_unlock (&self->internal_pool_lock);
299 
300   GST_D3D11_CLEAR_COM (self->decoder_handle);
301   GST_D3D11_CLEAR_COM (self->staging);
302 
303   memset (self->staging_texture_offset,
304       0, sizeof (self->staging_texture_offset));
305   memset (self->stating_texture_stride,
306       0, sizeof (self->stating_texture_stride));
307 }
308 
309 static void
gst_d3d11_decoder_reset(GstD3D11Decoder * self)310 gst_d3d11_decoder_reset (GstD3D11Decoder * self)
311 {
312   gst_d3d11_decoder_clear_resource (self);
313 
314   self->dpb_size = 0;
315   self->downstream_min_buffers = 0;
316 
317   self->configured = FALSE;
318   self->opened = FALSE;
319 
320   self->use_array_of_texture = FALSE;
321   self->downstream_supports_d3d11 = FALSE;
322 
323   g_clear_pointer (&self->output_state, gst_video_codec_state_unref);
324   g_clear_pointer (&self->input_state, gst_video_codec_state_unref);
325 }
326 
327 static void
gst_d3d11_decoder_dispose(GObject * obj)328 gst_d3d11_decoder_dispose (GObject * obj)
329 {
330   GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
331 
332   gst_d3d11_decoder_reset (self);
333 
334   GST_D3D11_CLEAR_COM (self->video_device);
335   GST_D3D11_CLEAR_COM (self->video_context);
336 
337   gst_clear_object (&self->device);
338 
339   G_OBJECT_CLASS (parent_class)->dispose (obj);
340 }
341 
342 static void
gst_d3d11_decoder_finalize(GObject * obj)343 gst_d3d11_decoder_finalize (GObject * obj)
344 {
345   GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
346 
347 #if HAVE_WINMM
348   /* Restore clock precision */
349   if (self->timer_resolution)
350     timeEndPeriod (self->timer_resolution);
351 #endif
352 
353   g_mutex_clear (&self->internal_pool_lock);
354 
355   G_OBJECT_CLASS (parent_class)->finalize (obj);
356 }
357 
358 GstD3D11Decoder *
gst_d3d11_decoder_new(GstD3D11Device * device,GstDXVACodec codec)359 gst_d3d11_decoder_new (GstD3D11Device * device, GstDXVACodec codec)
360 {
361   GstD3D11Decoder *self;
362 
363   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), nullptr);
364   g_return_val_if_fail (codec > GST_DXVA_CODEC_NONE, nullptr);
365   g_return_val_if_fail (codec < GST_DXVA_CODEC_LAST, nullptr);
366 
367   self = (GstD3D11Decoder *)
368       g_object_new (GST_TYPE_D3D11_DECODER, "device", device, NULL);
369 
370   if (!self->video_device || !self->video_context) {
371     gst_object_unref (self);
372     return NULL;
373   }
374 
375   self->codec = codec;
376 
377   gst_object_ref_sink (self);
378 
379   return self;
380 }
381 
382 gboolean
gst_d3d11_decoder_is_configured(GstD3D11Decoder * decoder)383 gst_d3d11_decoder_is_configured (GstD3D11Decoder * decoder)
384 {
385   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
386 
387   return decoder->configured;
388 }
389 
390 static GQuark
gst_d3d11_decoder_view_id_quark(void)391 gst_d3d11_decoder_view_id_quark (void)
392 {
393   static gsize id_quark = 0;
394 
395   if (g_once_init_enter (&id_quark)) {
396     GQuark quark = g_quark_from_string ("GstD3D11DecoderViewId");
397     g_once_init_leave (&id_quark, quark);
398   }
399 
400   return (GQuark) id_quark;
401 }
402 
403 static gboolean
gst_d3d11_decoder_ensure_output_view(GstD3D11Decoder * self,GstBuffer * buffer)404 gst_d3d11_decoder_ensure_output_view (GstD3D11Decoder * self,
405     GstBuffer * buffer)
406 {
407   GstD3D11Memory *mem;
408   gpointer val = NULL;
409 
410   mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
411   if (!gst_d3d11_memory_get_decoder_output_view (mem, self->video_device,
412           self->decoder_handle, &self->decoder_profile)) {
413     GST_ERROR_OBJECT (self, "Decoder output view is unavailable");
414     return FALSE;
415   }
416 
417   if (!self->use_array_of_texture)
418     return TRUE;
419 
420   val = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
421       gst_d3d11_decoder_view_id_quark ());
422   if (!val) {
423     g_assert (self->next_view_id < 128);
424     g_assert (self->next_view_id > 0);
425 
426     gst_mini_object_set_qdata (GST_MINI_OBJECT (mem),
427         gst_d3d11_decoder_view_id_quark (),
428         GUINT_TO_POINTER (self->next_view_id), NULL);
429 
430     self->next_view_id++;
431     /* valid view range is [0, 126], but 0 is not used to here
432      * (it's NULL as well) */
433     self->next_view_id %= 128;
434     if (self->next_view_id == 0)
435       self->next_view_id = 1;
436   }
437 
438 
439   return TRUE;
440 }
441 
442 static gboolean
gst_d3d11_decoder_prepare_output_view_pool(GstD3D11Decoder * self)443 gst_d3d11_decoder_prepare_output_view_pool (GstD3D11Decoder * self)
444 {
445   GstD3D11AllocationParams *alloc_params = NULL;
446   GstBufferPool *pool = NULL;
447   GstCaps *caps = NULL;
448   GstVideoAlignment align;
449   GstD3D11AllocationFlags alloc_flags = (GstD3D11AllocationFlags) 0;
450   gint bind_flags = D3D11_BIND_DECODER;
451   GstVideoInfo *info = &self->info;
452   guint pool_size;
453 
454   g_mutex_lock (&self->internal_pool_lock);
455   if (self->internal_pool) {
456     gst_buffer_pool_set_active (self->internal_pool, FALSE);
457     gst_clear_object (&self->internal_pool);
458   }
459   g_mutex_unlock (&self->internal_pool_lock);
460 
461   if (!self->use_array_of_texture) {
462     alloc_flags = GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY;
463   } else {
464     /* array of texture can have shader resource view */
465     bind_flags |= D3D11_BIND_SHADER_RESOURCE;
466   }
467 
468   alloc_params = gst_d3d11_allocation_params_new (self->device, info,
469       alloc_flags, bind_flags);
470 
471   if (!alloc_params) {
472     GST_ERROR_OBJECT (self, "Failed to create allocation param");
473     goto error;
474   }
475 
476   pool_size = self->dpb_size + self->downstream_min_buffers;
477   GST_DEBUG_OBJECT (self,
478       "Configuring internal pool with size %d "
479       "(dpb size: %d, downstream min buffers: %d)", pool_size, self->dpb_size,
480       self->downstream_min_buffers);
481 
482   if (!self->use_array_of_texture) {
483     alloc_params->desc[0].ArraySize = pool_size;
484   } else {
485     /* Valid view id is [0, 126], but we will use [1, 127] range so that
486      * it can be used by qdata, because zero is equal to null */
487     self->next_view_id = 1;
488 
489     /* our pool size can be increased as much as possbile */
490     pool_size = 0;
491   }
492 
493   gst_video_alignment_reset (&align);
494 
495   align.padding_right = self->aligned_width - GST_VIDEO_INFO_WIDTH (info);
496   align.padding_bottom = self->aligned_height - GST_VIDEO_INFO_HEIGHT (info);
497   if (!gst_d3d11_allocation_params_alignment (alloc_params, &align)) {
498     GST_ERROR_OBJECT (self, "Cannot set alignment");
499     goto error;
500   }
501 
502   caps = gst_video_info_to_caps (info);
503   if (!caps) {
504     GST_ERROR_OBJECT (self, "Couldn't convert video info to caps");
505     goto error;
506   }
507 
508   pool = gst_d3d11_buffer_pool_new_with_options (self->device,
509       caps, alloc_params, 0, pool_size);
510   gst_clear_caps (&caps);
511   g_clear_pointer (&alloc_params, gst_d3d11_allocation_params_free);
512 
513   if (!pool) {
514     GST_ERROR_OBJECT (self, "Failed to create buffer pool");
515     goto error;
516   }
517 
518   if (!gst_buffer_pool_set_active (pool, TRUE)) {
519     GST_ERROR_OBJECT (self, "Couldn't activate pool");
520     goto error;
521   }
522 
523   g_mutex_lock (&self->internal_pool_lock);
524   self->internal_pool = pool;
525   g_mutex_unlock (&self->internal_pool_lock);
526 
527   return TRUE;
528 
529 error:
530   if (alloc_params)
531     gst_d3d11_allocation_params_free (alloc_params);
532   if (pool)
533     gst_object_unref (pool);
534   if (caps)
535     gst_caps_unref (caps);
536 
537   return FALSE;
538 }
539 
540 static const gchar *
gst_dxva_codec_to_string(GstDXVACodec codec)541 gst_dxva_codec_to_string (GstDXVACodec codec)
542 {
543   switch (codec) {
544     case GST_DXVA_CODEC_NONE:
545       return "none";
546     case GST_DXVA_CODEC_H264:
547       return "H.264";
548     case GST_DXVA_CODEC_VP9:
549       return "VP9";
550     case GST_DXVA_CODEC_H265:
551       return "H.265";
552     case GST_DXVA_CODEC_VP8:
553       return "VP8";
554     case GST_DXVA_CODEC_MPEG2:
555       return "MPEG2";
556     case GST_DXVA_CODEC_AV1:
557       return "AV1";
558     default:
559       g_assert_not_reached ();
560       break;
561   }
562 
563   return "Unknown";
564 }
565 
566 gboolean
gst_d3d11_decoder_get_supported_decoder_profile(GstD3D11Device * device,GstDXVACodec codec,GstVideoFormat format,const GUID ** selected_profile)567 gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Device * device,
568     GstDXVACodec codec, GstVideoFormat format, const GUID ** selected_profile)
569 {
570   GUID *guid_list = nullptr;
571   const GUID *profile = nullptr;
572   guint available_profile_count;
573   guint i, j;
574   HRESULT hr;
575   ID3D11VideoDevice *video_device;
576   const GUID **profile_list = nullptr;
577   guint profile_size = 0;
578 
579   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
580   g_return_val_if_fail (selected_profile != nullptr, FALSE);
581 
582   video_device = gst_d3d11_device_get_video_device_handle (device);
583   if (!video_device)
584     return FALSE;
585 
586   switch (codec) {
587     case GST_DXVA_CODEC_H264:
588       if (format == GST_VIDEO_FORMAT_NV12) {
589         profile_list = profile_h264_list;
590         profile_size = G_N_ELEMENTS (profile_h264_list);
591       }
592       break;
593     case GST_DXVA_CODEC_H265:
594       if (format == GST_VIDEO_FORMAT_NV12) {
595         profile_list = profile_hevc_list;
596         profile_size = G_N_ELEMENTS (profile_hevc_list);
597       } else if (format == GST_VIDEO_FORMAT_P010_10LE) {
598         profile_list = profile_hevc_10_list;
599         profile_size = G_N_ELEMENTS (profile_hevc_10_list);
600       }
601       break;
602     case GST_DXVA_CODEC_VP8:
603       if (format == GST_VIDEO_FORMAT_NV12) {
604         profile_list = profile_vp8_list;
605         profile_size = G_N_ELEMENTS (profile_vp8_list);
606       }
607       break;
608     case GST_DXVA_CODEC_VP9:
609       if (format == GST_VIDEO_FORMAT_NV12) {
610         profile_list = profile_vp9_list;
611         profile_size = G_N_ELEMENTS (profile_vp9_list);
612       } else if (format == GST_VIDEO_FORMAT_P010_10LE) {
613         profile_list = profile_vp9_10_list;
614         profile_size = G_N_ELEMENTS (profile_vp9_10_list);
615       }
616       break;
617     case GST_DXVA_CODEC_MPEG2:
618       if (format == GST_VIDEO_FORMAT_NV12) {
619         profile_list = profile_mpeg2_list;
620         profile_size = G_N_ELEMENTS (profile_mpeg2_list);
621       }
622       break;
623     case GST_DXVA_CODEC_AV1:
624       profile_list = profile_av1_list;
625       profile_size = G_N_ELEMENTS (profile_av1_list);
626       break;
627     default:
628       break;
629   }
630 
631   if (!profile_list) {
632     GST_ERROR_OBJECT (device,
633         "Not supported codec (%d) and format (%s) configuration", codec,
634         gst_video_format_to_string (format));
635     return FALSE;
636   }
637 
638   available_profile_count = video_device->GetVideoDecoderProfileCount ();
639 
640   if (available_profile_count == 0) {
641     GST_INFO_OBJECT (device, "No available decoder profile");
642     return FALSE;
643   }
644 
645   GST_DEBUG_OBJECT (device,
646       "Have %u available decoder profiles", available_profile_count);
647   guid_list = (GUID *) g_alloca (sizeof (GUID) * available_profile_count);
648 
649   for (i = 0; i < available_profile_count; i++) {
650     hr = video_device->GetVideoDecoderProfile (i, &guid_list[i]);
651     if (!gst_d3d11_result (hr, device)) {
652       GST_WARNING_OBJECT (device, "Failed to get %d th decoder profile", i);
653       return FALSE;
654     }
655   }
656 
657 #ifndef GST_DISABLE_GST_DEBUG
658   GST_LOG_OBJECT (device, "Supported decoder GUID");
659   for (i = 0; i < available_profile_count; i++) {
660     const GUID *guid = &guid_list[i];
661 
662     GST_LOG_OBJECT (device,
663         "\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
664         (guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
665         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
666         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
667   }
668 
669   GST_LOG_OBJECT (device, "Requested decoder GUID");
670   for (i = 0; i < profile_size; i++) {
671     const GUID *guid = profile_list[i];
672 
673     GST_LOG_OBJECT (device,
674         "\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
675         (guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
676         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
677         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
678   }
679 #endif
680 
681   for (i = 0; i < profile_size; i++) {
682     for (j = 0; j < available_profile_count; j++) {
683       if (IsEqualGUID (*profile_list[i], guid_list[j])) {
684         profile = profile_list[i];
685         break;
686       }
687     }
688   }
689 
690   if (!profile) {
691     GST_INFO_OBJECT (device, "No supported decoder profile for %s codec",
692         gst_dxva_codec_to_string (codec));
693     return FALSE;
694   }
695 
696   *selected_profile = profile;
697 
698   GST_DEBUG_OBJECT (device,
699       "Selected guid "
700       "{ %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
701       (guint) profile->Data1, (guint) profile->Data2, (guint) profile->Data3,
702       profile->Data4[0], profile->Data4[1], profile->Data4[2],
703       profile->Data4[3], profile->Data4[4], profile->Data4[5],
704       profile->Data4[6], profile->Data4[7]);
705 
706   return TRUE;
707 }
708 
709 
710 gboolean
gst_d3d11_decoder_configure(GstD3D11Decoder * decoder,GstVideoCodecState * input_state,GstVideoInfo * info,gint coded_width,gint coded_height,guint dpb_size)711 gst_d3d11_decoder_configure (GstD3D11Decoder * decoder,
712     GstVideoCodecState * input_state, GstVideoInfo * info, gint coded_width,
713     gint coded_height, guint dpb_size)
714 {
715   const GstD3D11Format *d3d11_format;
716 
717   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
718   g_return_val_if_fail (info != NULL, FALSE);
719   g_return_val_if_fail (input_state != NULL, FALSE);
720   g_return_val_if_fail (coded_width >= GST_VIDEO_INFO_WIDTH (info), FALSE);
721   g_return_val_if_fail (coded_height >= GST_VIDEO_INFO_HEIGHT (info), FALSE);
722   g_return_val_if_fail (dpb_size > 0, FALSE);
723 
724   gst_d3d11_decoder_reset (decoder);
725 
726   d3d11_format = gst_d3d11_device_format_from_gst (decoder->device,
727       GST_VIDEO_INFO_FORMAT (info));
728   if (!d3d11_format || d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
729     GST_ERROR_OBJECT (decoder, "Could not determine dxgi format from %s",
730         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
731     return FALSE;
732   }
733 
734   decoder->input_state = gst_video_codec_state_ref (input_state);
735   decoder->info = decoder->output_info = *info;
736   decoder->coded_width = coded_width;
737   decoder->coded_height = coded_height;
738   decoder->dpb_size = dpb_size;
739   decoder->decoder_format = d3d11_format->dxgi_format;
740 
741   decoder->configured = TRUE;
742 
743   return TRUE;
744 }
745 
746 static gboolean
gst_d3d11_decoder_ensure_staging_texture(GstD3D11Decoder * self)747 gst_d3d11_decoder_ensure_staging_texture (GstD3D11Decoder * self)
748 {
749   ID3D11Device *device_handle;
750   D3D11_TEXTURE2D_DESC desc = { 0, };
751   HRESULT hr;
752 
753   if (self->staging)
754     return TRUE;
755 
756   device_handle = gst_d3d11_device_get_device_handle (self->device);
757 
758   /* create stage texture to copy out */
759   desc.Width = self->aligned_width;
760   desc.Height = self->aligned_height;
761   desc.MipLevels = 1;
762   desc.Format = self->decoder_format;
763   desc.SampleDesc.Count = 1;
764   desc.ArraySize = 1;
765   desc.Usage = D3D11_USAGE_STAGING;
766   desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
767 
768   hr = device_handle->CreateTexture2D (&desc, NULL, &self->staging);
769   if (!gst_d3d11_result (hr, self->device)) {
770     GST_ERROR_OBJECT (self, "Couldn't create staging texture");
771     return FALSE;
772   }
773 
774   return TRUE;
775 }
776 
777 static void
gst_d3d11_decoder_enable_high_precision_timer(GstD3D11Decoder * self)778 gst_d3d11_decoder_enable_high_precision_timer (GstD3D11Decoder * self)
779 {
780 #if HAVE_WINMM
781   GstD3D11DeviceVendor vendor;
782 
783   if (self->timer_resolution)
784     return;
785 
786   vendor = gst_d3d11_get_device_vendor (self->device);
787   /* Do this only for NVIDIA at the moment, other vendors doesn't seem to be
788    * requiring retry for BeginFrame() */
789   if (vendor == GST_D3D11_DEVICE_VENDOR_NVIDIA) {
790     TIMECAPS time_caps;
791     if (timeGetDevCaps (&time_caps, sizeof (TIMECAPS)) == TIMERR_NOERROR) {
792       guint resolution;
793       MMRESULT ret;
794 
795       resolution = MIN (MAX (time_caps.wPeriodMin, 1), time_caps.wPeriodMax);
796 
797       ret = timeBeginPeriod (resolution);
798       if (ret == TIMERR_NOERROR) {
799         self->timer_resolution = resolution;
800         GST_INFO_OBJECT (self, "Updated timer resolution to %d", resolution);
801       }
802     }
803   }
804 #endif
805 }
806 
807 static gboolean
gst_d3d11_decoder_open(GstD3D11Decoder * self)808 gst_d3d11_decoder_open (GstD3D11Decoder * self)
809 {
810   HRESULT hr;
811   BOOL can_support = FALSE;
812   guint config_count;
813   D3D11_VIDEO_DECODER_CONFIG *config_list;
814   D3D11_VIDEO_DECODER_CONFIG *best_config = NULL;
815   D3D11_VIDEO_DECODER_DESC decoder_desc = { 0, };
816   const GUID *selected_profile = NULL;
817   guint i;
818   gint aligned_width, aligned_height;
819   guint alignment;
820   GstD3D11DeviceVendor vendor;
821   ID3D11VideoDevice *video_device;
822   GstVideoInfo *info = &self->info;
823 
824   if (self->opened)
825     return TRUE;
826 
827   if (!self->configured) {
828     GST_ERROR_OBJECT (self, "Should configure first");
829     return FALSE;
830   }
831 
832   video_device = self->video_device;
833 
834   gst_d3d11_device_lock (self->device);
835   if (!gst_d3d11_decoder_get_supported_decoder_profile (self->device,
836           self->codec, GST_VIDEO_INFO_FORMAT (info), &selected_profile)) {
837     goto error;
838   }
839 
840   hr = video_device->CheckVideoDecoderFormat (selected_profile,
841       self->decoder_format, &can_support);
842   if (!gst_d3d11_result (hr, self->device) || !can_support) {
843     GST_ERROR_OBJECT (self,
844         "VideoDevice could not support dxgi format %d, hr: 0x%x",
845         self->decoder_format, (guint) hr);
846     goto error;
847   }
848 
849   gst_d3d11_decoder_clear_resource (self);
850   self->can_direct_rendering = TRUE;
851 
852   vendor = gst_d3d11_get_device_vendor (self->device);
853   switch (vendor) {
854     case GST_D3D11_DEVICE_VENDOR_XBOX:
855       /* FIXME: Need to figure out Xbox device's behavior
856        * https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/issues/1312
857        */
858       self->can_direct_rendering = FALSE;
859       break;
860     default:
861       break;
862   }
863 
864   /* NOTE: other dxva implementations (ffmpeg and vlc) do this
865    * and they say the required alignment were mentioned by dxva spec.
866    * See ff_dxva2_common_frame_params() in dxva.c of ffmpeg and
867    * directx_va_Setup() in directx_va.c of vlc.
868    * But... where it is? */
869   switch (self->codec) {
870     case GST_DXVA_CODEC_H265:
871     case GST_DXVA_CODEC_AV1:
872       /* See directx_va_Setup() impl. in vlc */
873       if (vendor != GST_D3D11_DEVICE_VENDOR_XBOX)
874         alignment = 128;
875       else
876         alignment = 16;
877       break;
878     case GST_DXVA_CODEC_MPEG2:
879       /* XXX: ffmpeg does this */
880       alignment = 32;
881       break;
882     default:
883       alignment = 16;
884       break;
885   }
886 
887   aligned_width = GST_ROUND_UP_N (self->coded_width, alignment);
888   aligned_height = GST_ROUND_UP_N (self->coded_height, alignment);
889   if (aligned_width != self->coded_width ||
890       aligned_height != self->coded_height) {
891     GST_DEBUG_OBJECT (self,
892         "coded resolution %dx%d is not aligned to %d, adjust to %dx%d",
893         self->coded_width, self->coded_height, alignment, aligned_width,
894         aligned_height);
895   }
896 
897   self->aligned_width = aligned_width;
898   self->aligned_height = aligned_height;
899 
900   decoder_desc.SampleWidth = aligned_width;
901   decoder_desc.SampleHeight = aligned_height;
902   decoder_desc.OutputFormat = self->decoder_format;
903   decoder_desc.Guid = *selected_profile;
904 
905   hr = video_device->GetVideoDecoderConfigCount (&decoder_desc, &config_count);
906   if (!gst_d3d11_result (hr, self->device) || config_count == 0) {
907     GST_ERROR_OBJECT (self, "Could not get decoder config count, hr: 0x%x",
908         (guint) hr);
909     goto error;
910   }
911 
912   GST_DEBUG_OBJECT (self, "Total %d config available", config_count);
913 
914   config_list = (D3D11_VIDEO_DECODER_CONFIG *)
915       g_alloca (sizeof (D3D11_VIDEO_DECODER_CONFIG) * config_count);
916 
917   for (i = 0; i < config_count; i++) {
918     hr = video_device->GetVideoDecoderConfig (&decoder_desc, i,
919         &config_list[i]);
920     if (!gst_d3d11_result (hr, self->device)) {
921       GST_ERROR_OBJECT (self, "Could not get decoder %dth config, hr: 0x%x",
922           i, (guint) hr);
923       goto error;
924     }
925 
926     /* FIXME: need support DXVA_Slice_H264_Long ?? */
927     /* this config uses DXVA_Slice_H264_Short */
928     switch (self->codec) {
929       case GST_DXVA_CODEC_H264:
930         if (config_list[i].ConfigBitstreamRaw == 2)
931           best_config = &config_list[i];
932         break;
933       case GST_DXVA_CODEC_H265:
934       case GST_DXVA_CODEC_VP9:
935       case GST_DXVA_CODEC_VP8:
936       case GST_DXVA_CODEC_MPEG2:
937       case GST_DXVA_CODEC_AV1:
938         if (config_list[i].ConfigBitstreamRaw == 1)
939           best_config = &config_list[i];
940         break;
941       default:
942         g_assert_not_reached ();
943         goto error;
944     }
945 
946     if (best_config)
947       break;
948   }
949 
950   if (best_config == NULL) {
951     GST_ERROR_OBJECT (self, "Could not determine decoder config");
952     goto error;
953   }
954 
955   GST_DEBUG_OBJECT (self, "ConfigDecoderSpecific 0x%x",
956       best_config->ConfigDecoderSpecific);
957 
958   /* bit 14 is equal to 1b means this config support array of texture and
959    * it's recommended type as per DXVA spec */
960   if ((best_config->ConfigDecoderSpecific & 0x4000) == 0x4000) {
961     GST_DEBUG_OBJECT (self, "Config support array of texture");
962     self->use_array_of_texture = TRUE;
963   }
964 
965   hr = video_device->CreateVideoDecoder (&decoder_desc,
966       best_config, &self->decoder_handle);
967   if (!gst_d3d11_result (hr, self->device) || !self->decoder_handle) {
968     GST_ERROR_OBJECT (self,
969         "Could not create decoder object, hr: 0x%x", (guint) hr);
970     goto error;
971   }
972 
973   GST_DEBUG_OBJECT (self, "Decoder object %p created", self->decoder_handle);
974 
975   if (!self->downstream_supports_d3d11 &&
976       !gst_d3d11_decoder_ensure_staging_texture (self)) {
977     GST_ERROR_OBJECT (self, "Couldn't prepare staging texture");
978     goto error;
979   }
980 
981   self->decoder_profile = *selected_profile;
982 
983   /* Store pool related information here, then we will setup internal pool
984    * later once the number of min buffer size required by downstream is known.
985    * Actual buffer pool size will be "dpb_size + downstream_min_buffers"
986    */
987   self->downstream_min_buffers = 0;
988   self->wait_on_pool_full = FALSE;
989 
990   self->opened = TRUE;
991   gst_d3d11_device_unlock (self->device);
992 
993   gst_d3d11_decoder_enable_high_precision_timer (self);
994 
995   return TRUE;
996 
997 error:
998   gst_d3d11_decoder_reset (self);
999   gst_d3d11_device_unlock (self->device);
1000 
1001   return FALSE;
1002 }
1003 
1004 static gboolean
gst_d3d11_decoder_begin_frame(GstD3D11Decoder * decoder,ID3D11VideoDecoderOutputView * output_view,guint content_key_size,gconstpointer content_key)1005 gst_d3d11_decoder_begin_frame (GstD3D11Decoder * decoder,
1006     ID3D11VideoDecoderOutputView * output_view, guint content_key_size,
1007     gconstpointer content_key)
1008 {
1009   ID3D11VideoContext *video_context;
1010   guint retry_count = 0;
1011   HRESULT hr;
1012   guint retry_threshold = 100;
1013 
1014   /* if we have high resolution timer, do more retry */
1015   if (decoder->timer_resolution)
1016     retry_threshold = 500;
1017 
1018   video_context = decoder->video_context;
1019 
1020   do {
1021     GST_LOG_OBJECT (decoder, "Try begin frame, retry count %d", retry_count);
1022     hr = video_context->DecoderBeginFrame (decoder->decoder_handle,
1023         output_view, content_key_size, content_key);
1024 
1025     /* HACK: Do retry with 1ms sleep per failure, since DXVA/D3D11
1026      * doesn't provide API for "GPU-IS-READY-TO-DECODE" like signal.
1027      */
1028     if (hr == E_PENDING && retry_count < retry_threshold) {
1029       GST_LOG_OBJECT (decoder, "GPU is busy, try again. Retry count %d",
1030           retry_count);
1031       g_usleep (1000);
1032     } else {
1033       if (gst_d3d11_result (hr, decoder->device))
1034         GST_LOG_OBJECT (decoder, "Succeeded with retry count %d", retry_count);
1035       break;
1036     }
1037 
1038     retry_count++;
1039   } while (TRUE);
1040 
1041   if (!gst_d3d11_result (hr, decoder->device)) {
1042     GST_ERROR_OBJECT (decoder, "Failed to begin frame, hr: 0x%x", (guint) hr);
1043     return FALSE;
1044   }
1045 
1046   return TRUE;
1047 }
1048 
1049 static gboolean
gst_d3d11_decoder_end_frame(GstD3D11Decoder * decoder)1050 gst_d3d11_decoder_end_frame (GstD3D11Decoder * decoder)
1051 {
1052   HRESULT hr;
1053   ID3D11VideoContext *video_context;
1054 
1055   video_context = decoder->video_context;
1056   hr = video_context->DecoderEndFrame (decoder->decoder_handle);
1057 
1058   if (!gst_d3d11_result (hr, decoder->device)) {
1059     GST_WARNING_OBJECT (decoder, "EndFrame failed, hr: 0x%x", (guint) hr);
1060     return FALSE;
1061   }
1062 
1063   return TRUE;
1064 }
1065 
1066 static gboolean
gst_d3d11_decoder_get_decoder_buffer(GstD3D11Decoder * decoder,D3D11_VIDEO_DECODER_BUFFER_TYPE type,guint * buffer_size,gpointer * buffer)1067 gst_d3d11_decoder_get_decoder_buffer (GstD3D11Decoder * decoder,
1068     D3D11_VIDEO_DECODER_BUFFER_TYPE type, guint * buffer_size,
1069     gpointer * buffer)
1070 {
1071   UINT size;
1072   void *decoder_buffer;
1073   HRESULT hr;
1074   ID3D11VideoContext *video_context;
1075 
1076   video_context = decoder->video_context;
1077   hr = video_context->GetDecoderBuffer (decoder->decoder_handle,
1078       type, &size, &decoder_buffer);
1079 
1080   if (!gst_d3d11_result (hr, decoder->device)) {
1081     GST_WARNING_OBJECT (decoder, "Getting buffer type %d error, hr: 0x%x",
1082         type, (guint) hr);
1083     return FALSE;
1084   }
1085 
1086   *buffer_size = size;
1087   *buffer = decoder_buffer;
1088 
1089   return TRUE;
1090 }
1091 
1092 static gboolean
gst_d3d11_decoder_release_decoder_buffer(GstD3D11Decoder * decoder,D3D11_VIDEO_DECODER_BUFFER_TYPE type)1093 gst_d3d11_decoder_release_decoder_buffer (GstD3D11Decoder * decoder,
1094     D3D11_VIDEO_DECODER_BUFFER_TYPE type)
1095 {
1096   HRESULT hr;
1097   ID3D11VideoContext *video_context;
1098 
1099   video_context = decoder->video_context;
1100   hr = video_context->ReleaseDecoderBuffer (decoder->decoder_handle, type);
1101 
1102   if (!gst_d3d11_result (hr, decoder->device)) {
1103     GST_WARNING_OBJECT (decoder, "ReleaseDecoderBuffer failed, hr: 0x%x",
1104         (guint) hr);
1105     return FALSE;
1106   }
1107 
1108   return TRUE;
1109 }
1110 
1111 static gboolean
gst_d3d11_decoder_submit_decoder_buffers(GstD3D11Decoder * decoder,guint buffer_count,const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)1112 gst_d3d11_decoder_submit_decoder_buffers (GstD3D11Decoder * decoder,
1113     guint buffer_count, const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)
1114 {
1115   HRESULT hr;
1116   ID3D11VideoContext *video_context;
1117 
1118   video_context = decoder->video_context;
1119   hr = video_context->SubmitDecoderBuffers (decoder->decoder_handle,
1120       buffer_count, buffers);
1121   if (!gst_d3d11_result (hr, decoder->device)) {
1122     GST_WARNING_OBJECT (decoder, "SubmitDecoderBuffers failed, hr: 0x%x",
1123         (guint) hr);
1124     return FALSE;
1125   }
1126 
1127   return TRUE;
1128 }
1129 
1130 gboolean
gst_d3d11_decoder_decode_frame(GstD3D11Decoder * decoder,ID3D11VideoDecoderOutputView * output_view,GstD3D11DecodeInputStreamArgs * input_args)1131 gst_d3d11_decoder_decode_frame (GstD3D11Decoder * decoder,
1132     ID3D11VideoDecoderOutputView * output_view,
1133     GstD3D11DecodeInputStreamArgs * input_args)
1134 {
1135   guint d3d11_buffer_size;
1136   gpointer d3d11_buffer;
1137   D3D11_VIDEO_DECODER_BUFFER_DESC buffer_desc[4];
1138   guint buffer_desc_size;
1139 
1140   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1141   g_return_val_if_fail (output_view != nullptr, FALSE);
1142   g_return_val_if_fail (input_args != nullptr, FALSE);
1143 
1144   memset (buffer_desc, 0, sizeof (buffer_desc));
1145 
1146   buffer_desc[0].BufferType = D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS;
1147   buffer_desc[0].DataSize = input_args->picture_params_size;
1148 
1149   buffer_desc[1].BufferType = D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL;
1150   buffer_desc[1].DataSize = input_args->slice_control_size;
1151 
1152   buffer_desc[2].BufferType = D3D11_VIDEO_DECODER_BUFFER_BITSTREAM;
1153   buffer_desc[2].DataOffset = 0;
1154   buffer_desc[2].DataSize = input_args->bitstream_size;
1155 
1156   buffer_desc_size = 3;
1157   if (input_args->inverse_quantization_matrix &&
1158       input_args->inverse_quantization_matrix_size > 0) {
1159     buffer_desc[3].BufferType =
1160         D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX;
1161     buffer_desc[3].DataSize = input_args->inverse_quantization_matrix_size;
1162     buffer_desc_size++;
1163   }
1164 
1165   gst_d3d11_device_lock (decoder->device);
1166   if (!gst_d3d11_decoder_begin_frame (decoder, output_view, 0, nullptr)) {
1167     gst_d3d11_device_unlock (decoder->device);
1168 
1169     return FALSE;
1170   }
1171 
1172   if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1173           D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS, &d3d11_buffer_size,
1174           &d3d11_buffer)) {
1175     GST_ERROR_OBJECT (decoder,
1176         "Failed to get decoder buffer for picture parameters");
1177     goto error;
1178   }
1179 
1180   if (d3d11_buffer_size < input_args->picture_params_size) {
1181     GST_ERROR_OBJECT (decoder,
1182         "Too small picture param buffer size %d", d3d11_buffer_size);
1183 
1184     gst_d3d11_decoder_release_decoder_buffer (decoder,
1185         D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS);
1186     goto error;
1187   }
1188 
1189   memcpy (d3d11_buffer, input_args->picture_params,
1190       input_args->picture_params_size);
1191 
1192   if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1193           D3D11_VIDEO_DECODER_BUFFER_PICTURE_PARAMETERS)) {
1194     GST_ERROR_OBJECT (decoder, "Failed to release picture param buffer");
1195     goto error;
1196   }
1197 
1198   if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1199           D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL, &d3d11_buffer_size,
1200           &d3d11_buffer)) {
1201     GST_ERROR_OBJECT (decoder, "Failed to get slice control buffer");
1202     goto error;
1203   }
1204 
1205   if (d3d11_buffer_size < input_args->slice_control_size) {
1206     GST_ERROR_OBJECT (decoder,
1207         "Too small slice control buffer size %d", d3d11_buffer_size);
1208 
1209     gst_d3d11_decoder_release_decoder_buffer (decoder,
1210         D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL);
1211     goto error;
1212   }
1213 
1214   memcpy (d3d11_buffer,
1215       input_args->slice_control, input_args->slice_control_size);
1216 
1217   if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1218           D3D11_VIDEO_DECODER_BUFFER_SLICE_CONTROL)) {
1219     GST_ERROR_OBJECT (decoder, "Failed to release slice control buffer");
1220     goto error;
1221   }
1222 
1223   if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1224           D3D11_VIDEO_DECODER_BUFFER_BITSTREAM, &d3d11_buffer_size,
1225           &d3d11_buffer)) {
1226     GST_ERROR_OBJECT (decoder, "Failed to get bitstream buffer");
1227     goto error;
1228   }
1229 
1230   if (d3d11_buffer_size < input_args->bitstream_size) {
1231     GST_ERROR_OBJECT (decoder, "Too small bitstream buffer size %d",
1232         d3d11_buffer_size);
1233 
1234     gst_d3d11_decoder_release_decoder_buffer (decoder,
1235         D3D11_VIDEO_DECODER_BUFFER_BITSTREAM);
1236     goto error;
1237   }
1238 
1239   memcpy (d3d11_buffer, input_args->bitstream, input_args->bitstream_size);
1240 
1241   if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1242           D3D11_VIDEO_DECODER_BUFFER_BITSTREAM)) {
1243     GST_ERROR_OBJECT (decoder, "Failed to release bitstream buffer");
1244     goto error;
1245   }
1246 
1247   if (input_args->inverse_quantization_matrix_size > 0) {
1248     if (!gst_d3d11_decoder_get_decoder_buffer (decoder,
1249             D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX,
1250             &d3d11_buffer_size, &d3d11_buffer)) {
1251       GST_ERROR_OBJECT (decoder,
1252           "Failed to get inverse quantization matrix buffer");
1253       goto error;
1254     }
1255 
1256     if (d3d11_buffer_size < input_args->inverse_quantization_matrix_size) {
1257       GST_ERROR_OBJECT (decoder,
1258           "Too small inverse quantization matrix buffer buffer %d",
1259           d3d11_buffer_size);
1260 
1261       gst_d3d11_decoder_release_decoder_buffer (decoder,
1262           D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX);
1263       goto error;
1264     }
1265 
1266     memcpy (d3d11_buffer, input_args->inverse_quantization_matrix,
1267         input_args->inverse_quantization_matrix_size);
1268 
1269     if (!gst_d3d11_decoder_release_decoder_buffer (decoder,
1270             D3D11_VIDEO_DECODER_BUFFER_INVERSE_QUANTIZATION_MATRIX)) {
1271       GST_ERROR_OBJECT (decoder,
1272           "Failed to release inverse quantization matrix buffer");
1273       goto error;
1274     }
1275   }
1276 
1277   if (!gst_d3d11_decoder_submit_decoder_buffers (decoder,
1278           buffer_desc_size, buffer_desc)) {
1279     GST_ERROR_OBJECT (decoder, "Failed to submit decoder buffers");
1280     goto error;
1281   }
1282 
1283   if (!gst_d3d11_decoder_end_frame (decoder)) {
1284     gst_d3d11_device_unlock (decoder->device);
1285     return FALSE;
1286   }
1287 
1288   gst_d3d11_device_unlock (decoder->device);
1289 
1290   return TRUE;
1291 
1292 error:
1293   gst_d3d11_decoder_end_frame (decoder);
1294   gst_d3d11_device_unlock (decoder->device);
1295   return FALSE;
1296 }
1297 
1298 GstBuffer *
gst_d3d11_decoder_get_output_view_buffer(GstD3D11Decoder * decoder,GstVideoDecoder * videodec)1299 gst_d3d11_decoder_get_output_view_buffer (GstD3D11Decoder * decoder,
1300     GstVideoDecoder * videodec)
1301 {
1302   GstBuffer *buf = NULL;
1303   GstFlowReturn ret;
1304 
1305   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1306 
1307   if (!decoder->internal_pool) {
1308     /* Try negotiate again whatever the previous negotiation result was.
1309      * There could be updated field(s) in sinkpad caps after we negotiated with
1310      * downstream on new_sequence() call. For example, h264/h265 parse
1311      * will be able to update HDR10 related caps field after parsing
1312      * corresponding SEI messages which are usually placed after the essential
1313      * headers */
1314     gst_video_decoder_negotiate (videodec);
1315 
1316     if (!gst_d3d11_decoder_prepare_output_view_pool (decoder)) {
1317       GST_ERROR_OBJECT (videodec, "Failed to setup internal pool");
1318       return NULL;
1319     }
1320   } else if (!gst_buffer_pool_set_active (decoder->internal_pool, TRUE)) {
1321     GST_ERROR_OBJECT (videodec, "Couldn't set active internal pool");
1322     return NULL;
1323   }
1324 
1325   ret = gst_buffer_pool_acquire_buffer (decoder->internal_pool, &buf, NULL);
1326 
1327   if (ret != GST_FLOW_OK || !buf) {
1328     if (ret != GST_FLOW_FLUSHING) {
1329       GST_ERROR_OBJECT (videodec, "Couldn't get buffer from pool, ret %s",
1330           gst_flow_get_name (ret));
1331     } else {
1332       GST_DEBUG_OBJECT (videodec, "We are flusing");
1333     }
1334 
1335     return NULL;
1336   }
1337 
1338   if (!gst_d3d11_decoder_ensure_output_view (decoder, buf)) {
1339     GST_ERROR_OBJECT (videodec, "Output view unavailable");
1340     gst_buffer_unref (buf);
1341 
1342     return NULL;
1343   }
1344 
1345   return buf;
1346 }
1347 
1348 ID3D11VideoDecoderOutputView *
gst_d3d11_decoder_get_output_view_from_buffer(GstD3D11Decoder * decoder,GstBuffer * buffer,guint8 * index)1349 gst_d3d11_decoder_get_output_view_from_buffer (GstD3D11Decoder * decoder,
1350     GstBuffer * buffer, guint8 * index)
1351 {
1352   GstMemory *mem;
1353   GstD3D11Memory *dmem;
1354   ID3D11VideoDecoderOutputView *view;
1355 
1356   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), NULL);
1357   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
1358 
1359   mem = gst_buffer_peek_memory (buffer, 0);
1360   if (!gst_is_d3d11_memory (mem)) {
1361     GST_WARNING_OBJECT (decoder, "Not a d3d11 memory");
1362     return NULL;
1363   }
1364 
1365   dmem = (GstD3D11Memory *) mem;
1366   view = gst_d3d11_memory_get_decoder_output_view (dmem, decoder->video_device,
1367       decoder->decoder_handle, &decoder->decoder_profile);
1368 
1369   if (!view) {
1370     GST_ERROR_OBJECT (decoder, "Decoder output view is unavailable");
1371     return NULL;
1372   }
1373 
1374   if (index) {
1375     if (decoder->use_array_of_texture) {
1376       guint8 id;
1377       gpointer val = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem),
1378           gst_d3d11_decoder_view_id_quark ());
1379       if (!val) {
1380         GST_ERROR_OBJECT (decoder, "memory has no qdata");
1381         return NULL;
1382       }
1383 
1384       id = (guint8) GPOINTER_TO_UINT (val);
1385       g_assert (id < 128);
1386 
1387       *index = (id - 1);
1388     } else {
1389       *index = gst_d3d11_memory_get_subresource_index (dmem);
1390     }
1391   }
1392 
1393   return view;
1394 }
1395 
1396 static gboolean
copy_to_system(GstD3D11Decoder * self,GstBuffer * decoder_buffer,GstBuffer * output)1397 copy_to_system (GstD3D11Decoder * self, GstBuffer * decoder_buffer,
1398     GstBuffer * output)
1399 {
1400   GstVideoFrame out_frame;
1401   GstVideoInfo *info = &self->output_info;
1402   guint i;
1403   GstD3D11Memory *in_mem;
1404   D3D11_MAPPED_SUBRESOURCE map;
1405   HRESULT hr;
1406   ID3D11Texture2D *in_texture;
1407   guint in_subresource_index;
1408   ID3D11DeviceContext *device_context =
1409       gst_d3d11_device_get_device_context_handle (self->device);
1410 
1411   if (!gst_d3d11_decoder_ensure_staging_texture (self)) {
1412     GST_ERROR_OBJECT (self, "Staging texture is not available");
1413     return FALSE;
1414   }
1415 
1416   if (!gst_video_frame_map (&out_frame, info, output, GST_MAP_WRITE)) {
1417     GST_ERROR_OBJECT (self, "Couldn't map output buffer");
1418     return FALSE;
1419   }
1420 
1421   in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
1422 
1423   in_texture = gst_d3d11_memory_get_texture_handle (in_mem);
1424   in_subresource_index = gst_d3d11_memory_get_subresource_index (in_mem);
1425 
1426   gst_d3d11_device_lock (self->device);
1427   device_context->CopySubresourceRegion (self->staging, 0, 0, 0, 0,
1428       in_texture, in_subresource_index, NULL);
1429 
1430   hr = device_context->Map (self->staging, 0, D3D11_MAP_READ, 0, &map);
1431 
1432   if (!gst_d3d11_result (hr, self->device)) {
1433     GST_ERROR_OBJECT (self, "Failed to map, hr: 0x%x", (guint) hr);
1434 
1435     gst_d3d11_device_unlock (self->device);
1436     gst_video_frame_unmap (&out_frame);
1437 
1438     return FALSE;
1439   }
1440 
1441   /* calculate stride and offset only once */
1442   if (self->stating_texture_stride[0] == 0) {
1443     D3D11_TEXTURE2D_DESC desc;
1444     gsize dummy;
1445 
1446     self->staging->GetDesc (&desc);
1447 
1448     gst_d3d11_dxgi_format_get_size (desc.Format, desc.Width, desc.Height,
1449         map.RowPitch, self->staging_texture_offset,
1450         self->stating_texture_stride, &dummy);
1451   }
1452 
1453   for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&out_frame); i++) {
1454     guint8 *src, *dst;
1455     gint j;
1456     gint width;
1457 
1458     src = (guint8 *) map.pData + self->staging_texture_offset[i];
1459     dst = (guint8 *) GST_VIDEO_FRAME_PLANE_DATA (&out_frame, i);
1460     width = GST_VIDEO_FRAME_COMP_WIDTH (&out_frame, i) *
1461         GST_VIDEO_FRAME_COMP_PSTRIDE (&out_frame, i);
1462 
1463     for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (&out_frame, i); j++) {
1464       memcpy (dst, src, width);
1465       dst += GST_VIDEO_FRAME_PLANE_STRIDE (&out_frame, i);
1466       src += self->stating_texture_stride[i];
1467     }
1468   }
1469 
1470   gst_video_frame_unmap (&out_frame);
1471   device_context->Unmap (self->staging, 0);
1472   gst_d3d11_device_unlock (self->device);
1473 
1474   return TRUE;
1475 }
1476 
1477 static gboolean
copy_to_d3d11(GstD3D11Decoder * self,GstBuffer * decoder_buffer,GstBuffer * output)1478 copy_to_d3d11 (GstD3D11Decoder * self, GstBuffer * decoder_buffer,
1479     GstBuffer * output)
1480 {
1481   GstVideoInfo *info = &self->output_info;
1482   GstD3D11Memory *in_mem;
1483   GstD3D11Memory *out_mem;
1484   GstMapInfo out_map;
1485   D3D11_BOX src_box;
1486   ID3D11Texture2D *in_texture;
1487   guint in_subresource_index, out_subresource_index;
1488   ID3D11DeviceContext *device_context =
1489       gst_d3d11_device_get_device_context_handle (self->device);
1490 
1491   in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
1492   out_mem = (GstD3D11Memory *) gst_buffer_peek_memory (output, 0);
1493 
1494   if (!gst_memory_map (GST_MEMORY_CAST (out_mem),
1495           &out_map, (GstMapFlags) (GST_MAP_WRITE | GST_MAP_D3D11))) {
1496     GST_ERROR_OBJECT (self, "Couldn't map output d3d11 memory");
1497     return FALSE;
1498   }
1499 
1500   gst_d3d11_device_lock (self->device);
1501   in_texture = gst_d3d11_memory_get_texture_handle (in_mem);
1502   in_subresource_index = gst_d3d11_memory_get_subresource_index (in_mem);
1503 
1504   src_box.left = 0;
1505   src_box.top = 0;
1506   src_box.front = 0;
1507   src_box.back = 1;
1508 
1509   src_box.right = GST_ROUND_UP_2 (GST_VIDEO_INFO_WIDTH (info));
1510   src_box.bottom = GST_ROUND_UP_2 (GST_VIDEO_INFO_HEIGHT (info));
1511 
1512   out_subresource_index = gst_d3d11_memory_get_subresource_index (out_mem);
1513   device_context->CopySubresourceRegion ((ID3D11Resource *) out_map.data,
1514       out_subresource_index, 0, 0, 0, in_texture, in_subresource_index,
1515       &src_box);
1516 
1517   gst_d3d11_device_unlock (self->device);
1518   gst_memory_unmap (GST_MEMORY_CAST (out_mem), &out_map);
1519 
1520   return TRUE;
1521 }
1522 
1523 gboolean
gst_d3d11_decoder_process_output(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,gint display_width,gint display_height,GstBuffer * decoder_buffer,GstBuffer ** output)1524 gst_d3d11_decoder_process_output (GstD3D11Decoder * decoder,
1525     GstVideoDecoder * videodec, gint display_width, gint display_height,
1526     GstBuffer * decoder_buffer, GstBuffer ** output)
1527 {
1528   gboolean can_device_copy = TRUE;
1529 
1530   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1531   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1532   g_return_val_if_fail (GST_IS_BUFFER (decoder_buffer), FALSE);
1533   g_return_val_if_fail (output != NULL, FALSE);
1534 
1535   if (display_width != GST_VIDEO_INFO_WIDTH (&decoder->output_info) ||
1536       display_height != GST_VIDEO_INFO_HEIGHT (&decoder->output_info)) {
1537     GST_INFO_OBJECT (videodec, "Frame size changed, do renegotiate");
1538 
1539     gst_video_info_set_format (&decoder->output_info,
1540         GST_VIDEO_INFO_FORMAT (&decoder->info), display_width, display_height);
1541     GST_VIDEO_INFO_INTERLACE_MODE (&decoder->output_info) =
1542         GST_VIDEO_INFO_INTERLACE_MODE (&decoder->info);
1543 
1544     if (!gst_video_decoder_negotiate (videodec)) {
1545       GST_ERROR_OBJECT (videodec, "Failed to re-negotiate with new frame size");
1546       return FALSE;
1547     }
1548   }
1549 
1550   if (gst_d3d11_decoder_can_direct_render (decoder, videodec, decoder_buffer,
1551           display_width, display_height)) {
1552     GstMemory *mem;
1553 
1554     mem = gst_buffer_peek_memory (decoder_buffer, 0);
1555     GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
1556 
1557     *output = gst_buffer_ref (decoder_buffer);
1558 
1559     return TRUE;
1560   }
1561 
1562   *output = gst_video_decoder_allocate_output_buffer (videodec);
1563   if (*output == NULL) {
1564     GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer");
1565 
1566     return FALSE;
1567   }
1568 
1569   /* decoder buffer must have single memory */
1570   if (gst_buffer_n_memory (decoder_buffer) == gst_buffer_n_memory (*output)) {
1571     GstMemory *mem;
1572     GstD3D11Memory *dmem;
1573 
1574     mem = gst_buffer_peek_memory (*output, 0);
1575     if (!gst_is_d3d11_memory (mem)) {
1576       can_device_copy = FALSE;
1577       goto do_process;
1578     }
1579 
1580     dmem = (GstD3D11Memory *) mem;
1581     if (dmem->device != decoder->device)
1582       can_device_copy = FALSE;
1583   } else {
1584     can_device_copy = FALSE;
1585   }
1586 
1587 do_process:
1588   if (can_device_copy) {
1589     return copy_to_d3d11 (decoder, decoder_buffer, *output);
1590   }
1591 
1592   return copy_to_system (decoder, decoder_buffer, *output);
1593 }
1594 
1595 gboolean
gst_d3d11_decoder_negotiate(GstD3D11Decoder * decoder,GstVideoDecoder * videodec)1596 gst_d3d11_decoder_negotiate (GstD3D11Decoder * decoder,
1597     GstVideoDecoder * videodec)
1598 {
1599   GstVideoInfo *info;
1600   GstCaps *peer_caps;
1601   GstVideoCodecState *state = NULL;
1602   gboolean alternate_interlaced;
1603   gboolean alternate_supported = FALSE;
1604   gboolean d3d11_supported = FALSE;
1605   /* No d3d11 element supports alternate now */
1606   gboolean d3d11_alternate_supported = FALSE;
1607   GstVideoCodecState *input_state;
1608   GstStructure *s;
1609   const gchar *str;
1610 
1611   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1612   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1613 
1614   info = &decoder->output_info;
1615   input_state = decoder->input_state;
1616 
1617   alternate_interlaced =
1618       (GST_VIDEO_INFO_INTERLACE_MODE (info) ==
1619       GST_VIDEO_INTERLACE_MODE_ALTERNATE);
1620 
1621   peer_caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (videodec));
1622   GST_DEBUG_OBJECT (videodec, "Allowed caps %" GST_PTR_FORMAT, peer_caps);
1623 
1624   if (!peer_caps || gst_caps_is_any (peer_caps)) {
1625     GST_DEBUG_OBJECT (videodec,
1626         "cannot determine output format, use system memory");
1627   } else {
1628     GstCapsFeatures *features;
1629     guint size = gst_caps_get_size (peer_caps);
1630     guint i;
1631 
1632     for (i = 0; i < size; i++) {
1633       features = gst_caps_get_features (peer_caps, i);
1634 
1635       if (!features)
1636         continue;
1637 
1638       if (gst_caps_features_contains (features,
1639               GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1640         d3d11_supported = TRUE;
1641 
1642         if (gst_caps_features_contains (features,
1643                 GST_CAPS_FEATURE_FORMAT_INTERLACED)) {
1644           d3d11_alternate_supported = TRUE;
1645         }
1646       }
1647 
1648       if (gst_caps_features_contains (features,
1649               GST_CAPS_FEATURE_FORMAT_INTERLACED)) {
1650         alternate_supported = TRUE;
1651       }
1652     }
1653   }
1654   gst_clear_caps (&peer_caps);
1655 
1656   GST_DEBUG_OBJECT (videodec,
1657       "Downstream feature support, D3D11 memory: %d, interlaced format %d",
1658       d3d11_supported, alternate_supported);
1659 
1660   if (alternate_interlaced) {
1661     /* FIXME: D3D11 cannot support alternating interlaced stream yet */
1662     GST_FIXME_OBJECT (videodec,
1663         "Implement alternating interlaced stream for D3D11");
1664 
1665     if (d3d11_alternate_supported || (!d3d11_supported && alternate_supported)) {
1666       gint height = GST_VIDEO_INFO_HEIGHT (info);
1667 
1668       /* Set caps resolution with display size, that's how we designed
1669        * for alternating interlaced stream */
1670       height = 2 * height;
1671       state = gst_video_decoder_set_interlaced_output_state (videodec,
1672           GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1673           GST_VIDEO_INFO_WIDTH (info), height, input_state);
1674     } else {
1675       GST_WARNING_OBJECT (videodec,
1676           "Downstream doesn't support alternating interlaced stream");
1677 
1678       state = gst_video_decoder_set_output_state (videodec,
1679           GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
1680           GST_VIDEO_INFO_HEIGHT (info), input_state);
1681 
1682       /* XXX: adjust PAR, this would produce output similar to that of
1683        * "line doubling" (so called bob deinterlacing) processing.
1684        * apart from missing anchor line (top-field or bottom-field) information.
1685        * Potentially flickering could happen. So this might not be correct.
1686        * But it would be better than negotiation error of half-height squeezed
1687        * image */
1688       state->info.par_d *= 2;
1689       state->info.fps_n *= 2;
1690     }
1691   } else {
1692     state = gst_video_decoder_set_interlaced_output_state (videodec,
1693         GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1694         GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), input_state);
1695   }
1696 
1697   if (!state) {
1698     GST_ERROR_OBJECT (decoder, "Couldn't set output state");
1699     return FALSE;
1700   }
1701 
1702   state->caps = gst_video_info_to_caps (&state->info);
1703 
1704   s = gst_caps_get_structure (input_state->caps, 0);
1705   str = gst_structure_get_string (s, "mastering-display-info");
1706   if (str) {
1707     gst_caps_set_simple (state->caps,
1708         "mastering-display-info", G_TYPE_STRING, str, nullptr);
1709   }
1710 
1711   str = gst_structure_get_string (s, "content-light-level");
1712   if (str) {
1713     gst_caps_set_simple (state->caps,
1714         "content-light-level", G_TYPE_STRING, str, nullptr);
1715   }
1716 
1717   g_clear_pointer (&decoder->output_state, gst_video_codec_state_unref);
1718   decoder->output_state = state;
1719 
1720   if (d3d11_supported) {
1721     gst_caps_set_features (state->caps, 0,
1722         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL));
1723   }
1724 
1725   decoder->downstream_supports_d3d11 = d3d11_supported;
1726 
1727   return gst_d3d11_decoder_open (decoder);
1728 }
1729 
1730 gboolean
gst_d3d11_decoder_decide_allocation(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,GstQuery * query)1731 gst_d3d11_decoder_decide_allocation (GstD3D11Decoder * decoder,
1732     GstVideoDecoder * videodec, GstQuery * query)
1733 {
1734   GstCaps *outcaps;
1735   GstBufferPool *pool = NULL;
1736   guint n, size, min = 0, max = 0;
1737   GstVideoInfo vinfo = { 0, };
1738   GstStructure *config;
1739   GstD3D11AllocationParams *d3d11_params;
1740   gboolean use_d3d11_pool;
1741 
1742   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1743   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1744   g_return_val_if_fail (query != NULL, FALSE);
1745 
1746   if (!decoder->opened) {
1747     GST_ERROR_OBJECT (videodec, "Should open decoder first");
1748     return FALSE;
1749   }
1750 
1751   gst_query_parse_allocation (query, &outcaps, NULL);
1752 
1753   if (!outcaps) {
1754     GST_DEBUG_OBJECT (decoder, "No output caps");
1755     return FALSE;
1756   }
1757 
1758   use_d3d11_pool = decoder->downstream_supports_d3d11;
1759 
1760   gst_video_info_from_caps (&vinfo, outcaps);
1761   n = gst_query_get_n_allocation_pools (query);
1762   if (n > 0)
1763     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1764 
1765   /* create our own pool */
1766   if (pool && use_d3d11_pool) {
1767     if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
1768       GST_DEBUG_OBJECT (videodec,
1769           "Downstream pool is not d3d11, will create new one");
1770       gst_clear_object (&pool);
1771     } else {
1772       GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
1773       if (dpool->device != decoder->device) {
1774         GST_DEBUG_OBJECT (videodec, "Different device, will create new one");
1775         gst_clear_object (&pool);
1776       }
1777     }
1778   }
1779 
1780   if (!pool) {
1781     if (use_d3d11_pool)
1782       pool = gst_d3d11_buffer_pool_new (decoder->device);
1783     else
1784       pool = gst_video_buffer_pool_new ();
1785 
1786     size = (guint) vinfo.size;
1787   }
1788 
1789   config = gst_buffer_pool_get_config (pool);
1790   gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1791   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1792 
1793   if (use_d3d11_pool) {
1794     GstVideoAlignment align;
1795     gint width, height;
1796 
1797     gst_video_alignment_reset (&align);
1798 
1799     d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
1800     if (!d3d11_params)
1801       d3d11_params = gst_d3d11_allocation_params_new (decoder->device, &vinfo,
1802           (GstD3D11AllocationFlags) 0, 0);
1803 
1804     width = GST_VIDEO_INFO_WIDTH (&vinfo);
1805     height = GST_VIDEO_INFO_HEIGHT (&vinfo);
1806 
1807     /* need alignment to copy decoder output texture to downstream texture */
1808     align.padding_right = GST_ROUND_UP_16 (width) - width;
1809     align.padding_bottom = GST_ROUND_UP_16 (height) - height;
1810     if (!gst_d3d11_allocation_params_alignment (d3d11_params, &align)) {
1811       GST_ERROR_OBJECT (videodec, "Cannot set alignment");
1812       return FALSE;
1813     }
1814 
1815     /* Needs render target bind flag so that it can be used for
1816      * output of shader pipeline if internal resizing is required.
1817      * Also, downstream can keep using video processor even if we copy
1818      * some decoded textures into downstream buffer */
1819     d3d11_params->desc[0].BindFlags |= D3D11_BIND_RENDER_TARGET;
1820 
1821     gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1822     gst_d3d11_allocation_params_free (d3d11_params);
1823 
1824     /* Store min buffer size. We need to take account of the amount of buffers
1825      * which might be held by downstream in case of zero-copy playback */
1826     if (!decoder->internal_pool) {
1827       if (n > 0) {
1828         GST_DEBUG_OBJECT (videodec, "Downstream proposed pool");
1829         decoder->wait_on_pool_full = TRUE;
1830         /* XXX: hardcoded bound 16, to avoid too large pool size */
1831         decoder->downstream_min_buffers = MIN (min, 16);
1832       } else {
1833         GST_DEBUG_OBJECT (videodec, "Downstream didn't propose pool");
1834         decoder->wait_on_pool_full = FALSE;
1835         /* don't know how many buffers would be queued by downstream */
1836         decoder->downstream_min_buffers = 4;
1837       }
1838     } else {
1839       /* We configured our DPB pool already, let's check if our margin can
1840        * cover min size */
1841       decoder->wait_on_pool_full = FALSE;
1842 
1843       if (n > 0) {
1844         if (decoder->downstream_min_buffers >= min)
1845           decoder->wait_on_pool_full = TRUE;
1846 
1847         GST_DEBUG_OBJECT (videodec,
1848             "Pre-allocated margin %d can%s cover downstream min size %d",
1849             decoder->downstream_min_buffers,
1850             decoder->wait_on_pool_full ? "" : "not", min);
1851       } else {
1852         GST_DEBUG_OBJECT (videodec, "Downstream min size is unknown");
1853       }
1854     }
1855 
1856     GST_DEBUG_OBJECT (videodec, "Downstream min buffres: %d", min);
1857 
1858     /* We will not use downstream pool for decoding, and therefore preallocation
1859      * is unnecessary. So, Non-zero min buffer will be a waste of GPU memory */
1860     min = 0;
1861   }
1862 
1863   gst_buffer_pool_set_config (pool, config);
1864   if (use_d3d11_pool) {
1865     /* d3d11 buffer pool will update buffer size based on allocated texture,
1866      * get size from config again */
1867     config = gst_buffer_pool_get_config (pool);
1868     gst_buffer_pool_config_get_params (config,
1869         nullptr, &size, nullptr, nullptr);
1870     gst_structure_free (config);
1871   }
1872 
1873   if (n > 0)
1874     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1875   else
1876     gst_query_add_allocation_pool (query, pool, size, min, max);
1877   gst_object_unref (pool);
1878 
1879   return TRUE;
1880 }
1881 
1882 gboolean
gst_d3d11_decoder_set_flushing(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,gboolean flushing)1883 gst_d3d11_decoder_set_flushing (GstD3D11Decoder * decoder,
1884     GstVideoDecoder * videodec, gboolean flushing)
1885 {
1886   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1887 
1888   g_mutex_lock (&decoder->internal_pool_lock);
1889   if (decoder->internal_pool)
1890     gst_buffer_pool_set_flushing (decoder->internal_pool, flushing);
1891   g_mutex_unlock (&decoder->internal_pool_lock);
1892 
1893   return TRUE;
1894 }
1895 
1896 static gboolean
gst_d3d11_decoder_can_direct_render(GstD3D11Decoder * decoder,GstVideoDecoder * videodec,GstBuffer * view_buffer,gint display_width,gint display_height)1897 gst_d3d11_decoder_can_direct_render (GstD3D11Decoder * decoder,
1898     GstVideoDecoder * videodec, GstBuffer * view_buffer,
1899     gint display_width, gint display_height)
1900 {
1901   GstMemory *mem;
1902   GstD3D11PoolAllocator *alloc;
1903   guint max_size = 0, outstanding_size = 0;
1904 
1905   /* We don't support direct render for reverse playback */
1906   if (videodec->input_segment.rate < 0)
1907     return FALSE;
1908 
1909   if (!decoder->can_direct_rendering || !decoder->downstream_supports_d3d11)
1910     return FALSE;
1911 
1912   /* different size, need copy */
1913   /* TODO: crop meta */
1914   if (display_width != GST_VIDEO_INFO_WIDTH (&decoder->info) ||
1915       display_height != GST_VIDEO_INFO_HEIGHT (&decoder->info))
1916     return FALSE;
1917 
1918   /* we can do direct render in this case, since there is no DPB pool size
1919    * limit */
1920   if (decoder->use_array_of_texture)
1921     return TRUE;
1922 
1923   /* Let's believe downstream info */
1924   if (decoder->wait_on_pool_full)
1925     return TRUE;
1926 
1927   /* Check if we are about to full */
1928   mem = gst_buffer_peek_memory (view_buffer, 0);
1929 
1930   /* something went wrong */
1931   if (!gst_is_d3d11_memory (mem)) {
1932     GST_ERROR_OBJECT (decoder, "Not a D3D11 memory");
1933     return FALSE;
1934   }
1935 
1936   alloc = GST_D3D11_POOL_ALLOCATOR (mem->allocator);
1937   if (!gst_d3d11_pool_allocator_get_pool_size (alloc, &max_size,
1938           &outstanding_size)) {
1939     GST_ERROR_OBJECT (decoder, "Couldn't query pool size");
1940     return FALSE;
1941   }
1942 
1943   /* 2 buffer margin */
1944   if (max_size <= outstanding_size + 1) {
1945     GST_DEBUG_OBJECT (decoder, "memory pool is about to full (%u/%u)",
1946         outstanding_size, max_size);
1947     return FALSE;
1948   }
1949 
1950   GST_LOG_OBJECT (decoder, "Can do direct rendering");
1951 
1952   return TRUE;
1953 }
1954 
1955 /* Keep sync with chromium and keep in sorted order.
1956  * See supported_profile_helpers.cc in chromium */
1957 static const guint legacy_amd_list[] = {
1958   0x130f, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707,
1959   0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x6720, 0x6721,
1960   0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, 0x6738,
1961   0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746,
1962   0x6747, 0x6748, 0x6749, 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b,
1963   0x675d, 0x675f, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766,
1964   0x6767, 0x6768, 0x6770, 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6798,
1965   0x67b1, 0x6821, 0x683d, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, 0x6850,
1966   0x6858, 0x6859, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, 0x6898,
1967   0x6899, 0x689b, 0x689c, 0x689d, 0x689e, 0x68a0, 0x68a1, 0x68a8, 0x68a9,
1968   0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x68c0, 0x68c1, 0x68c7,
1969   0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68e0, 0x68e1, 0x68e4,
1970   0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, 0x68fe,
1971   0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x9440,
1972   0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e,
1973   0x9450, 0x9452, 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a,
1974   0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, 0x9489, 0x948a, 0x948f,
1975   0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x94a0, 0x94a1,
1976   0x94a3, 0x94b1, 0x94b3, 0x94b4, 0x94b5, 0x94b9, 0x94c0, 0x94c1, 0x94c3,
1977   0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd,
1978   0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, 0x9508, 0x9509, 0x950f,
1979   0x9511, 0x9515, 0x9517, 0x9519, 0x9540, 0x9541, 0x9542, 0x954e, 0x954f,
1980   0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x9580, 0x9581, 0x9583, 0x9586,
1981   0x9587, 0x9588, 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f,
1982   0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, 0x959b,
1983   0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c9, 0x95cc, 0x95cd,
1984   0x95ce, 0x95cf, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616,
1985   0x9640, 0x9641, 0x9642, 0x9643, 0x9644, 0x9645, 0x9647, 0x9648, 0x9649,
1986   0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9710, 0x9711, 0x9712, 0x9713,
1987   0x9714, 0x9715, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808,
1988   0x9809, 0x980a, 0x9830, 0x983d, 0x9850, 0x9851, 0x9874, 0x9900, 0x9901,
1989   0x9903, 0x9904, 0x9905, 0x9906, 0x9907, 0x9908, 0x9909, 0x990a, 0x990b,
1990   0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, 0x9919,
1991   0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
1992   0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4
1993 };
1994 
1995 static const guint legacy_intel_list[] = {
1996   0x102, 0x106, 0x116, 0x126, 0x152, 0x156, 0x166,
1997   0x402, 0x406, 0x416, 0x41e, 0xa06, 0xa16, 0xf31,
1998 };
1999 
2000 static gint
binary_search_compare(const guint * a,const guint * b)2001 binary_search_compare (const guint * a, const guint * b)
2002 {
2003   return *a - *b;
2004 }
2005 
2006 /* Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and some second
2007  * generation Intel GPU drivers crash if we create a video device with a
2008  * resolution higher then 1920 x 1088. This function checks if the GPU is in
2009  * this list and if yes returns true. */
2010 gboolean
gst_d3d11_decoder_util_is_legacy_device(GstD3D11Device * device)2011 gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device)
2012 {
2013   const guint amd_id[] = { 0x1002, 0x1022 };
2014   const guint intel_id = 0x8086;
2015   guint device_id = 0;
2016   guint vendor_id = 0;
2017   guint *match = NULL;
2018 
2019   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
2020 
2021   g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id, NULL);
2022 
2023   if (vendor_id == amd_id[0] || vendor_id == amd_id[1]) {
2024     match =
2025         (guint *) gst_util_array_binary_search ((gpointer) legacy_amd_list,
2026         G_N_ELEMENTS (legacy_amd_list), sizeof (guint),
2027         (GCompareDataFunc) binary_search_compare,
2028         GST_SEARCH_MODE_EXACT, &device_id, NULL);
2029   } else if (vendor_id == intel_id) {
2030     match =
2031         (guint *) gst_util_array_binary_search ((gpointer) legacy_intel_list,
2032         G_N_ELEMENTS (legacy_intel_list), sizeof (guint),
2033         (GCompareDataFunc) binary_search_compare,
2034         GST_SEARCH_MODE_EXACT, &device_id, NULL);
2035   }
2036 
2037   if (match) {
2038     GST_DEBUG_OBJECT (device, "it's legacy device");
2039     return TRUE;
2040   }
2041 
2042   return FALSE;
2043 }
2044 
2045 gboolean
gst_d3d11_decoder_supports_format(GstD3D11Device * device,const GUID * decoder_profile,DXGI_FORMAT format)2046 gst_d3d11_decoder_supports_format (GstD3D11Device * device,
2047     const GUID * decoder_profile, DXGI_FORMAT format)
2048 {
2049   HRESULT hr;
2050   BOOL can_support = FALSE;
2051   ID3D11VideoDevice *video_device;
2052 
2053   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
2054   g_return_val_if_fail (decoder_profile != NULL, FALSE);
2055   g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
2056 
2057   video_device = gst_d3d11_device_get_video_device_handle (device);
2058   if (!video_device)
2059     return FALSE;
2060 
2061   hr = video_device->CheckVideoDecoderFormat (decoder_profile, format,
2062       &can_support);
2063   if (!gst_d3d11_result (hr, device) || !can_support) {
2064     GST_DEBUG_OBJECT (device,
2065         "VideoDevice could not support dxgi format %d, hr: 0x%x",
2066         format, (guint) hr);
2067 
2068     return FALSE;
2069   }
2070 
2071   return TRUE;
2072 }
2073 
2074 /* Don't call this method with legacy device */
2075 gboolean
gst_d3d11_decoder_supports_resolution(GstD3D11Device * device,const GUID * decoder_profile,DXGI_FORMAT format,guint width,guint height)2076 gst_d3d11_decoder_supports_resolution (GstD3D11Device * device,
2077     const GUID * decoder_profile, DXGI_FORMAT format, guint width, guint height)
2078 {
2079   D3D11_VIDEO_DECODER_DESC desc;
2080   HRESULT hr;
2081   UINT config_count;
2082   ID3D11VideoDevice *video_device;
2083 
2084   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
2085   g_return_val_if_fail (decoder_profile != NULL, FALSE);
2086   g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
2087 
2088   video_device = gst_d3d11_device_get_video_device_handle (device);
2089   if (!video_device)
2090     return FALSE;
2091 
2092   desc.SampleWidth = width;
2093   desc.SampleHeight = height;
2094   desc.OutputFormat = format;
2095   desc.Guid = *decoder_profile;
2096 
2097   hr = video_device->GetVideoDecoderConfigCount (&desc, &config_count);
2098   if (!gst_d3d11_result (hr, device) || config_count == 0) {
2099     GST_DEBUG_OBJECT (device, "Could not get decoder config count, hr: 0x%x",
2100         (guint) hr);
2101     return FALSE;
2102   }
2103 
2104   return TRUE;
2105 }
2106 
2107 enum
2108 {
2109   PROP_DECODER_ADAPTER_LUID = 1,
2110   PROP_DECODER_DEVICE_ID,
2111   PROP_DECODER_VENDOR_ID,
2112 };
2113 
2114 struct _GstD3D11DecoderClassData
2115 {
2116   GstD3D11DecoderSubClassData subclass_data;
2117   GstCaps *sink_caps;
2118   GstCaps *src_caps;
2119   gchar *description;
2120 };
2121 
2122 /**
2123  * gst_d3d11_decoder_class_data_new:
2124  * @device: (transfer none): a #GstD3D11Device
2125  * @sink_caps: (transfer full): a #GstCaps
2126  * @src_caps: (transfer full): a #GstCaps
2127  *
2128  * Create new #GstD3D11DecoderClassData
2129  *
2130  * Returns: (transfer full): the new #GstD3D11DecoderClassData
2131  */
2132 GstD3D11DecoderClassData *
gst_d3d11_decoder_class_data_new(GstD3D11Device * device,GstDXVACodec codec,GstCaps * sink_caps,GstCaps * src_caps)2133 gst_d3d11_decoder_class_data_new (GstD3D11Device * device, GstDXVACodec codec,
2134     GstCaps * sink_caps, GstCaps * src_caps)
2135 {
2136   GstD3D11DecoderClassData *ret;
2137 
2138   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
2139   g_return_val_if_fail (sink_caps != NULL, NULL);
2140   g_return_val_if_fail (src_caps != NULL, NULL);
2141 
2142   ret = g_new0 (GstD3D11DecoderClassData, 1);
2143 
2144   /* class data will be leaked if the element never gets instantiated */
2145   GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2146   GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
2147 
2148   ret->subclass_data.codec = codec;
2149   g_object_get (device, "adapter-luid", &ret->subclass_data.adapter_luid,
2150       "device-id", &ret->subclass_data.device_id,
2151       "vendor-id", &ret->subclass_data.vendor_id,
2152       "description", &ret->description, nullptr);
2153   ret->sink_caps = sink_caps;
2154   ret->src_caps = src_caps;
2155 
2156   return ret;
2157 }
2158 
2159 void
gst_d3d11_decoder_class_data_fill_subclass_data(GstD3D11DecoderClassData * data,GstD3D11DecoderSubClassData * subclass_data)2160 gst_d3d11_decoder_class_data_fill_subclass_data (GstD3D11DecoderClassData *
2161     data, GstD3D11DecoderSubClassData * subclass_data)
2162 {
2163   g_return_if_fail (data != nullptr);
2164   g_return_if_fail (subclass_data != nullptr);
2165 
2166   *subclass_data = data->subclass_data;
2167 }
2168 
2169 static void
gst_d3d11_decoder_class_data_free(GstD3D11DecoderClassData * data)2170 gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data)
2171 {
2172   if (!data)
2173     return;
2174 
2175   gst_clear_caps (&data->sink_caps);
2176   gst_clear_caps (&data->src_caps);
2177   g_free (data->description);
2178   g_free (data);
2179 }
2180 
2181 void
gst_d3d11_decoder_proxy_class_init(GstElementClass * klass,GstD3D11DecoderClassData * data,const gchar * author)2182 gst_d3d11_decoder_proxy_class_init (GstElementClass * klass,
2183     GstD3D11DecoderClassData * data, const gchar * author)
2184 {
2185   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2186   GstD3D11DecoderSubClassData *cdata = &data->subclass_data;
2187   std::string long_name;
2188   std::string description;
2189   const gchar *codec_name;
2190 
2191   g_object_class_install_property (gobject_class, PROP_DECODER_ADAPTER_LUID,
2192       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
2193           "DXGI Adapter LUID (Locally Unique Identifier) of created device",
2194           G_MININT64, G_MAXINT64, cdata->adapter_luid,
2195           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2196 
2197   g_object_class_install_property (gobject_class, PROP_DECODER_DEVICE_ID,
2198       g_param_spec_uint ("device-id", "Device Id",
2199           "DXGI Device ID", 0, G_MAXUINT32, 0,
2200           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2201 
2202   g_object_class_install_property (gobject_class, PROP_DECODER_VENDOR_ID,
2203       g_param_spec_uint ("vendor-id", "Vendor Id",
2204           "DXGI Vendor ID", 0, G_MAXUINT32, 0,
2205           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2206 
2207   codec_name = gst_dxva_codec_to_string (cdata->codec);
2208   long_name = "Direct3D11/DXVA " + std::string (codec_name) + " " +
2209       std::string (data->description) + " Decoder";
2210   description = "Direct3D11/DXVA based " + std::string (codec_name) +
2211       " video decoder";
2212 
2213   gst_element_class_set_metadata (klass, long_name.c_str (),
2214       "Codec/Decoder/Video/Hardware", description.c_str (), author);
2215 
2216   gst_element_class_add_pad_template (klass,
2217       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
2218           data->sink_caps));
2219   gst_element_class_add_pad_template (klass,
2220       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
2221           data->src_caps));
2222 
2223   gst_d3d11_decoder_class_data_free (data);
2224 }
2225 
2226 void
gst_d3d11_decoder_proxy_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec,GstD3D11DecoderSubClassData * subclass_data)2227 gst_d3d11_decoder_proxy_get_property (GObject * object, guint prop_id,
2228     GValue * value, GParamSpec * pspec,
2229     GstD3D11DecoderSubClassData * subclass_data)
2230 {
2231   switch (prop_id) {
2232     case PROP_DECODER_ADAPTER_LUID:
2233       g_value_set_int64 (value, subclass_data->adapter_luid);
2234       break;
2235     case PROP_DECODER_DEVICE_ID:
2236       g_value_set_uint (value, subclass_data->device_id);
2237       break;
2238     case PROP_DECODER_VENDOR_ID:
2239       g_value_set_uint (value, subclass_data->vendor_id);
2240       break;
2241     default:
2242       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2243       break;
2244   }
2245 }
2246 
2247 gboolean
gst_d3d11_decoder_proxy_open(GstVideoDecoder * videodec,GstD3D11DecoderSubClassData * subclass_data,GstD3D11Device ** device,GstD3D11Decoder ** decoder)2248 gst_d3d11_decoder_proxy_open (GstVideoDecoder * videodec,
2249     GstD3D11DecoderSubClassData * subclass_data, GstD3D11Device ** device,
2250     GstD3D11Decoder ** decoder)
2251 {
2252   GstElement *elem = GST_ELEMENT (videodec);
2253 
2254   if (!gst_d3d11_ensure_element_data_for_adapter_luid (elem,
2255           subclass_data->adapter_luid, device)) {
2256     GST_ERROR_OBJECT (elem, "Cannot create d3d11device");
2257     return FALSE;
2258   }
2259 
2260   *decoder = gst_d3d11_decoder_new (*device, subclass_data->codec);
2261 
2262   if (*decoder == nullptr) {
2263     GST_ERROR_OBJECT (elem, "Cannot create d3d11 decoder");
2264     gst_clear_object (device);
2265     return FALSE;
2266   }
2267 
2268   return TRUE;
2269 }
2270