23329a0f4ff23c70ec3259efefce98d82b51f656
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / sys / d3d11 / gstd3d11decoder.cpp
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 <timeapi.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
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
220 gst_d3d11_decoder_init (GstD3D11Decoder * self)
221 {
222   g_mutex_init (&self->internal_pool_lock);
223 }
224
225 static void
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
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
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
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
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
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
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 *
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
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
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
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_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
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 *
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
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
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   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   if (!gst_d3d11_device_get_format (decoder->device,
727           GST_VIDEO_INFO_FORMAT (info), &d3d11_format) ||
728       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
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
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
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
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
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
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
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
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
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 *
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 *
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_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 gboolean
1397 gst_d3d11_decoder_process_output (GstD3D11Decoder * decoder,
1398     GstVideoDecoder * videodec, gint display_width, gint display_height,
1399     GstBuffer * decoder_buffer, GstBuffer ** output)
1400 {
1401   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1402   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1403   g_return_val_if_fail (GST_IS_BUFFER (decoder_buffer), FALSE);
1404   g_return_val_if_fail (output != NULL, FALSE);
1405
1406   if (display_width != GST_VIDEO_INFO_WIDTH (&decoder->output_info) ||
1407       display_height != GST_VIDEO_INFO_HEIGHT (&decoder->output_info)) {
1408     GST_INFO_OBJECT (videodec, "Frame size changed, do renegotiate");
1409
1410     gst_video_info_set_format (&decoder->output_info,
1411         GST_VIDEO_INFO_FORMAT (&decoder->info), display_width, display_height);
1412     GST_VIDEO_INFO_INTERLACE_MODE (&decoder->output_info) =
1413         GST_VIDEO_INFO_INTERLACE_MODE (&decoder->info);
1414
1415     if (!gst_video_decoder_negotiate (videodec)) {
1416       GST_ERROR_OBJECT (videodec, "Failed to re-negotiate with new frame size");
1417       return FALSE;
1418     }
1419   }
1420
1421   if (gst_d3d11_decoder_can_direct_render (decoder, videodec, decoder_buffer,
1422           display_width, display_height)) {
1423     GstMemory *mem;
1424
1425     mem = gst_buffer_peek_memory (decoder_buffer, 0);
1426     GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
1427
1428     *output = gst_buffer_ref (decoder_buffer);
1429
1430     return TRUE;
1431   }
1432
1433   *output = gst_video_decoder_allocate_output_buffer (videodec);
1434   if (*output == NULL) {
1435     GST_ERROR_OBJECT (videodec, "Couldn't allocate output buffer");
1436
1437     return FALSE;
1438   }
1439
1440   return gst_d3d11_buffer_copy_into (*output,
1441       decoder_buffer, &decoder->output_info);
1442 }
1443
1444 gboolean
1445 gst_d3d11_decoder_negotiate (GstD3D11Decoder * decoder,
1446     GstVideoDecoder * videodec)
1447 {
1448   GstVideoInfo *info;
1449   GstCaps *peer_caps;
1450   GstVideoCodecState *state = NULL;
1451   gboolean alternate_interlaced;
1452   gboolean alternate_supported = FALSE;
1453   gboolean d3d11_supported = FALSE;
1454   GstVideoCodecState *input_state;
1455
1456   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1457   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1458
1459   info = &decoder->output_info;
1460   input_state = decoder->input_state;
1461
1462   alternate_interlaced =
1463       (GST_VIDEO_INFO_INTERLACE_MODE (info) ==
1464       GST_VIDEO_INTERLACE_MODE_ALTERNATE);
1465
1466   peer_caps = gst_pad_get_allowed_caps (GST_VIDEO_DECODER_SRC_PAD (videodec));
1467   GST_DEBUG_OBJECT (videodec, "Allowed caps %" GST_PTR_FORMAT, peer_caps);
1468
1469   if (!peer_caps || gst_caps_is_any (peer_caps)) {
1470     GST_DEBUG_OBJECT (videodec,
1471         "cannot determine output format, use system memory");
1472   } else {
1473     GstCapsFeatures *features;
1474     guint size = gst_caps_get_size (peer_caps);
1475     guint i;
1476
1477     for (i = 0; i < size; i++) {
1478       features = gst_caps_get_features (peer_caps, i);
1479
1480       if (!features)
1481         continue;
1482
1483       if (gst_caps_features_contains (features,
1484               GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
1485         d3d11_supported = TRUE;
1486       }
1487
1488       /* FIXME: software deinterlace element will not return interlaced caps
1489        * feature... We should fix it */
1490       if (gst_caps_features_contains (features,
1491               GST_CAPS_FEATURE_FORMAT_INTERLACED)) {
1492         alternate_supported = TRUE;
1493       }
1494     }
1495   }
1496   gst_clear_caps (&peer_caps);
1497
1498   GST_DEBUG_OBJECT (videodec,
1499       "Downstream feature support, D3D11 memory: %d, interlaced format %d",
1500       d3d11_supported, alternate_supported);
1501
1502   if (alternate_interlaced) {
1503     /* FIXME: D3D11 cannot support alternating interlaced stream yet */
1504     GST_FIXME_OBJECT (videodec,
1505         "Implement alternating interlaced stream for D3D11");
1506
1507     if (alternate_supported) {
1508       gint height = GST_VIDEO_INFO_HEIGHT (info);
1509
1510       /* Set caps resolution with display size, that's how we designed
1511        * for alternating interlaced stream */
1512       height = 2 * height;
1513       state = gst_video_decoder_set_interlaced_output_state (videodec,
1514           GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1515           GST_VIDEO_INFO_WIDTH (info), height, input_state);
1516     } else {
1517       GST_WARNING_OBJECT (videodec,
1518           "Downstream doesn't support alternating interlaced stream");
1519
1520       state = gst_video_decoder_set_output_state (videodec,
1521           GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
1522           GST_VIDEO_INFO_HEIGHT (info), input_state);
1523
1524       /* XXX: adjust PAR, this would produce output similar to that of
1525        * "line doubling" (so called bob deinterlacing) processing.
1526        * apart from missing anchor line (top-field or bottom-field) information.
1527        * Potentially flickering could happen. So this might not be correct.
1528        * But it would be better than negotiation error of half-height squeezed
1529        * image */
1530       state->info.par_d *= 2;
1531       state->info.fps_n *= 2;
1532     }
1533   } else {
1534     state = gst_video_decoder_set_interlaced_output_state (videodec,
1535         GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info),
1536         GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), input_state);
1537   }
1538
1539   if (!state) {
1540     GST_ERROR_OBJECT (decoder, "Couldn't set output state");
1541     return FALSE;
1542   }
1543
1544   state->caps = gst_video_info_to_caps (&state->info);
1545
1546   g_clear_pointer (&decoder->output_state, gst_video_codec_state_unref);
1547   decoder->output_state = state;
1548
1549   if (d3d11_supported) {
1550     gst_caps_set_features (state->caps, 0,
1551         gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, NULL));
1552   }
1553
1554   decoder->downstream_supports_d3d11 = d3d11_supported;
1555
1556   return gst_d3d11_decoder_open (decoder);
1557 }
1558
1559 gboolean
1560 gst_d3d11_decoder_decide_allocation (GstD3D11Decoder * decoder,
1561     GstVideoDecoder * videodec, GstQuery * query)
1562 {
1563   GstCaps *outcaps;
1564   GstBufferPool *pool = NULL;
1565   guint n, size, min = 0, max = 0;
1566   GstVideoInfo vinfo = { 0, };
1567   GstStructure *config;
1568   GstD3D11AllocationParams *d3d11_params;
1569   gboolean use_d3d11_pool;
1570   gboolean has_videometa;
1571
1572   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1573   g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
1574   g_return_val_if_fail (query != NULL, FALSE);
1575
1576   if (!decoder->opened) {
1577     GST_ERROR_OBJECT (videodec, "Should open decoder first");
1578     return FALSE;
1579   }
1580
1581   gst_query_parse_allocation (query, &outcaps, NULL);
1582
1583   if (!outcaps) {
1584     GST_DEBUG_OBJECT (decoder, "No output caps");
1585     return FALSE;
1586   }
1587
1588   has_videometa = gst_query_find_allocation_meta (query,
1589       GST_VIDEO_META_API_TYPE, nullptr);
1590
1591   use_d3d11_pool = decoder->downstream_supports_d3d11;
1592
1593   gst_video_info_from_caps (&vinfo, outcaps);
1594   n = gst_query_get_n_allocation_pools (query);
1595   if (n > 0)
1596     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1597
1598   /* create our own pool */
1599   if (pool) {
1600     if (use_d3d11_pool) {
1601       if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
1602         GST_DEBUG_OBJECT (videodec,
1603             "Downstream pool is not d3d11, will create new one");
1604         gst_clear_object (&pool);
1605       } else {
1606         GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
1607         if (dpool->device != decoder->device) {
1608           GST_DEBUG_OBJECT (videodec, "Different device, will create new one");
1609           gst_clear_object (&pool);
1610         }
1611       }
1612     } else if (has_videometa) {
1613       /* We will use d3d11 staging buffer pool */
1614       gst_clear_object (&pool);
1615     }
1616   }
1617
1618   if (!pool) {
1619     if (use_d3d11_pool)
1620       pool = gst_d3d11_buffer_pool_new (decoder->device);
1621     else if (has_videometa)
1622       pool = gst_d3d11_staging_buffer_pool_new (decoder->device);
1623     else
1624       pool = gst_video_buffer_pool_new ();
1625
1626     size = (guint) vinfo.size;
1627   }
1628
1629   config = gst_buffer_pool_get_config (pool);
1630   gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
1631   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1632
1633   if (use_d3d11_pool) {
1634     GstVideoAlignment align;
1635     gint width, height;
1636
1637     gst_video_alignment_reset (&align);
1638
1639     d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
1640     if (!d3d11_params)
1641       d3d11_params = gst_d3d11_allocation_params_new (decoder->device, &vinfo,
1642           (GstD3D11AllocationFlags) 0, 0);
1643
1644     width = GST_VIDEO_INFO_WIDTH (&vinfo);
1645     height = GST_VIDEO_INFO_HEIGHT (&vinfo);
1646
1647     /* need alignment to copy decoder output texture to downstream texture */
1648     align.padding_right = GST_ROUND_UP_16 (width) - width;
1649     align.padding_bottom = GST_ROUND_UP_16 (height) - height;
1650     if (!gst_d3d11_allocation_params_alignment (d3d11_params, &align)) {
1651       GST_ERROR_OBJECT (videodec, "Cannot set alignment");
1652       return FALSE;
1653     }
1654
1655     /* Needs render target bind flag so that it can be used for
1656      * output of shader pipeline if internal resizing is required.
1657      * Also, downstream can keep using video processor even if we copy
1658      * some decoded textures into downstream buffer */
1659     d3d11_params->desc[0].BindFlags |= D3D11_BIND_RENDER_TARGET;
1660
1661     gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
1662     gst_d3d11_allocation_params_free (d3d11_params);
1663
1664     /* Store min buffer size. We need to take account of the amount of buffers
1665      * which might be held by downstream in case of zero-copy playback */
1666     if (!decoder->internal_pool) {
1667       if (n > 0) {
1668         GST_DEBUG_OBJECT (videodec, "Downstream proposed pool");
1669         decoder->wait_on_pool_full = TRUE;
1670         /* XXX: hardcoded bound 16, to avoid too large pool size */
1671         decoder->downstream_min_buffers = MIN (min, 16);
1672       } else {
1673         GST_DEBUG_OBJECT (videodec, "Downstream didn't propose pool");
1674         decoder->wait_on_pool_full = FALSE;
1675         /* don't know how many buffers would be queued by downstream */
1676         decoder->downstream_min_buffers = 4;
1677       }
1678     } else {
1679       /* We configured our DPB pool already, let's check if our margin can
1680        * cover min size */
1681       decoder->wait_on_pool_full = FALSE;
1682
1683       if (n > 0) {
1684         if (decoder->downstream_min_buffers >= min)
1685           decoder->wait_on_pool_full = TRUE;
1686
1687         GST_DEBUG_OBJECT (videodec,
1688             "Pre-allocated margin %d can%s cover downstream min size %d",
1689             decoder->downstream_min_buffers,
1690             decoder->wait_on_pool_full ? "" : "not", min);
1691       } else {
1692         GST_DEBUG_OBJECT (videodec, "Downstream min size is unknown");
1693       }
1694     }
1695
1696     GST_DEBUG_OBJECT (videodec, "Downstream min buffres: %d", min);
1697   }
1698
1699   gst_buffer_pool_set_config (pool, config);
1700   /* d3d11 buffer pool will update buffer size based on allocated texture,
1701    * get size from config again */
1702   config = gst_buffer_pool_get_config (pool);
1703   gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
1704   gst_structure_free (config);
1705
1706   if (n > 0)
1707     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1708   else
1709     gst_query_add_allocation_pool (query, pool, size, min, max);
1710   gst_object_unref (pool);
1711
1712   return TRUE;
1713 }
1714
1715 gboolean
1716 gst_d3d11_decoder_set_flushing (GstD3D11Decoder * decoder,
1717     GstVideoDecoder * videodec, gboolean flushing)
1718 {
1719   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1720
1721   g_mutex_lock (&decoder->internal_pool_lock);
1722   if (decoder->internal_pool)
1723     gst_buffer_pool_set_flushing (decoder->internal_pool, flushing);
1724   g_mutex_unlock (&decoder->internal_pool_lock);
1725
1726   return TRUE;
1727 }
1728
1729 static gboolean
1730 gst_d3d11_decoder_can_direct_render (GstD3D11Decoder * decoder,
1731     GstVideoDecoder * videodec, GstBuffer * view_buffer,
1732     gint display_width, gint display_height)
1733 {
1734   GstMemory *mem;
1735   GstD3D11PoolAllocator *alloc;
1736   guint max_size = 0, outstanding_size = 0;
1737
1738   /* We don't support direct render for reverse playback */
1739   if (videodec->input_segment.rate < 0)
1740     return FALSE;
1741
1742   if (!decoder->can_direct_rendering || !decoder->downstream_supports_d3d11)
1743     return FALSE;
1744
1745   /* different size, need copy */
1746   /* TODO: crop meta */
1747   if (display_width != GST_VIDEO_INFO_WIDTH (&decoder->info) ||
1748       display_height != GST_VIDEO_INFO_HEIGHT (&decoder->info))
1749     return FALSE;
1750
1751   /* we can do direct render in this case, since there is no DPB pool size
1752    * limit */
1753   if (decoder->use_array_of_texture)
1754     return TRUE;
1755
1756   /* Let's believe downstream info */
1757   if (decoder->wait_on_pool_full)
1758     return TRUE;
1759
1760   /* Check if we are about to full */
1761   mem = gst_buffer_peek_memory (view_buffer, 0);
1762
1763   /* something went wrong */
1764   if (!gst_is_d3d11_memory (mem)) {
1765     GST_ERROR_OBJECT (decoder, "Not a D3D11 memory");
1766     return FALSE;
1767   }
1768
1769   alloc = GST_D3D11_POOL_ALLOCATOR (mem->allocator);
1770   if (!gst_d3d11_pool_allocator_get_pool_size (alloc, &max_size,
1771           &outstanding_size)) {
1772     GST_ERROR_OBJECT (decoder, "Couldn't query pool size");
1773     return FALSE;
1774   }
1775
1776   /* 2 buffer margin */
1777   if (max_size <= outstanding_size + 1) {
1778     GST_DEBUG_OBJECT (decoder, "memory pool is about to full (%u/%u)",
1779         outstanding_size, max_size);
1780     return FALSE;
1781   }
1782
1783   GST_LOG_OBJECT (decoder, "Can do direct rendering");
1784
1785   return TRUE;
1786 }
1787
1788 /* Keep sync with chromium and keep in sorted order.
1789  * See supported_profile_helpers.cc in chromium */
1790 static const guint legacy_amd_list[] = {
1791   0x130f, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707,
1792   0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x6720, 0x6721,
1793   0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, 0x6738,
1794   0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746,
1795   0x6747, 0x6748, 0x6749, 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b,
1796   0x675d, 0x675f, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766,
1797   0x6767, 0x6768, 0x6770, 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6798,
1798   0x67b1, 0x6821, 0x683d, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, 0x6850,
1799   0x6858, 0x6859, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, 0x6898,
1800   0x6899, 0x689b, 0x689c, 0x689d, 0x689e, 0x68a0, 0x68a1, 0x68a8, 0x68a9,
1801   0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x68c0, 0x68c1, 0x68c7,
1802   0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68e0, 0x68e1, 0x68e4,
1803   0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, 0x68fe,
1804   0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x9440,
1805   0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e,
1806   0x9450, 0x9452, 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a,
1807   0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, 0x9489, 0x948a, 0x948f,
1808   0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x94a0, 0x94a1,
1809   0x94a3, 0x94b1, 0x94b3, 0x94b4, 0x94b5, 0x94b9, 0x94c0, 0x94c1, 0x94c3,
1810   0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd,
1811   0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, 0x9508, 0x9509, 0x950f,
1812   0x9511, 0x9515, 0x9517, 0x9519, 0x9540, 0x9541, 0x9542, 0x954e, 0x954f,
1813   0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x9580, 0x9581, 0x9583, 0x9586,
1814   0x9587, 0x9588, 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f,
1815   0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, 0x959b,
1816   0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c9, 0x95cc, 0x95cd,
1817   0x95ce, 0x95cf, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616,
1818   0x9640, 0x9641, 0x9642, 0x9643, 0x9644, 0x9645, 0x9647, 0x9648, 0x9649,
1819   0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9710, 0x9711, 0x9712, 0x9713,
1820   0x9714, 0x9715, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808,
1821   0x9809, 0x980a, 0x9830, 0x983d, 0x9850, 0x9851, 0x9874, 0x9900, 0x9901,
1822   0x9903, 0x9904, 0x9905, 0x9906, 0x9907, 0x9908, 0x9909, 0x990a, 0x990b,
1823   0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, 0x9919,
1824   0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
1825   0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4
1826 };
1827
1828 static const guint legacy_intel_list[] = {
1829   0x102, 0x106, 0x116, 0x126, 0x152, 0x156, 0x166,
1830   0x402, 0x406, 0x416, 0x41e, 0xa06, 0xa16, 0xf31,
1831 };
1832
1833 static gint
1834 binary_search_compare (const guint * a, const guint * b)
1835 {
1836   return *a - *b;
1837 }
1838
1839 /* Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and some second
1840  * generation Intel GPU drivers crash if we create a video device with a
1841  * resolution higher then 1920 x 1088. This function checks if the GPU is in
1842  * this list and if yes returns true. */
1843 gboolean
1844 gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device)
1845 {
1846   const guint amd_id[] = { 0x1002, 0x1022 };
1847   const guint intel_id = 0x8086;
1848   guint device_id = 0;
1849   guint vendor_id = 0;
1850   guint *match = NULL;
1851
1852   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
1853
1854   g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id, NULL);
1855
1856   if (vendor_id == amd_id[0] || vendor_id == amd_id[1]) {
1857     match =
1858         (guint *) gst_util_array_binary_search ((gpointer) legacy_amd_list,
1859         G_N_ELEMENTS (legacy_amd_list), sizeof (guint),
1860         (GCompareDataFunc) binary_search_compare,
1861         GST_SEARCH_MODE_EXACT, &device_id, NULL);
1862   } else if (vendor_id == intel_id) {
1863     match =
1864         (guint *) gst_util_array_binary_search ((gpointer) legacy_intel_list,
1865         G_N_ELEMENTS (legacy_intel_list), sizeof (guint),
1866         (GCompareDataFunc) binary_search_compare,
1867         GST_SEARCH_MODE_EXACT, &device_id, NULL);
1868   }
1869
1870   if (match) {
1871     GST_DEBUG_OBJECT (device, "it's legacy device");
1872     return TRUE;
1873   }
1874
1875   return FALSE;
1876 }
1877
1878 gboolean
1879 gst_d3d11_decoder_supports_format (GstD3D11Device * device,
1880     const GUID * decoder_profile, DXGI_FORMAT format)
1881 {
1882   HRESULT hr;
1883   BOOL can_support = FALSE;
1884   ID3D11VideoDevice *video_device;
1885
1886   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
1887   g_return_val_if_fail (decoder_profile != NULL, FALSE);
1888   g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
1889
1890   video_device = gst_d3d11_device_get_video_device_handle (device);
1891   if (!video_device)
1892     return FALSE;
1893
1894   hr = video_device->CheckVideoDecoderFormat (decoder_profile, format,
1895       &can_support);
1896   if (!gst_d3d11_result (hr, device) || !can_support) {
1897     GST_DEBUG_OBJECT (device,
1898         "VideoDevice could not support dxgi format %d, hr: 0x%x",
1899         format, (guint) hr);
1900
1901     return FALSE;
1902   }
1903
1904   return TRUE;
1905 }
1906
1907 /* Don't call this method with legacy device */
1908 gboolean
1909 gst_d3d11_decoder_supports_resolution (GstD3D11Device * device,
1910     const GUID * decoder_profile, DXGI_FORMAT format, guint width, guint height)
1911 {
1912   D3D11_VIDEO_DECODER_DESC desc;
1913   HRESULT hr;
1914   UINT config_count;
1915   ID3D11VideoDevice *video_device;
1916
1917   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
1918   g_return_val_if_fail (decoder_profile != NULL, FALSE);
1919   g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
1920
1921   video_device = gst_d3d11_device_get_video_device_handle (device);
1922   if (!video_device)
1923     return FALSE;
1924
1925   desc.SampleWidth = width;
1926   desc.SampleHeight = height;
1927   desc.OutputFormat = format;
1928   desc.Guid = *decoder_profile;
1929
1930   hr = video_device->GetVideoDecoderConfigCount (&desc, &config_count);
1931   if (!gst_d3d11_result (hr, device) || config_count == 0) {
1932     GST_DEBUG_OBJECT (device, "Could not get decoder config count, hr: 0x%x",
1933         (guint) hr);
1934     return FALSE;
1935   }
1936
1937   return TRUE;
1938 }
1939
1940 enum
1941 {
1942   PROP_DECODER_ADAPTER_LUID = 1,
1943   PROP_DECODER_DEVICE_ID,
1944   PROP_DECODER_VENDOR_ID,
1945 };
1946
1947 struct _GstD3D11DecoderClassData
1948 {
1949   GstD3D11DecoderSubClassData subclass_data;
1950   GstCaps *sink_caps;
1951   GstCaps *src_caps;
1952   gchar *description;
1953 };
1954
1955 /**
1956  * gst_d3d11_decoder_class_data_new:
1957  * @device: (transfer none): a #GstD3D11Device
1958  * @sink_caps: (transfer full): a #GstCaps
1959  * @src_caps: (transfer full): a #GstCaps
1960  *
1961  * Create new #GstD3D11DecoderClassData
1962  *
1963  * Returns: (transfer full): the new #GstD3D11DecoderClassData
1964  */
1965 GstD3D11DecoderClassData *
1966 gst_d3d11_decoder_class_data_new (GstD3D11Device * device, GstDXVACodec codec,
1967     GstCaps * sink_caps, GstCaps * src_caps)
1968 {
1969   GstD3D11DecoderClassData *ret;
1970
1971   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1972   g_return_val_if_fail (sink_caps != NULL, NULL);
1973   g_return_val_if_fail (src_caps != NULL, NULL);
1974
1975   ret = g_new0 (GstD3D11DecoderClassData, 1);
1976
1977   /* class data will be leaked if the element never gets instantiated */
1978   GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1979   GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1980
1981   ret->subclass_data.codec = codec;
1982   g_object_get (device, "adapter-luid", &ret->subclass_data.adapter_luid,
1983       "device-id", &ret->subclass_data.device_id,
1984       "vendor-id", &ret->subclass_data.vendor_id,
1985       "description", &ret->description, nullptr);
1986   ret->sink_caps = sink_caps;
1987   ret->src_caps = src_caps;
1988
1989   return ret;
1990 }
1991
1992 void
1993 gst_d3d11_decoder_class_data_fill_subclass_data (GstD3D11DecoderClassData *
1994     data, GstD3D11DecoderSubClassData * subclass_data)
1995 {
1996   g_return_if_fail (data != nullptr);
1997   g_return_if_fail (subclass_data != nullptr);
1998
1999   *subclass_data = data->subclass_data;
2000 }
2001
2002 static void
2003 gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data)
2004 {
2005   if (!data)
2006     return;
2007
2008   gst_clear_caps (&data->sink_caps);
2009   gst_clear_caps (&data->src_caps);
2010   g_free (data->description);
2011   g_free (data);
2012 }
2013
2014 void
2015 gst_d3d11_decoder_proxy_class_init (GstElementClass * klass,
2016     GstD3D11DecoderClassData * data, const gchar * author)
2017 {
2018   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2019   GstD3D11DecoderSubClassData *cdata = &data->subclass_data;
2020   std::string long_name;
2021   std::string description;
2022   const gchar *codec_name;
2023
2024   g_object_class_install_property (gobject_class, PROP_DECODER_ADAPTER_LUID,
2025       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
2026           "DXGI Adapter LUID (Locally Unique Identifier) of created device",
2027           G_MININT64, G_MAXINT64, cdata->adapter_luid,
2028           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2029
2030   g_object_class_install_property (gobject_class, PROP_DECODER_DEVICE_ID,
2031       g_param_spec_uint ("device-id", "Device Id",
2032           "DXGI Device ID", 0, G_MAXUINT32, 0,
2033           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2034
2035   g_object_class_install_property (gobject_class, PROP_DECODER_VENDOR_ID,
2036       g_param_spec_uint ("vendor-id", "Vendor Id",
2037           "DXGI Vendor ID", 0, G_MAXUINT32, 0,
2038           (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
2039
2040   codec_name = gst_dxva_codec_to_string (cdata->codec);
2041   long_name = "Direct3D11/DXVA " + std::string (codec_name) + " " +
2042       std::string (data->description) + " Decoder";
2043   description = "Direct3D11/DXVA based " + std::string (codec_name) +
2044       " video decoder";
2045
2046   gst_element_class_set_metadata (klass, long_name.c_str (),
2047       "Codec/Decoder/Video/Hardware", description.c_str (), author);
2048
2049   gst_element_class_add_pad_template (klass,
2050       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
2051           data->sink_caps));
2052   gst_element_class_add_pad_template (klass,
2053       gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
2054           data->src_caps));
2055
2056   gst_d3d11_decoder_class_data_free (data);
2057 }
2058
2059 void
2060 gst_d3d11_decoder_proxy_get_property (GObject * object, guint prop_id,
2061     GValue * value, GParamSpec * pspec,
2062     GstD3D11DecoderSubClassData * subclass_data)
2063 {
2064   switch (prop_id) {
2065     case PROP_DECODER_ADAPTER_LUID:
2066       g_value_set_int64 (value, subclass_data->adapter_luid);
2067       break;
2068     case PROP_DECODER_DEVICE_ID:
2069       g_value_set_uint (value, subclass_data->device_id);
2070       break;
2071     case PROP_DECODER_VENDOR_ID:
2072       g_value_set_uint (value, subclass_data->vendor_id);
2073       break;
2074     default:
2075       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2076       break;
2077   }
2078 }
2079
2080 gboolean
2081 gst_d3d11_decoder_proxy_open (GstVideoDecoder * videodec,
2082     GstD3D11DecoderSubClassData * subclass_data, GstD3D11Device ** device,
2083     GstD3D11Decoder ** decoder)
2084 {
2085   GstElement *elem = GST_ELEMENT (videodec);
2086
2087   if (!gst_d3d11_ensure_element_data_for_adapter_luid (elem,
2088           subclass_data->adapter_luid, device)) {
2089     GST_ERROR_OBJECT (elem, "Cannot create d3d11device");
2090     return FALSE;
2091   }
2092
2093   *decoder = gst_d3d11_decoder_new (*device, subclass_data->codec);
2094
2095   if (*decoder == nullptr) {
2096     GST_ERROR_OBJECT (elem, "Cannot create d3d11 decoder");
2097     gst_clear_object (device);
2098     return FALSE;
2099   }
2100
2101   return TRUE;
2102 }