f72b4cba2ae6174993050811a02c76772c82d15f
[platform/upstream/gstreamer.git] / sys / d3d11 / gstd3d11decoder.c
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 "gstd3d11memory.h"
56 #include "gstd3d11bufferpool.h"
57 #include "gstd3d11device.h"
58 #include <string.h>
59
60 GST_DEBUG_CATEGORY (d3d11_decoder_debug);
61 #define GST_CAT_DEFAULT d3d11_decoder_debug
62
63 enum
64 {
65   PROP_0,
66   PROP_DEVICE,
67 };
68
69 struct _GstD3D11DecoderPrivate
70 {
71   GstD3D11Device *device;
72
73   ID3D11VideoDevice *video_device;
74   ID3D11VideoContext *video_context;
75
76   ID3D11VideoDecoder *decoder;
77
78   GstBufferPool *internal_pool;
79
80   /* for staging */
81   ID3D11Texture2D *staging;
82   D3D11_TEXTURE2D_DESC staging_desc;
83   D3D11_BOX staging_box;
84
85   GUID decoder_profile;
86 };
87
88 #define OUTPUT_VIEW_QUARK _decoder_output_view_get()
89 static GQuark
90 _decoder_output_view_get (void)
91 {
92   static volatile gsize g_quark = 0;
93
94   if (g_once_init_enter (&g_quark)) {
95     gsize quark =
96         (gsize) g_quark_from_static_string ("GstD3D11DecoderOutputView");
97     g_once_init_leave (&g_quark, quark);
98   }
99   return (GQuark) g_quark;
100 }
101
102 static void gst_d3d11_decoder_constructed (GObject * object);
103 static void gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
104     const GValue * value, GParamSpec * pspec);
105 static void gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
106     GValue * value, GParamSpec * pspec);
107 static void gst_d3d11_decoder_dispose (GObject * obj);
108
109 #define parent_class gst_d3d11_decoder_parent_class
110 G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Decoder,
111     gst_d3d11_decoder, GST_TYPE_OBJECT);
112
113 static void
114 gst_d3d11_decoder_class_init (GstD3D11DecoderClass * klass)
115 {
116   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
117
118   gobject_class->constructed = gst_d3d11_decoder_constructed;
119   gobject_class->set_property = gst_d3d11_decoder_set_property;
120   gobject_class->get_property = gst_d3d11_decoder_get_property;
121   gobject_class->dispose = gst_d3d11_decoder_dispose;
122
123   g_object_class_install_property (gobject_class, PROP_DEVICE,
124       g_param_spec_object ("device", "Device",
125           "D3D11 Devicd to use", GST_TYPE_D3D11_DEVICE,
126           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
127
128   GST_DEBUG_CATEGORY_INIT (d3d11_decoder_debug,
129       "d3d11decoder", 0, "Direct3D11 Base Video Decoder object");
130 }
131
132 static void
133 gst_d3d11_decoder_init (GstD3D11Decoder * self)
134 {
135   self->priv = gst_d3d11_decoder_get_instance_private (self);
136 }
137
138 static void
139 gst_d3d11_decoder_constructed (GObject * object)
140 {
141   GstD3D11Decoder *self = GST_D3D11_DECODER (object);
142   GstD3D11DecoderPrivate *priv = self->priv;
143   HRESULT hr;
144   ID3D11Device *device_handle;
145   ID3D11DeviceContext *device_context_handle;
146
147   if (!priv->device) {
148     GST_ERROR_OBJECT (self, "No D3D11Device available");
149     return;
150   }
151
152   device_handle = gst_d3d11_device_get_device_handle (priv->device);
153   device_context_handle =
154       gst_d3d11_device_get_device_context_handle (priv->device);
155
156   hr = ID3D11Device_QueryInterface (device_handle, &IID_ID3D11VideoDevice,
157       (void **) &priv->video_device);
158
159   if (!gst_d3d11_result (hr, priv->device) || !priv->video_device) {
160     GST_WARNING_OBJECT (self, "Cannot create VideoDevice Object: 0x%x",
161         (guint) hr);
162     priv->video_device = NULL;
163
164     return;
165   }
166
167   hr = ID3D11DeviceContext_QueryInterface (device_context_handle,
168       &IID_ID3D11VideoContext, (void **) &priv->video_context);
169
170   if (!gst_d3d11_result (hr, priv->device) || !priv->video_context) {
171     GST_WARNING_OBJECT (self, "Cannot create VideoContext Object: 0x%x",
172         (guint) hr);
173     priv->video_context = NULL;
174
175     goto fail;
176   }
177
178   return;
179
180 fail:
181   if (priv->video_device) {
182     ID3D11VideoDevice_Release (priv->video_device);
183     priv->video_device = NULL;
184   }
185
186   if (priv->video_context) {
187     ID3D11VideoContext_Release (priv->video_context);
188     priv->video_context = NULL;
189   }
190
191   return;
192 }
193
194 static void
195 gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
196     const GValue * value, GParamSpec * pspec)
197 {
198   GstD3D11Decoder *self = GST_D3D11_DECODER (object);
199   GstD3D11DecoderPrivate *priv = self->priv;
200
201   switch (prop_id) {
202     case PROP_DEVICE:
203       priv->device = g_value_dup_object (value);
204       break;
205     default:
206       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
207       break;
208   }
209 }
210
211 static void
212 gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
213     GValue * value, GParamSpec * pspec)
214 {
215   GstD3D11Decoder *self = GST_D3D11_DECODER (object);
216   GstD3D11DecoderPrivate *priv = self->priv;
217
218   switch (prop_id) {
219     case PROP_DEVICE:
220       g_value_set_object (value, priv->device);
221       break;
222     default:
223       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
224       break;
225   }
226 }
227
228 static gboolean
229 gst_d3d11_decoder_close (GstD3D11Decoder * self)
230 {
231   GstD3D11DecoderPrivate *priv = self->priv;
232
233   gst_d3d11_decoder_reset (self);
234
235   if (priv->video_device) {
236     ID3D11VideoDevice_Release (priv->video_device);
237     priv->video_device = NULL;
238   }
239
240   if (priv->video_context) {
241     ID3D11VideoContext_Release (priv->video_context);
242     priv->video_context = NULL;
243   }
244
245   return TRUE;
246 }
247
248 static void
249 gst_d3d11_decoder_reset_unlocked (GstD3D11Decoder * decoder)
250 {
251   GstD3D11DecoderPrivate *priv;
252
253   priv = decoder->priv;
254   gst_clear_object (&priv->internal_pool);
255
256   if (priv->decoder) {
257     ID3D11VideoDecoder_Release (priv->decoder);
258     priv->decoder = NULL;
259   }
260
261   if (priv->staging) {
262     ID3D11Texture2D_Release (priv->staging);
263     priv->staging = NULL;
264   }
265
266   decoder->opened = FALSE;
267 }
268
269 void
270 gst_d3d11_decoder_reset (GstD3D11Decoder * decoder)
271 {
272   GstD3D11DecoderPrivate *priv;
273
274   g_return_if_fail (GST_IS_D3D11_DECODER (decoder));
275
276   priv = decoder->priv;
277   gst_d3d11_device_lock (priv->device);
278   gst_d3d11_decoder_reset_unlocked (decoder);
279   gst_d3d11_device_unlock (priv->device);
280 }
281
282 static void
283 gst_d3d11_decoder_dispose (GObject * obj)
284 {
285   GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
286   GstD3D11DecoderPrivate *priv = self->priv;
287
288   if (priv->device) {
289     gst_d3d11_decoder_close (self);
290     gst_object_unref (priv->device);
291     priv->device = NULL;
292   }
293
294   G_OBJECT_CLASS (parent_class)->dispose (obj);
295 }
296
297 GstD3D11Decoder *
298 gst_d3d11_decoder_new (GstD3D11Device * device)
299 {
300   GstD3D11Decoder *decoder;
301   GstD3D11DecoderPrivate *priv;
302
303   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
304
305   decoder = g_object_new (GST_TYPE_D3D11_DECODER, "device", device, NULL);
306   priv = decoder->priv;
307
308   if (!priv->video_device || !priv->video_context) {
309     gst_object_unref (decoder);
310     return NULL;
311   }
312
313   gst_object_ref_sink (decoder);
314
315   return decoder;
316 }
317
318 static void
319 gst_d3d11_decoder_output_view_free (GstD3D11DecoderOutputView * view)
320 {
321   GST_DEBUG_OBJECT (view->device, "Free view %p", view);
322
323   if (view->handle) {
324     gst_d3d11_device_lock (view->device);
325     ID3D11VideoDecoderOutputView_Release (view->handle);
326     gst_d3d11_device_unlock (view->device);
327   }
328
329   gst_clear_object (&view->device);
330   g_free (view);
331 }
332
333 static gboolean
334 gst_d3d11_decoder_ensure_output_view (GstD3D11Decoder * self,
335     GstBuffer * buffer)
336 {
337   GstD3D11DecoderPrivate *priv = self->priv;
338   D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = { 0, };
339   GstD3D11Memory *mem;
340   GstD3D11DecoderOutputView *view;
341   ID3D11VideoDecoderOutputView *view_handle;
342   HRESULT hr;
343
344   mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
345
346   view = (GstD3D11DecoderOutputView *)
347       gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
348
349   if (view)
350     return TRUE;
351
352   view_desc.DecodeProfile = priv->decoder_profile;
353   view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
354   view_desc.Texture2D.ArraySlice = mem->subresource_index;
355
356   GST_LOG_OBJECT (self,
357       "Create decoder output view with index %d", mem->subresource_index);
358
359   hr = ID3D11VideoDevice_CreateVideoDecoderOutputView (priv->video_device,
360       (ID3D11Resource *) mem->texture, &view_desc, &view_handle);
361   if (!gst_d3d11_result (hr, priv->device)) {
362     GST_ERROR_OBJECT (self,
363         "Could not create decoder output view, hr: 0x%x", (guint) hr);
364     return FALSE;
365   }
366
367   view = g_new0 (GstD3D11DecoderOutputView, 1);
368   view->device = gst_object_ref (priv->device);
369   view->handle = view_handle;
370   view->view_id = mem->subresource_index;
371
372   gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK,
373       view, (GDestroyNotify) gst_d3d11_decoder_output_view_free);
374
375   return TRUE;
376 }
377
378 /* Must be called from D3D11Device thread */
379 static gboolean
380 gst_d3d11_decoder_prepare_output_view_pool (GstD3D11Decoder * self,
381     GstVideoInfo * info, guint coded_width, guint coded_height,
382     guint pool_size, const GUID * decoder_profile)
383 {
384   GstD3D11DecoderPrivate *priv = self->priv;
385   GstD3D11AllocationParams *alloc_params = NULL;
386   GstBufferPool *pool = NULL;
387   GstStructure *config = NULL;
388   GstCaps *caps = NULL;
389   GstVideoAlignment align;
390
391   gst_clear_object (&priv->internal_pool);
392
393   alloc_params = gst_d3d11_allocation_params_new (priv->device, info,
394       GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY, D3D11_BIND_DECODER);
395
396   if (!alloc_params) {
397     GST_ERROR_OBJECT (self, "Failed to create allocation param");
398     goto error;
399   }
400
401   alloc_params->desc[0].ArraySize = pool_size;
402   gst_video_alignment_reset (&align);
403
404   align.padding_right = coded_width - GST_VIDEO_INFO_WIDTH (info);
405   align.padding_bottom = coded_height - GST_VIDEO_INFO_HEIGHT (info);
406   if (!gst_d3d11_allocation_params_alignment (alloc_params, &align)) {
407     GST_ERROR_OBJECT (self, "Cannot set alignment");
408     return FALSE;
409   }
410
411   pool = gst_d3d11_buffer_pool_new (priv->device);
412   if (!pool) {
413     GST_ERROR_OBJECT (self, "Failed to create buffer pool");
414     goto error;
415   }
416
417   /* Setup buffer pool */
418   config = gst_buffer_pool_get_config (pool);
419   caps = gst_video_info_to_caps (info);
420   if (!caps) {
421     GST_ERROR_OBJECT (self, "Couldn't convert video info to caps");
422     goto error;
423   }
424
425   gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (info),
426       0, pool_size);
427   gst_buffer_pool_config_set_d3d11_allocation_params (config, alloc_params);
428   gst_caps_unref (caps);
429   gst_d3d11_allocation_params_free (alloc_params);
430   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
431
432   if (!gst_buffer_pool_set_config (pool, config)) {
433     GST_ERROR_OBJECT (self, "Invalid pool config");
434     goto error;
435   }
436
437   if (!gst_buffer_pool_set_active (pool, TRUE)) {
438     GST_ERROR_OBJECT (self, "Couldn't activate pool");
439     goto error;
440   }
441
442   priv->internal_pool = pool;
443
444   return TRUE;
445
446 error:
447   if (alloc_params)
448     gst_d3d11_allocation_params_free (alloc_params);
449   if (pool)
450     gst_object_unref (pool);
451   if (caps)
452     gst_caps_unref (caps);
453
454   return FALSE;
455 }
456
457 gboolean
458 gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Decoder * decoder,
459     const GUID ** decoder_profiles, guint profile_size, GUID * selected_profile)
460 {
461   GstD3D11DecoderPrivate *priv;
462   GUID *guid_list = NULL;
463   const GUID *profile = NULL;
464   guint available_profile_count;
465   gint i, j;
466   HRESULT hr;
467
468   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
469   g_return_val_if_fail (decoder_profiles != NULL, FALSE);
470   g_return_val_if_fail (profile_size > 0, FALSE);
471   g_return_val_if_fail (selected_profile != NULL, FALSE);
472
473   priv = decoder->priv;
474
475   available_profile_count =
476       ID3D11VideoDevice_GetVideoDecoderProfileCount (priv->video_device);
477
478   if (available_profile_count == 0) {
479     GST_WARNING_OBJECT (decoder, "No available decoder profile");
480     return FALSE;
481   }
482
483   GST_DEBUG_OBJECT (decoder,
484       "Have %u available decoder profiles", available_profile_count);
485   guid_list = g_alloca (sizeof (GUID) * available_profile_count);
486
487   for (i = 0; i < available_profile_count; i++) {
488     hr = ID3D11VideoDevice_GetVideoDecoderProfile (priv->video_device,
489         i, &guid_list[i]);
490     if (!gst_d3d11_result (hr, priv->device)) {
491       GST_WARNING_OBJECT (decoder, "Failed to get %d th decoder profile", i);
492       return FALSE;
493     }
494   }
495
496 #ifndef GST_DISABLE_GST_DEBUG
497   GST_LOG_OBJECT (decoder, "Supported decoder GUID");
498   for (i = 0; i < available_profile_count; i++) {
499     const GUID *guid = &guid_list[i];
500
501     GST_LOG_OBJECT (decoder,
502         "\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
503         (guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
504         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
505         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
506   }
507
508   GST_LOG_OBJECT (decoder, "Requested decoder GUID");
509   for (i = 0; i < profile_size; i++) {
510     const GUID *guid = decoder_profiles[i];
511
512     GST_LOG_OBJECT (decoder,
513         "\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
514         (guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
515         guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
516         guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
517   }
518 #endif
519
520   for (i = 0; i < profile_size; i++) {
521     for (j = 0; j < available_profile_count; j++) {
522       if (IsEqualGUID (decoder_profiles[i], &guid_list[j])) {
523         profile = decoder_profiles[i];
524         break;
525       }
526     }
527   }
528
529   if (!profile) {
530     GST_WARNING_OBJECT (decoder, "No supported decoder profile");
531     return FALSE;
532   }
533
534   *selected_profile = *profile;
535
536   GST_DEBUG_OBJECT (decoder,
537       "Selected guid "
538       "{ %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
539       (guint) selected_profile->Data1, (guint) selected_profile->Data2,
540       (guint) selected_profile->Data3,
541       selected_profile->Data4[0], selected_profile->Data4[1],
542       selected_profile->Data4[2], selected_profile->Data4[3],
543       selected_profile->Data4[4], selected_profile->Data4[5],
544       selected_profile->Data4[6], selected_profile->Data4[7]);
545
546   return TRUE;
547 }
548
549 gboolean
550 gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
551     GstVideoInfo * info, guint coded_width, guint coded_height,
552     guint pool_size, const GUID ** decoder_profiles, guint profile_size)
553 {
554   GstD3D11DecoderPrivate *priv;
555   const GstD3D11Format *d3d11_format;
556   HRESULT hr;
557   BOOL can_support = FALSE;
558   guint config_count;
559   D3D11_VIDEO_DECODER_CONFIG *config_list;
560   D3D11_VIDEO_DECODER_CONFIG *best_config = NULL;
561   D3D11_VIDEO_DECODER_DESC decoder_desc = { 0, };
562   GUID selected_profile;
563   gint i;
564
565   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
566   g_return_val_if_fail (codec > GST_D3D11_CODEC_NONE, FALSE);
567   g_return_val_if_fail (codec < GST_D3D11_CODEC_LAST, FALSE);
568   g_return_val_if_fail (info != NULL, FALSE);
569   g_return_val_if_fail (coded_width >= GST_VIDEO_INFO_WIDTH (info), FALSE);
570   g_return_val_if_fail (coded_height >= GST_VIDEO_INFO_HEIGHT (info), FALSE);
571   g_return_val_if_fail (pool_size > 0, FALSE);
572   g_return_val_if_fail (decoder_profiles != NULL, FALSE);
573   g_return_val_if_fail (profile_size > 0, FALSE);
574
575   priv = decoder->priv;
576   decoder->opened = FALSE;
577
578   d3d11_format = gst_d3d11_device_format_from_gst (priv->device,
579       GST_VIDEO_INFO_FORMAT (info));
580   if (!d3d11_format || d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
581     GST_ERROR_OBJECT (decoder, "Could not determine dxgi format from %s",
582         gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
583     return FALSE;
584   }
585
586   gst_d3d11_device_lock (priv->device);
587   if (!gst_d3d11_decoder_get_supported_decoder_profile (decoder,
588           decoder_profiles, profile_size, &selected_profile)) {
589     goto error;
590   }
591
592   hr = ID3D11VideoDevice_CheckVideoDecoderFormat (priv->video_device,
593       &selected_profile, d3d11_format->dxgi_format, &can_support);
594   if (!gst_d3d11_result (hr, priv->device) || !can_support) {
595     GST_ERROR_OBJECT (decoder,
596         "VideoDevice could not support dxgi format %d, hr: 0x%x",
597         d3d11_format->dxgi_format, (guint) hr);
598     goto error;
599   }
600
601   gst_d3d11_decoder_reset_unlocked (decoder);
602
603   decoder_desc.SampleWidth = coded_width;
604   decoder_desc.SampleHeight = coded_height;
605   decoder_desc.OutputFormat = d3d11_format->dxgi_format;
606   decoder_desc.Guid = selected_profile;
607
608   hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device,
609       &decoder_desc, &config_count);
610   if (!gst_d3d11_result (hr, priv->device) || config_count == 0) {
611     GST_ERROR_OBJECT (decoder, "Could not get decoder config count, hr: 0x%x",
612         (guint) hr);
613     goto error;
614   }
615
616   GST_DEBUG_OBJECT (decoder, "Total %d config available", config_count);
617
618   config_list = g_alloca (sizeof (D3D11_VIDEO_DECODER_CONFIG) * config_count);
619
620   for (i = 0; i < config_count; i++) {
621     hr = ID3D11VideoDevice_GetVideoDecoderConfig (priv->video_device,
622         &decoder_desc, i, &config_list[i]);
623     if (!gst_d3d11_result (hr, priv->device)) {
624       GST_ERROR_OBJECT (decoder, "Could not get decoder %dth config, hr: 0x%x",
625           i, (guint) hr);
626       goto error;
627     }
628
629     /* FIXME: need support DXVA_Slice_H264_Long ?? */
630     /* this config uses DXVA_Slice_H264_Short */
631     if (codec == GST_D3D11_CODEC_H264 && config_list[i].ConfigBitstreamRaw == 2) {
632       best_config = &config_list[i];
633       break;
634     }
635
636     if ((codec == GST_D3D11_CODEC_VP9 || codec == GST_D3D11_CODEC_H265)
637         && config_list[i].ConfigBitstreamRaw == 1) {
638       best_config = &config_list[i];
639       break;
640     }
641   }
642
643   if (best_config == NULL) {
644     GST_ERROR_OBJECT (decoder, "Could not determine decoder config");
645     goto error;
646   }
647
648   if (!gst_d3d11_decoder_prepare_output_view_pool (decoder,
649           info, coded_width, coded_height, pool_size, &selected_profile)) {
650     GST_ERROR_OBJECT (decoder, "Couldn't prepare output view pool");
651     goto error;
652   }
653
654   hr = ID3D11VideoDevice_CreateVideoDecoder (priv->video_device,
655       &decoder_desc, best_config, &priv->decoder);
656   if (!gst_d3d11_result (hr, priv->device) || !priv->decoder) {
657     GST_ERROR_OBJECT (decoder,
658         "Could not create decoder object, hr: 0x%x", (guint) hr);
659     goto error;
660   }
661
662   GST_DEBUG_OBJECT (decoder, "Decoder object %p created", priv->decoder);
663
664   /* create stage texture to copy out */
665   memset (&priv->staging_desc, 0, sizeof (D3D11_TEXTURE2D_DESC));
666   priv->staging_desc.Width = GST_VIDEO_INFO_WIDTH (info);
667   priv->staging_desc.Height = GST_VIDEO_INFO_HEIGHT (info);
668   priv->staging_desc.MipLevels = 1;
669   priv->staging_desc.Format = d3d11_format->dxgi_format;
670   priv->staging_desc.SampleDesc.Count = 1;
671   priv->staging_desc.ArraySize = 1;
672   priv->staging_desc.Usage = D3D11_USAGE_STAGING;
673   priv->staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
674
675   priv->staging = gst_d3d11_device_create_texture (priv->device,
676       &priv->staging_desc, NULL);
677   if (!priv->staging) {
678     GST_ERROR_OBJECT (decoder, "Couldn't create staging texture");
679     goto error;
680   }
681
682   /* This D3D11_BOX structure is used to copy decoder view to staging texture,
683    * in case of system memory downstream.
684    * Since resolution of decoder view might be larger than this staging texture,
685    * this D3D11_BOX structure will guide the target area which need to be copied.
686    */
687   priv->staging_box.left = 0;
688   priv->staging_box.top = 0;
689   priv->staging_box.front = 0;
690   priv->staging_box.back = 1;
691   priv->staging_box.right = GST_VIDEO_INFO_WIDTH (info);
692   priv->staging_box.bottom = GST_VIDEO_INFO_HEIGHT (info);
693
694   priv->decoder_profile = selected_profile;
695   decoder->opened = TRUE;
696   gst_d3d11_device_unlock (priv->device);
697
698   return TRUE;
699
700 error:
701   gst_d3d11_device_unlock (priv->device);
702
703   return FALSE;
704 }
705
706 gboolean
707 gst_d3d11_decoder_begin_frame (GstD3D11Decoder * decoder,
708     GstD3D11DecoderOutputView * output_view, guint content_key_size,
709     gconstpointer content_key)
710 {
711   GstD3D11DecoderPrivate *priv;
712   guint retry_count = 0;
713   HRESULT hr;
714
715   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
716   g_return_val_if_fail (output_view != NULL, FALSE);
717   g_return_val_if_fail (output_view->handle != NULL, FALSE);
718
719   priv = decoder->priv;
720
721   do {
722     GST_LOG_OBJECT (decoder, "Try begin frame, retry count %d", retry_count);
723     gst_d3d11_device_lock (priv->device);
724     hr = ID3D11VideoContext_DecoderBeginFrame (priv->video_context,
725         priv->decoder, output_view->handle, content_key_size, content_key);
726     gst_d3d11_device_unlock (priv->device);
727
728     if (gst_d3d11_result (hr, priv->device)) {
729       GST_LOG_OBJECT (decoder, "Success with retry %d", retry_count);
730       break;
731     } else if (hr == E_PENDING && retry_count < 50) {
732       GST_LOG_OBJECT (decoder, "GPU busy, try again");
733
734       /* HACK: no better idea other than sleep...
735        * 1ms waiting like msdkdec */
736       g_usleep (1000);
737     } else {
738       break;
739     }
740
741     retry_count++;
742   } while (TRUE);
743
744   if (!gst_d3d11_result (hr, priv->device)) {
745     GST_ERROR_OBJECT (decoder, "Failed to begin frame, hr: 0x%x", (guint) hr);
746     return FALSE;
747   }
748
749   return TRUE;
750 }
751
752 gboolean
753 gst_d3d11_decoder_end_frame (GstD3D11Decoder * decoder)
754 {
755   GstD3D11DecoderPrivate *priv;
756   HRESULT hr;
757
758   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
759
760   priv = decoder->priv;
761
762   gst_d3d11_device_lock (priv->device);
763   hr = ID3D11VideoContext_DecoderEndFrame (priv->video_context, priv->decoder);
764   gst_d3d11_device_unlock (priv->device);
765
766   if (!gst_d3d11_result (hr, priv->device)) {
767     GST_WARNING_OBJECT (decoder, "EndFrame failed, hr: 0x%x", (guint) hr);
768     return FALSE;
769   }
770
771   return TRUE;
772 }
773
774 gboolean
775 gst_d3d11_decoder_get_decoder_buffer (GstD3D11Decoder * decoder,
776     D3D11_VIDEO_DECODER_BUFFER_TYPE type, guint * buffer_size,
777     gpointer * buffer)
778 {
779   GstD3D11DecoderPrivate *priv;
780   UINT size;
781   void *decoder_buffer;
782   HRESULT hr;
783
784   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
785
786   priv = decoder->priv;
787
788   gst_d3d11_device_lock (priv->device);
789   hr = ID3D11VideoContext_GetDecoderBuffer (priv->video_context,
790       priv->decoder, type, &size, &decoder_buffer);
791   gst_d3d11_device_unlock (priv->device);
792
793   if (!gst_d3d11_result (hr, priv->device)) {
794     GST_WARNING_OBJECT (decoder, "Getting buffer type %d error, hr: 0x%x",
795         type, (guint) hr);
796     return FALSE;
797   }
798
799   *buffer_size = size;
800   *buffer = decoder_buffer;
801
802   return TRUE;
803 }
804
805 gboolean
806 gst_d3d11_decoder_release_decoder_buffer (GstD3D11Decoder * decoder,
807     D3D11_VIDEO_DECODER_BUFFER_TYPE type)
808 {
809   GstD3D11DecoderPrivate *priv;
810   HRESULT hr;
811
812   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
813
814   priv = decoder->priv;
815
816   gst_d3d11_device_lock (priv->device);
817   hr = ID3D11VideoContext_ReleaseDecoderBuffer (priv->video_context,
818       priv->decoder, type);
819   gst_d3d11_device_unlock (priv->device);
820
821   if (!gst_d3d11_result (hr, priv->device)) {
822     GST_WARNING_OBJECT (decoder, "ReleaseDecoderBuffer failed, hr: 0x%x",
823         (guint) hr);
824     return FALSE;
825   }
826
827   return TRUE;
828 }
829
830 gboolean
831 gst_d3d11_decoder_submit_decoder_buffers (GstD3D11Decoder * decoder,
832     guint buffer_count, const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)
833 {
834   GstD3D11DecoderPrivate *priv;
835   HRESULT hr;
836
837   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
838
839   priv = decoder->priv;
840
841   gst_d3d11_device_lock (priv->device);
842   hr = ID3D11VideoContext_SubmitDecoderBuffers (priv->video_context,
843       priv->decoder, buffer_count, buffers);
844   gst_d3d11_device_unlock (priv->device);
845
846   if (!gst_d3d11_result (hr, priv->device)) {
847     GST_WARNING_OBJECT (decoder, "SubmitDecoderBuffers failed, hr: 0x%x",
848         (guint) hr);
849     return FALSE;
850   }
851
852   return TRUE;
853 }
854
855 GstBuffer *
856 gst_d3d11_decoder_get_output_view_buffer (GstD3D11Decoder * decoder)
857 {
858   GstD3D11DecoderPrivate *priv;
859   GstBuffer *buf = NULL;
860   GstFlowReturn ret;
861
862   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
863
864   priv = decoder->priv;
865
866   ret = gst_buffer_pool_acquire_buffer (priv->internal_pool, &buf, NULL);
867
868   if (ret != GST_FLOW_OK || !buf) {
869     GST_ERROR_OBJECT (decoder, "Couldn't get buffer from pool, ret %s",
870         gst_flow_get_name (ret));
871     return NULL;
872   }
873
874   if (!gst_d3d11_decoder_ensure_output_view (decoder, buf)) {
875     GST_ERROR_OBJECT (decoder, "Output view unavailable");
876     gst_buffer_unref (buf);
877
878     return NULL;
879   }
880
881   return buf;
882 }
883
884 GstD3D11DecoderOutputView *
885 gst_d3d11_decoder_get_output_view_from_buffer (GstD3D11Decoder * decoder,
886     GstBuffer * buffer)
887 {
888   GstMemory *mem;
889   GstD3D11DecoderOutputView *view;
890
891   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), NULL);
892   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
893
894   mem = gst_buffer_peek_memory (buffer, 0);
895   if (!gst_is_d3d11_memory (mem)) {
896     GST_WARNING_OBJECT (decoder, "nemory is not d3d11 memory");
897     return NULL;
898   }
899
900   view = (GstD3D11DecoderOutputView *)
901       gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
902
903   if (!view) {
904     GST_WARNING_OBJECT (decoder, "memory does not have output view");
905   }
906
907   return view;
908 }
909
910 guint
911 gst_d3d11_decoder_get_output_view_index (GstD3D11Decoder * decoder,
912     ID3D11VideoDecoderOutputView * view_handle)
913 {
914   D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc;
915
916   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), 0xff);
917   g_return_val_if_fail (view_handle != NULL, 0xff);
918
919   ID3D11VideoDecoderOutputView_GetDesc (view_handle, &view_desc);
920
921   return view_desc.Texture2D.ArraySlice;
922 }
923
924 static gboolean
925 copy_to_system (GstD3D11Decoder * self, GstVideoInfo * info,
926     GstBuffer * decoder_buffer, GstBuffer * output)
927 {
928   GstD3D11DecoderPrivate *priv = self->priv;
929   D3D11_TEXTURE2D_DESC *desc = &priv->staging_desc;
930   GstVideoFrame out_frame;
931   gint i;
932   GstD3D11Memory *in_mem;
933   D3D11_MAPPED_SUBRESOURCE map;
934   gsize offset[GST_VIDEO_MAX_PLANES];
935   gint stride[GST_VIDEO_MAX_PLANES];
936   gsize dummy;
937   HRESULT hr;
938   ID3D11DeviceContext *device_context =
939       gst_d3d11_device_get_device_context_handle (priv->device);
940
941   if (!gst_video_frame_map (&out_frame, info, output, GST_MAP_WRITE)) {
942     GST_ERROR_OBJECT (self, "Couldn't map output buffer");
943     return FALSE;
944   }
945
946   in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
947
948   gst_d3d11_device_lock (priv->device);
949   ID3D11DeviceContext_CopySubresourceRegion (device_context,
950       (ID3D11Resource *) priv->staging, 0, 0, 0, 0,
951       (ID3D11Resource *) in_mem->texture, in_mem->subresource_index,
952       &priv->staging_box);
953
954   hr = ID3D11DeviceContext_Map (device_context,
955       (ID3D11Resource *) priv->staging, 0, D3D11_MAP_READ, 0, &map);
956
957   if (!gst_d3d11_result (hr, priv->device)) {
958     GST_ERROR_OBJECT (self, "Failed to map, hr: 0x%x", (guint) hr);
959     gst_d3d11_device_unlock (priv->device);
960     return FALSE;
961   }
962
963   gst_d3d11_dxgi_format_get_size (desc->Format, desc->Width, desc->Height,
964       map.RowPitch, offset, stride, &dummy);
965
966   for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&out_frame); i++) {
967     guint8 *src, *dst;
968     gint j;
969     gint width;
970
971     src = (guint8 *) map.pData + offset[i];
972     dst = GST_VIDEO_FRAME_PLANE_DATA (&out_frame, i);
973     width = GST_VIDEO_FRAME_COMP_WIDTH (&out_frame, i) *
974         GST_VIDEO_FRAME_COMP_PSTRIDE (&out_frame, i);
975
976     for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (&out_frame, i); j++) {
977       memcpy (dst, src, width);
978       dst += GST_VIDEO_FRAME_PLANE_STRIDE (&out_frame, i);
979       src += map.RowPitch;
980     }
981   }
982
983   gst_video_frame_unmap (&out_frame);
984   ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) priv->staging,
985       0);
986   gst_d3d11_device_unlock (priv->device);
987
988   return TRUE;
989 }
990
991 static gboolean
992 copy_to_d3d11 (GstD3D11Decoder * self, GstVideoInfo * info,
993     GstBuffer * decoder_buffer, GstBuffer * output)
994 {
995   GstD3D11DecoderPrivate *priv = self->priv;
996   gint i;
997   ID3D11DeviceContext *device_context =
998       gst_d3d11_device_get_device_context_handle (priv->device);
999
1000   gst_d3d11_device_lock (priv->device);
1001   for (i = 0; i < gst_buffer_n_memory (output); i++) {
1002     GstD3D11Memory *in_mem;
1003     GstD3D11Memory *out_mem;
1004     D3D11_BOX src_box;
1005     D3D11_TEXTURE2D_DESC desc;
1006
1007     in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, i);
1008     out_mem = (GstD3D11Memory *) gst_buffer_peek_memory (output, i);
1009
1010     ID3D11Texture2D_GetDesc (out_mem->texture, &desc);
1011
1012     src_box.left = 0;
1013     src_box.top = 0;
1014     src_box.front = 0;
1015     src_box.back = 1;
1016     src_box.right = desc.Width;
1017     src_box.bottom = desc.Height;
1018
1019     ID3D11DeviceContext_CopySubresourceRegion (device_context,
1020         (ID3D11Resource *) out_mem->texture,
1021         out_mem->subresource_index, 0, 0, 0,
1022         (ID3D11Resource *) in_mem->texture, in_mem->subresource_index,
1023         &src_box);
1024
1025     GST_MINI_OBJECT_FLAG_SET (out_mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
1026   }
1027   gst_d3d11_device_unlock (priv->device);
1028
1029   return TRUE;
1030 }
1031
1032 gboolean
1033 gst_d3d11_decoder_copy_decoder_buffer (GstD3D11Decoder * decoder,
1034     GstVideoInfo * info, GstBuffer * decoder_buffer, GstBuffer * output)
1035 {
1036   GstD3D11DecoderPrivate *priv;
1037   gboolean can_device_copy = TRUE;
1038
1039   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1040   g_return_val_if_fail (GST_IS_BUFFER (decoder_buffer), FALSE);
1041   g_return_val_if_fail (GST_IS_BUFFER (output), FALSE);
1042
1043   priv = decoder->priv;
1044
1045   if (gst_buffer_n_memory (decoder_buffer) == gst_buffer_n_memory (output)) {
1046     gint i;
1047
1048     for (i = 0; i < gst_buffer_n_memory (output); i++) {
1049       GstMemory *mem;
1050       GstD3D11Memory *dmem;
1051
1052       mem = gst_buffer_peek_memory (output, i);
1053
1054       if (!gst_is_d3d11_memory (mem)) {
1055         can_device_copy = FALSE;
1056         break;
1057       }
1058
1059       dmem = (GstD3D11Memory *) mem;
1060
1061       if (dmem->device != priv->device) {
1062         can_device_copy = FALSE;
1063         break;
1064       }
1065     }
1066   } else {
1067     can_device_copy = FALSE;
1068   }
1069
1070   if (can_device_copy) {
1071     return copy_to_d3d11 (decoder, info, decoder_buffer, output);
1072   }
1073
1074   return copy_to_system (decoder, info, decoder_buffer, output);
1075 }
1076
1077 /* Keep sync with chromium and keep in sorted order.
1078  * See supported_profile_helpers.cc in chromium */
1079 static const guint legacy_amd_list[] = {
1080   0x130f, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707,
1081   0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x6720, 0x6721,
1082   0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, 0x6738,
1083   0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746,
1084   0x6747, 0x6748, 0x6749, 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b,
1085   0x675d, 0x675f, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766,
1086   0x6767, 0x6768, 0x6770, 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6798,
1087   0x67b1, 0x6821, 0x683d, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, 0x6850,
1088   0x6858, 0x6859, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, 0x6898,
1089   0x6899, 0x689b, 0x689c, 0x689d, 0x689e, 0x68a0, 0x68a1, 0x68a8, 0x68a9,
1090   0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x68c0, 0x68c1, 0x68c7,
1091   0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68e0, 0x68e1, 0x68e4,
1092   0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, 0x68fe,
1093   0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x9440,
1094   0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e,
1095   0x9450, 0x9452, 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a,
1096   0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, 0x9489, 0x948a, 0x948f,
1097   0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x94a0, 0x94a1,
1098   0x94a3, 0x94b1, 0x94b3, 0x94b4, 0x94b5, 0x94b9, 0x94c0, 0x94c1, 0x94c3,
1099   0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd,
1100   0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, 0x9508, 0x9509, 0x950f,
1101   0x9511, 0x9515, 0x9517, 0x9519, 0x9540, 0x9541, 0x9542, 0x954e, 0x954f,
1102   0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x9580, 0x9581, 0x9583, 0x9586,
1103   0x9587, 0x9588, 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f,
1104   0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, 0x959b,
1105   0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c9, 0x95cc, 0x95cd,
1106   0x95ce, 0x95cf, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616,
1107   0x9640, 0x9641, 0x9642, 0x9643, 0x9644, 0x9645, 0x9647, 0x9648, 0x9649,
1108   0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9710, 0x9711, 0x9712, 0x9713,
1109   0x9714, 0x9715, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808,
1110   0x9809, 0x980a, 0x9830, 0x983d, 0x9850, 0x9851, 0x9874, 0x9900, 0x9901,
1111   0x9903, 0x9904, 0x9905, 0x9906, 0x9907, 0x9908, 0x9909, 0x990a, 0x990b,
1112   0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, 0x9919,
1113   0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
1114   0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4
1115 };
1116
1117 static const guint legacy_intel_list[] = {
1118   0x102, 0x106, 0x116, 0x126, 0x152, 0x156, 0x166,
1119   0x402, 0x406, 0x416, 0x41e, 0xa06, 0xa16, 0xf31,
1120 };
1121
1122 static gint
1123 binary_search_compare (const guint * a, const guint * b)
1124 {
1125   return *a - *b;
1126 }
1127
1128 /* Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and some second
1129  * generation Intel GPU drivers crash if we create a video device with a
1130  * resolution higher then 1920 x 1088. This function checks if the GPU is in
1131  * this list and if yes returns true. */
1132 gboolean
1133 gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device)
1134 {
1135   const guint amd_id[] = { 0x1002, 0x1022 };
1136   const guint intel_id = 0x8086;
1137   guint device_id = 0;
1138   guint vendor_id = 0;
1139   guint *match = NULL;
1140
1141   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
1142
1143   g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id, NULL);
1144
1145   if (vendor_id == amd_id[0] || vendor_id == amd_id[1]) {
1146     match =
1147         (guint *) gst_util_array_binary_search ((gpointer) legacy_amd_list,
1148         G_N_ELEMENTS (legacy_amd_list), sizeof (guint),
1149         (GCompareDataFunc) binary_search_compare,
1150         GST_SEARCH_MODE_EXACT, &device_id, NULL);
1151   } else if (vendor_id == intel_id) {
1152     match =
1153         (guint *) gst_util_array_binary_search ((gpointer) legacy_intel_list,
1154         G_N_ELEMENTS (legacy_intel_list), sizeof (guint),
1155         (GCompareDataFunc) binary_search_compare,
1156         GST_SEARCH_MODE_EXACT, &device_id, NULL);
1157   }
1158
1159   if (match) {
1160     GST_DEBUG_OBJECT (device, "it's legacy device");
1161     return TRUE;
1162   }
1163
1164   return FALSE;
1165 }
1166
1167 gboolean
1168 gst_d3d11_decoder_supports_format (GstD3D11Decoder * decoder,
1169     const GUID * decoder_profile, DXGI_FORMAT format)
1170 {
1171   GstD3D11DecoderPrivate *priv;
1172   HRESULT hr;
1173   BOOL can_support = FALSE;
1174
1175   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1176   g_return_val_if_fail (decoder_profile != NULL, FALSE);
1177   g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
1178
1179   priv = decoder->priv;
1180
1181   hr = ID3D11VideoDevice_CheckVideoDecoderFormat (priv->video_device,
1182       decoder_profile, format, &can_support);
1183   if (!gst_d3d11_result (hr, priv->device) || !can_support) {
1184     GST_DEBUG_OBJECT (decoder,
1185         "VideoDevice could not support dxgi format %d, hr: 0x%x",
1186         format, (guint) hr);
1187
1188     return FALSE;
1189   }
1190
1191   return TRUE;
1192 }
1193
1194 /* Don't call this method with legacy device */
1195 gboolean
1196 gst_d3d11_decoder_supports_resolution (GstD3D11Decoder * decoder,
1197     const GUID * decoder_profile, DXGI_FORMAT format, guint width, guint height)
1198 {
1199   D3D11_VIDEO_DECODER_DESC desc;
1200   GstD3D11DecoderPrivate *priv;
1201   HRESULT hr;
1202   UINT config_count;
1203
1204   g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
1205   g_return_val_if_fail (decoder_profile != NULL, FALSE);
1206   g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
1207
1208   priv = decoder->priv;
1209
1210   desc.SampleWidth = width;
1211   desc.SampleHeight = height;
1212   desc.OutputFormat = format;
1213   desc.Guid = *decoder_profile;
1214
1215   hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device,
1216       &desc, &config_count);
1217   if (!gst_d3d11_result (hr, priv->device) || config_count == 0) {
1218     GST_DEBUG_OBJECT (decoder, "Could not get decoder config count, hr: 0x%x",
1219         (guint) hr);
1220     return FALSE;
1221   }
1222
1223   return TRUE;
1224 }
1225
1226 /**
1227  * gst_d3d11_decoder_class_data_new:
1228  * @device: (transfer none): a #GstD3D11Device
1229  * @sink_caps: (transfer full): a #GstCaps
1230  * @src_caps: (transfer full): a #GstCaps
1231  *
1232  * Create new #GstD3D11DecoderClassData
1233  *
1234  * Returns: (transfer full): the new #GstD3D11DecoderClassData
1235  */
1236 GstD3D11DecoderClassData *
1237 gst_d3d11_decoder_class_data_new (GstD3D11Device * device,
1238     GstCaps * sink_caps, GstCaps * src_caps)
1239 {
1240   GstD3D11DecoderClassData *ret;
1241
1242   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1243   g_return_val_if_fail (sink_caps != NULL, NULL);
1244   g_return_val_if_fail (src_caps != NULL, NULL);
1245
1246   ret = g_new0 (GstD3D11DecoderClassData, 1);
1247
1248   /* class data will be leaked if the element never gets instantiated */
1249   GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1250   GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
1251
1252   g_object_get (device, "adapter", &ret->adapter,
1253       "device-id", &ret->device_id, "vendor-id", &ret->vendor_id,
1254       "description", &ret->description, NULL);
1255   ret->sink_caps = sink_caps;
1256   ret->src_caps = src_caps;
1257
1258   return ret;
1259 }
1260
1261 void
1262 gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data)
1263 {
1264   if (!data)
1265     return;
1266
1267   gst_clear_caps (&data->sink_caps);
1268   gst_clear_caps (&data->src_caps);
1269   g_free (data->description);
1270   g_free (data);
1271 }