2 * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
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.
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.
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.
19 * NOTE: some of implementations are copied/modified from Chromium code
21 * Copyright 2015 The Chromium Authors. All rights reserved.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions are
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
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.
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.
54 #include "gstd3d11decoder.h"
55 #include "gstd3d11memory.h"
56 #include "gstd3d11bufferpool.h"
57 #include "gstd3d11device.h"
60 GST_DEBUG_CATEGORY (d3d11_decoder_debug);
61 #define GST_CAT_DEFAULT d3d11_decoder_debug
69 struct _GstD3D11DecoderPrivate
71 GstD3D11Device *device;
73 ID3D11VideoDevice *video_device;
74 ID3D11VideoContext *video_context;
76 ID3D11VideoDecoder *decoder;
78 GstBufferPool *internal_pool;
81 ID3D11Texture2D *staging;
82 D3D11_TEXTURE2D_DESC staging_desc;
83 D3D11_BOX staging_box;
88 #define OUTPUT_VIEW_QUARK _decoder_output_view_get()
90 _decoder_output_view_get (void)
92 static volatile gsize g_quark = 0;
94 if (g_once_init_enter (&g_quark)) {
96 (gsize) g_quark_from_static_string ("GstD3D11DecoderOutputView");
97 g_once_init_leave (&g_quark, quark);
99 return (GQuark) g_quark;
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);
109 #define parent_class gst_d3d11_decoder_parent_class
110 G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Decoder,
111 gst_d3d11_decoder, GST_TYPE_OBJECT);
114 gst_d3d11_decoder_class_init (GstD3D11DecoderClass * klass)
116 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
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;
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));
128 GST_DEBUG_CATEGORY_INIT (d3d11_decoder_debug,
129 "d3d11decoder", 0, "Direct3D11 Base Video Decoder object");
133 gst_d3d11_decoder_init (GstD3D11Decoder * self)
135 self->priv = gst_d3d11_decoder_get_instance_private (self);
139 gst_d3d11_decoder_constructed (GObject * object)
141 GstD3D11Decoder *self = GST_D3D11_DECODER (object);
142 GstD3D11DecoderPrivate *priv = self->priv;
144 ID3D11Device *device_handle;
145 ID3D11DeviceContext *device_context_handle;
148 GST_ERROR_OBJECT (self, "No D3D11Device available");
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);
156 hr = ID3D11Device_QueryInterface (device_handle, &IID_ID3D11VideoDevice,
157 (void **) &priv->video_device);
159 if (!gst_d3d11_result (hr, priv->device) || !priv->video_device) {
160 GST_WARNING_OBJECT (self, "Cannot create VideoDevice Object: 0x%x",
162 priv->video_device = NULL;
167 hr = ID3D11DeviceContext_QueryInterface (device_context_handle,
168 &IID_ID3D11VideoContext, (void **) &priv->video_context);
170 if (!gst_d3d11_result (hr, priv->device) || !priv->video_context) {
171 GST_WARNING_OBJECT (self, "Cannot create VideoContext Object: 0x%x",
173 priv->video_context = NULL;
181 if (priv->video_device) {
182 ID3D11VideoDevice_Release (priv->video_device);
183 priv->video_device = NULL;
186 if (priv->video_context) {
187 ID3D11VideoContext_Release (priv->video_context);
188 priv->video_context = NULL;
195 gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
196 const GValue * value, GParamSpec * pspec)
198 GstD3D11Decoder *self = GST_D3D11_DECODER (object);
199 GstD3D11DecoderPrivate *priv = self->priv;
203 priv->device = g_value_dup_object (value);
206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
212 gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
213 GValue * value, GParamSpec * pspec)
215 GstD3D11Decoder *self = GST_D3D11_DECODER (object);
216 GstD3D11DecoderPrivate *priv = self->priv;
220 g_value_set_object (value, priv->device);
223 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
229 gst_d3d11_decoder_close (GstD3D11Decoder * self)
231 GstD3D11DecoderPrivate *priv = self->priv;
233 gst_d3d11_decoder_reset (self);
235 if (priv->video_device) {
236 ID3D11VideoDevice_Release (priv->video_device);
237 priv->video_device = NULL;
240 if (priv->video_context) {
241 ID3D11VideoContext_Release (priv->video_context);
242 priv->video_context = NULL;
249 gst_d3d11_decoder_reset_unlocked (GstD3D11Decoder * decoder)
251 GstD3D11DecoderPrivate *priv;
253 priv = decoder->priv;
254 gst_clear_object (&priv->internal_pool);
257 ID3D11VideoDecoder_Release (priv->decoder);
258 priv->decoder = NULL;
262 ID3D11Texture2D_Release (priv->staging);
263 priv->staging = NULL;
266 decoder->opened = FALSE;
270 gst_d3d11_decoder_reset (GstD3D11Decoder * decoder)
272 GstD3D11DecoderPrivate *priv;
274 g_return_if_fail (GST_IS_D3D11_DECODER (decoder));
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);
283 gst_d3d11_decoder_dispose (GObject * obj)
285 GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
286 GstD3D11DecoderPrivate *priv = self->priv;
289 gst_d3d11_decoder_close (self);
290 gst_object_unref (priv->device);
294 G_OBJECT_CLASS (parent_class)->dispose (obj);
298 gst_d3d11_decoder_new (GstD3D11Device * device)
300 GstD3D11Decoder *decoder;
301 GstD3D11DecoderPrivate *priv;
303 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
305 decoder = g_object_new (GST_TYPE_D3D11_DECODER, "device", device, NULL);
306 priv = decoder->priv;
308 if (!priv->video_device || !priv->video_context) {
309 gst_object_unref (decoder);
313 gst_object_ref_sink (decoder);
319 gst_d3d11_decoder_output_view_free (GstD3D11DecoderOutputView * view)
321 GST_DEBUG_OBJECT (view->device, "Free view %p", view);
324 gst_d3d11_device_lock (view->device);
325 ID3D11VideoDecoderOutputView_Release (view->handle);
326 gst_d3d11_device_unlock (view->device);
329 gst_clear_object (&view->device);
334 gst_d3d11_decoder_ensure_output_view (GstD3D11Decoder * self,
337 GstD3D11DecoderPrivate *priv = self->priv;
338 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = { 0, };
340 GstD3D11DecoderOutputView *view;
341 ID3D11VideoDecoderOutputView *view_handle;
344 mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
346 view = (GstD3D11DecoderOutputView *)
347 gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
352 view_desc.DecodeProfile = priv->decoder_profile;
353 view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
354 view_desc.Texture2D.ArraySlice = mem->subresource_index;
356 GST_LOG_OBJECT (self,
357 "Create decoder output view with index %d", mem->subresource_index);
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);
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;
372 gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK,
373 view, (GDestroyNotify) gst_d3d11_decoder_output_view_free);
378 /* Must be called from D3D11Device thread */
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)
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;
391 gst_clear_object (&priv->internal_pool);
393 alloc_params = gst_d3d11_allocation_params_new (priv->device, info,
394 GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY, D3D11_BIND_DECODER);
397 GST_ERROR_OBJECT (self, "Failed to create allocation param");
401 alloc_params->desc[0].ArraySize = pool_size;
402 gst_video_alignment_reset (&align);
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");
411 pool = gst_d3d11_buffer_pool_new (priv->device);
413 GST_ERROR_OBJECT (self, "Failed to create buffer pool");
417 /* Setup buffer pool */
418 config = gst_buffer_pool_get_config (pool);
419 caps = gst_video_info_to_caps (info);
421 GST_ERROR_OBJECT (self, "Couldn't convert video info to caps");
425 gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (info),
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);
432 if (!gst_buffer_pool_set_config (pool, config)) {
433 GST_ERROR_OBJECT (self, "Invalid pool config");
437 if (!gst_buffer_pool_set_active (pool, TRUE)) {
438 GST_ERROR_OBJECT (self, "Couldn't activate pool");
442 priv->internal_pool = pool;
448 gst_d3d11_allocation_params_free (alloc_params);
450 gst_object_unref (pool);
452 gst_caps_unref (caps);
458 gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Decoder * decoder,
459 const GUID ** decoder_profiles, guint profile_size, GUID * selected_profile)
461 GstD3D11DecoderPrivate *priv;
462 GUID *guid_list = NULL;
463 const GUID *profile = NULL;
464 guint available_profile_count;
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);
473 priv = decoder->priv;
475 available_profile_count =
476 ID3D11VideoDevice_GetVideoDecoderProfileCount (priv->video_device);
478 if (available_profile_count == 0) {
479 GST_WARNING_OBJECT (decoder, "No available decoder profile");
483 GST_DEBUG_OBJECT (decoder,
484 "Have %u available decoder profiles", available_profile_count);
485 guid_list = g_alloca (sizeof (GUID) * available_profile_count);
487 for (i = 0; i < available_profile_count; i++) {
488 hr = ID3D11VideoDevice_GetVideoDecoderProfile (priv->video_device,
490 if (!gst_d3d11_result (hr, priv->device)) {
491 GST_WARNING_OBJECT (decoder, "Failed to get %d th decoder profile", i);
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];
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]);
508 GST_LOG_OBJECT (decoder, "Requested decoder GUID");
509 for (i = 0; i < profile_size; i++) {
510 const GUID *guid = decoder_profiles[i];
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]);
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];
530 GST_WARNING_OBJECT (decoder, "No supported decoder profile");
534 *selected_profile = *profile;
536 GST_DEBUG_OBJECT (decoder,
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]);
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)
554 GstD3D11DecoderPrivate *priv;
555 const GstD3D11Format *d3d11_format;
557 BOOL can_support = FALSE;
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;
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);
575 priv = decoder->priv;
576 decoder->opened = FALSE;
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)));
586 gst_d3d11_device_lock (priv->device);
587 if (!gst_d3d11_decoder_get_supported_decoder_profile (decoder,
588 decoder_profiles, profile_size, &selected_profile)) {
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);
601 gst_d3d11_decoder_reset_unlocked (decoder);
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;
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",
616 GST_DEBUG_OBJECT (decoder, "Total %d config available", config_count);
618 config_list = g_alloca (sizeof (D3D11_VIDEO_DECODER_CONFIG) * config_count);
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",
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];
636 if ((codec == GST_D3D11_CODEC_VP9 || codec == GST_D3D11_CODEC_H265)
637 && config_list[i].ConfigBitstreamRaw == 1) {
638 best_config = &config_list[i];
643 if (best_config == NULL) {
644 GST_ERROR_OBJECT (decoder, "Could not determine decoder config");
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");
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);
662 GST_DEBUG_OBJECT (decoder, "Decoder object %p created", priv->decoder);
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;
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");
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.
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);
694 priv->decoder_profile = selected_profile;
695 decoder->opened = TRUE;
696 gst_d3d11_device_unlock (priv->device);
701 gst_d3d11_device_unlock (priv->device);
707 gst_d3d11_decoder_begin_frame (GstD3D11Decoder * decoder,
708 GstD3D11DecoderOutputView * output_view, guint content_key_size,
709 gconstpointer content_key)
711 GstD3D11DecoderPrivate *priv;
712 guint retry_count = 0;
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);
719 priv = decoder->priv;
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);
728 if (gst_d3d11_result (hr, priv->device)) {
729 GST_LOG_OBJECT (decoder, "Success with retry %d", retry_count);
731 } else if (hr == E_PENDING && retry_count < 50) {
732 GST_LOG_OBJECT (decoder, "GPU busy, try again");
734 /* HACK: no better idea other than sleep...
735 * 1ms waiting like msdkdec */
744 if (!gst_d3d11_result (hr, priv->device)) {
745 GST_ERROR_OBJECT (decoder, "Failed to begin frame, hr: 0x%x", (guint) hr);
753 gst_d3d11_decoder_end_frame (GstD3D11Decoder * decoder)
755 GstD3D11DecoderPrivate *priv;
758 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
760 priv = decoder->priv;
762 gst_d3d11_device_lock (priv->device);
763 hr = ID3D11VideoContext_DecoderEndFrame (priv->video_context, priv->decoder);
764 gst_d3d11_device_unlock (priv->device);
766 if (!gst_d3d11_result (hr, priv->device)) {
767 GST_WARNING_OBJECT (decoder, "EndFrame failed, hr: 0x%x", (guint) hr);
775 gst_d3d11_decoder_get_decoder_buffer (GstD3D11Decoder * decoder,
776 D3D11_VIDEO_DECODER_BUFFER_TYPE type, guint * buffer_size,
779 GstD3D11DecoderPrivate *priv;
781 void *decoder_buffer;
784 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
786 priv = decoder->priv;
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);
793 if (!gst_d3d11_result (hr, priv->device)) {
794 GST_WARNING_OBJECT (decoder, "Getting buffer type %d error, hr: 0x%x",
800 *buffer = decoder_buffer;
806 gst_d3d11_decoder_release_decoder_buffer (GstD3D11Decoder * decoder,
807 D3D11_VIDEO_DECODER_BUFFER_TYPE type)
809 GstD3D11DecoderPrivate *priv;
812 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
814 priv = decoder->priv;
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);
821 if (!gst_d3d11_result (hr, priv->device)) {
822 GST_WARNING_OBJECT (decoder, "ReleaseDecoderBuffer failed, hr: 0x%x",
831 gst_d3d11_decoder_submit_decoder_buffers (GstD3D11Decoder * decoder,
832 guint buffer_count, const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)
834 GstD3D11DecoderPrivate *priv;
837 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
839 priv = decoder->priv;
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);
846 if (!gst_d3d11_result (hr, priv->device)) {
847 GST_WARNING_OBJECT (decoder, "SubmitDecoderBuffers failed, hr: 0x%x",
856 gst_d3d11_decoder_get_output_view_buffer (GstD3D11Decoder * decoder)
858 GstD3D11DecoderPrivate *priv;
859 GstBuffer *buf = NULL;
862 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
864 priv = decoder->priv;
866 ret = gst_buffer_pool_acquire_buffer (priv->internal_pool, &buf, NULL);
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));
874 if (!gst_d3d11_decoder_ensure_output_view (decoder, buf)) {
875 GST_ERROR_OBJECT (decoder, "Output view unavailable");
876 gst_buffer_unref (buf);
884 GstD3D11DecoderOutputView *
885 gst_d3d11_decoder_get_output_view_from_buffer (GstD3D11Decoder * decoder,
889 GstD3D11DecoderOutputView *view;
891 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), NULL);
892 g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
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");
900 view = (GstD3D11DecoderOutputView *)
901 gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
904 GST_WARNING_OBJECT (decoder, "memory does not have output view");
911 gst_d3d11_decoder_get_output_view_index (GstD3D11Decoder * decoder,
912 ID3D11VideoDecoderOutputView * view_handle)
914 D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc;
916 g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), 0xff);
917 g_return_val_if_fail (view_handle != NULL, 0xff);
919 ID3D11VideoDecoderOutputView_GetDesc (view_handle, &view_desc);
921 return view_desc.Texture2D.ArraySlice;
925 copy_to_system (GstD3D11Decoder * self, GstVideoInfo * info,
926 GstBuffer * decoder_buffer, GstBuffer * output)
928 GstD3D11DecoderPrivate *priv = self->priv;
929 D3D11_TEXTURE2D_DESC *desc = &priv->staging_desc;
930 GstVideoFrame out_frame;
932 GstD3D11Memory *in_mem;
933 D3D11_MAPPED_SUBRESOURCE map;
934 gsize offset[GST_VIDEO_MAX_PLANES];
935 gint stride[GST_VIDEO_MAX_PLANES];
938 ID3D11DeviceContext *device_context =
939 gst_d3d11_device_get_device_context_handle (priv->device);
941 if (!gst_video_frame_map (&out_frame, info, output, GST_MAP_WRITE)) {
942 GST_ERROR_OBJECT (self, "Couldn't map output buffer");
946 in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
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,
954 hr = ID3D11DeviceContext_Map (device_context,
955 (ID3D11Resource *) priv->staging, 0, D3D11_MAP_READ, 0, &map);
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);
963 gst_d3d11_dxgi_format_get_size (desc->Format, desc->Width, desc->Height,
964 map.RowPitch, offset, stride, &dummy);
966 for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&out_frame); i++) {
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);
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);
983 gst_video_frame_unmap (&out_frame);
984 ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) priv->staging,
986 gst_d3d11_device_unlock (priv->device);
992 copy_to_d3d11 (GstD3D11Decoder * self, GstVideoInfo * info,
993 GstBuffer * decoder_buffer, GstBuffer * output)
995 GstD3D11DecoderPrivate *priv = self->priv;
997 ID3D11DeviceContext *device_context =
998 gst_d3d11_device_get_device_context_handle (priv->device);
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;
1005 D3D11_TEXTURE2D_DESC desc;
1007 in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, i);
1008 out_mem = (GstD3D11Memory *) gst_buffer_peek_memory (output, i);
1010 ID3D11Texture2D_GetDesc (out_mem->texture, &desc);
1016 src_box.right = desc.Width;
1017 src_box.bottom = desc.Height;
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,
1025 GST_MINI_OBJECT_FLAG_SET (out_mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
1027 gst_d3d11_device_unlock (priv->device);
1033 gst_d3d11_decoder_copy_decoder_buffer (GstD3D11Decoder * decoder,
1034 GstVideoInfo * info, GstBuffer * decoder_buffer, GstBuffer * output)
1036 GstD3D11DecoderPrivate *priv;
1037 gboolean can_device_copy = TRUE;
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);
1043 priv = decoder->priv;
1045 if (gst_buffer_n_memory (decoder_buffer) == gst_buffer_n_memory (output)) {
1048 for (i = 0; i < gst_buffer_n_memory (output); i++) {
1050 GstD3D11Memory *dmem;
1052 mem = gst_buffer_peek_memory (output, i);
1054 if (!gst_is_d3d11_memory (mem)) {
1055 can_device_copy = FALSE;
1059 dmem = (GstD3D11Memory *) mem;
1061 if (dmem->device != priv->device) {
1062 can_device_copy = FALSE;
1067 can_device_copy = FALSE;
1070 if (can_device_copy) {
1071 return copy_to_d3d11 (decoder, info, decoder_buffer, output);
1074 return copy_to_system (decoder, info, decoder_buffer, output);
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
1117 static const guint legacy_intel_list[] = {
1118 0x102, 0x106, 0x116, 0x126, 0x152, 0x156, 0x166,
1119 0x402, 0x406, 0x416, 0x41e, 0xa06, 0xa16, 0xf31,
1123 binary_search_compare (const guint * a, const guint * b)
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. */
1133 gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device)
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;
1141 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
1143 g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id, NULL);
1145 if (vendor_id == amd_id[0] || vendor_id == amd_id[1]) {
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) {
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);
1160 GST_DEBUG_OBJECT (device, "it's legacy device");
1168 gst_d3d11_decoder_supports_format (GstD3D11Decoder * decoder,
1169 const GUID * decoder_profile, DXGI_FORMAT format)
1171 GstD3D11DecoderPrivate *priv;
1173 BOOL can_support = FALSE;
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);
1179 priv = decoder->priv;
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);
1194 /* Don't call this method with legacy device */
1196 gst_d3d11_decoder_supports_resolution (GstD3D11Decoder * decoder,
1197 const GUID * decoder_profile, DXGI_FORMAT format, guint width, guint height)
1199 D3D11_VIDEO_DECODER_DESC desc;
1200 GstD3D11DecoderPrivate *priv;
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);
1208 priv = decoder->priv;
1210 desc.SampleWidth = width;
1211 desc.SampleHeight = height;
1212 desc.OutputFormat = format;
1213 desc.Guid = *decoder_profile;
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",
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
1232 * Create new #GstD3D11DecoderClassData
1234 * Returns: (transfer full): the new #GstD3D11DecoderClassData
1236 GstD3D11DecoderClassData *
1237 gst_d3d11_decoder_class_data_new (GstD3D11Device * device,
1238 GstCaps * sink_caps, GstCaps * src_caps)
1240 GstD3D11DecoderClassData *ret;
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);
1246 ret = g_new0 (GstD3D11DecoderClassData, 1);
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);
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;
1262 gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data)
1267 gst_clear_caps (&data->sink_caps);
1268 gst_clear_caps (&data->src_caps);
1269 g_free (data->description);