gstreamer/sys/d3d11/gstd3d11decoder.c
Seungha Yang 5c51601cdf d3d11decoder: Use aligned resolution for staging texture
Not only any textures for decoder output view, any destination texture
which would be copied from decoder output texture need to be aligned too.
Otherwise driver sometimes crashed/hung (not sure why).
2020-03-09 23:44:12 +09:00

1376 lines
42 KiB
C

/* GStreamer
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* NOTE: some of implementations are copied/modified from Chromium code
*
* Copyright 2015 The Chromium Authors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gstd3d11decoder.h"
#include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h"
#include "gstd3d11device.h"
#include <string.h>
GST_DEBUG_CATEGORY (d3d11_decoder_debug);
#define GST_CAT_DEFAULT d3d11_decoder_debug
enum
{
PROP_0,
PROP_DEVICE,
};
struct _GstD3D11DecoderPrivate
{
GstD3D11Device *device;
ID3D11VideoDevice *video_device;
ID3D11VideoContext *video_context;
ID3D11VideoDecoder *decoder;
GstBufferPool *internal_pool;
/* for staging */
ID3D11Texture2D *staging;
gsize staging_texture_offset[GST_VIDEO_MAX_PLANES];
gint stating_texture_stride[GST_VIDEO_MAX_PLANES];
GUID decoder_profile;
};
#define OUTPUT_VIEW_QUARK _decoder_output_view_get()
static GQuark
_decoder_output_view_get (void)
{
static volatile gsize g_quark = 0;
if (g_once_init_enter (&g_quark)) {
gsize quark =
(gsize) g_quark_from_static_string ("GstD3D11DecoderOutputView");
g_once_init_leave (&g_quark, quark);
}
return (GQuark) g_quark;
}
static void gst_d3d11_decoder_constructed (GObject * object);
static void gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_d3d11_decoder_dispose (GObject * obj);
#define parent_class gst_d3d11_decoder_parent_class
G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Decoder,
gst_d3d11_decoder, GST_TYPE_OBJECT);
static void
gst_d3d11_decoder_class_init (GstD3D11DecoderClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructed = gst_d3d11_decoder_constructed;
gobject_class->set_property = gst_d3d11_decoder_set_property;
gobject_class->get_property = gst_d3d11_decoder_get_property;
gobject_class->dispose = gst_d3d11_decoder_dispose;
g_object_class_install_property (gobject_class, PROP_DEVICE,
g_param_spec_object ("device", "Device",
"D3D11 Devicd to use", GST_TYPE_D3D11_DEVICE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
GST_DEBUG_CATEGORY_INIT (d3d11_decoder_debug,
"d3d11decoder", 0, "Direct3D11 Base Video Decoder object");
}
static void
gst_d3d11_decoder_init (GstD3D11Decoder * self)
{
self->priv = gst_d3d11_decoder_get_instance_private (self);
}
static void
gst_d3d11_decoder_constructed (GObject * object)
{
GstD3D11Decoder *self = GST_D3D11_DECODER (object);
GstD3D11DecoderPrivate *priv = self->priv;
HRESULT hr;
ID3D11Device *device_handle;
ID3D11DeviceContext *device_context_handle;
if (!priv->device) {
GST_ERROR_OBJECT (self, "No D3D11Device available");
return;
}
device_handle = gst_d3d11_device_get_device_handle (priv->device);
device_context_handle =
gst_d3d11_device_get_device_context_handle (priv->device);
hr = ID3D11Device_QueryInterface (device_handle, &IID_ID3D11VideoDevice,
(void **) &priv->video_device);
if (!gst_d3d11_result (hr, priv->device) || !priv->video_device) {
GST_WARNING_OBJECT (self, "Cannot create VideoDevice Object: 0x%x",
(guint) hr);
priv->video_device = NULL;
return;
}
hr = ID3D11DeviceContext_QueryInterface (device_context_handle,
&IID_ID3D11VideoContext, (void **) &priv->video_context);
if (!gst_d3d11_result (hr, priv->device) || !priv->video_context) {
GST_WARNING_OBJECT (self, "Cannot create VideoContext Object: 0x%x",
(guint) hr);
priv->video_context = NULL;
goto fail;
}
return;
fail:
if (priv->video_device) {
ID3D11VideoDevice_Release (priv->video_device);
priv->video_device = NULL;
}
if (priv->video_context) {
ID3D11VideoContext_Release (priv->video_context);
priv->video_context = NULL;
}
return;
}
static void
gst_d3d11_decoder_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstD3D11Decoder *self = GST_D3D11_DECODER (object);
GstD3D11DecoderPrivate *priv = self->priv;
switch (prop_id) {
case PROP_DEVICE:
priv->device = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_d3d11_decoder_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D11Decoder *self = GST_D3D11_DECODER (object);
GstD3D11DecoderPrivate *priv = self->priv;
switch (prop_id) {
case PROP_DEVICE:
g_value_set_object (value, priv->device);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_d3d11_decoder_close (GstD3D11Decoder * self)
{
GstD3D11DecoderPrivate *priv = self->priv;
gst_d3d11_decoder_reset (self);
if (priv->video_device) {
ID3D11VideoDevice_Release (priv->video_device);
priv->video_device = NULL;
}
if (priv->video_context) {
ID3D11VideoContext_Release (priv->video_context);
priv->video_context = NULL;
}
return TRUE;
}
static void
gst_d3d11_decoder_reset_unlocked (GstD3D11Decoder * decoder)
{
GstD3D11DecoderPrivate *priv;
priv = decoder->priv;
gst_clear_object (&priv->internal_pool);
if (priv->decoder) {
ID3D11VideoDecoder_Release (priv->decoder);
priv->decoder = NULL;
}
if (priv->staging) {
ID3D11Texture2D_Release (priv->staging);
priv->staging = NULL;
}
decoder->opened = FALSE;
}
void
gst_d3d11_decoder_reset (GstD3D11Decoder * decoder)
{
GstD3D11DecoderPrivate *priv;
g_return_if_fail (GST_IS_D3D11_DECODER (decoder));
priv = decoder->priv;
gst_d3d11_device_lock (priv->device);
gst_d3d11_decoder_reset_unlocked (decoder);
gst_d3d11_device_unlock (priv->device);
}
static void
gst_d3d11_decoder_dispose (GObject * obj)
{
GstD3D11Decoder *self = GST_D3D11_DECODER (obj);
GstD3D11DecoderPrivate *priv = self->priv;
if (priv->device) {
gst_d3d11_decoder_close (self);
gst_object_unref (priv->device);
priv->device = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (obj);
}
GstD3D11Decoder *
gst_d3d11_decoder_new (GstD3D11Device * device)
{
GstD3D11Decoder *decoder;
GstD3D11DecoderPrivate *priv;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
decoder = g_object_new (GST_TYPE_D3D11_DECODER, "device", device, NULL);
priv = decoder->priv;
if (!priv->video_device || !priv->video_context) {
gst_object_unref (decoder);
return NULL;
}
gst_object_ref_sink (decoder);
return decoder;
}
static void
gst_d3d11_decoder_output_view_free (GstD3D11DecoderOutputView * view)
{
GST_DEBUG_OBJECT (view->device, "Free view %p", view);
if (view->handle) {
gst_d3d11_device_lock (view->device);
ID3D11VideoDecoderOutputView_Release (view->handle);
gst_d3d11_device_unlock (view->device);
}
gst_clear_object (&view->device);
g_free (view);
}
static gboolean
gst_d3d11_decoder_ensure_output_view (GstD3D11Decoder * self,
GstBuffer * buffer)
{
GstD3D11DecoderPrivate *priv = self->priv;
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc = { 0, };
GstD3D11Memory *mem;
GstD3D11DecoderOutputView *view;
ID3D11VideoDecoderOutputView *view_handle;
HRESULT hr;
mem = (GstD3D11Memory *) gst_buffer_peek_memory (buffer, 0);
view = (GstD3D11DecoderOutputView *)
gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
if (view)
return TRUE;
view_desc.DecodeProfile = priv->decoder_profile;
view_desc.ViewDimension = D3D11_VDOV_DIMENSION_TEXTURE2D;
view_desc.Texture2D.ArraySlice = mem->subresource_index;
GST_LOG_OBJECT (self,
"Create decoder output view with index %d", mem->subresource_index);
hr = ID3D11VideoDevice_CreateVideoDecoderOutputView (priv->video_device,
(ID3D11Resource *) mem->texture, &view_desc, &view_handle);
if (!gst_d3d11_result (hr, priv->device)) {
GST_ERROR_OBJECT (self,
"Could not create decoder output view, hr: 0x%x", (guint) hr);
return FALSE;
}
view = g_new0 (GstD3D11DecoderOutputView, 1);
view->device = gst_object_ref (priv->device);
view->handle = view_handle;
view->view_id = mem->subresource_index;
gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK,
view, (GDestroyNotify) gst_d3d11_decoder_output_view_free);
return TRUE;
}
/* Must be called from D3D11Device thread */
static gboolean
gst_d3d11_decoder_prepare_output_view_pool (GstD3D11Decoder * self,
GstVideoInfo * info, guint coded_width, guint coded_height,
guint pool_size, const GUID * decoder_profile)
{
GstD3D11DecoderPrivate *priv = self->priv;
GstD3D11AllocationParams *alloc_params = NULL;
GstBufferPool *pool = NULL;
GstStructure *config = NULL;
GstCaps *caps = NULL;
GstVideoAlignment align;
gst_clear_object (&priv->internal_pool);
alloc_params = gst_d3d11_allocation_params_new (priv->device, info,
GST_D3D11_ALLOCATION_FLAG_TEXTURE_ARRAY, D3D11_BIND_DECODER);
if (!alloc_params) {
GST_ERROR_OBJECT (self, "Failed to create allocation param");
goto error;
}
alloc_params->desc[0].ArraySize = pool_size;
gst_video_alignment_reset (&align);
align.padding_right = coded_width - GST_VIDEO_INFO_WIDTH (info);
align.padding_bottom = coded_height - GST_VIDEO_INFO_HEIGHT (info);
if (!gst_d3d11_allocation_params_alignment (alloc_params, &align)) {
GST_ERROR_OBJECT (self, "Cannot set alignment");
return FALSE;
}
pool = gst_d3d11_buffer_pool_new (priv->device);
if (!pool) {
GST_ERROR_OBJECT (self, "Failed to create buffer pool");
goto error;
}
/* Setup buffer pool */
config = gst_buffer_pool_get_config (pool);
caps = gst_video_info_to_caps (info);
if (!caps) {
GST_ERROR_OBJECT (self, "Couldn't convert video info to caps");
goto error;
}
gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (info),
0, pool_size);
gst_buffer_pool_config_set_d3d11_allocation_params (config, alloc_params);
gst_caps_unref (caps);
gst_d3d11_allocation_params_free (alloc_params);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
if (!gst_buffer_pool_set_config (pool, config)) {
GST_ERROR_OBJECT (self, "Invalid pool config");
goto error;
}
if (!gst_buffer_pool_set_active (pool, TRUE)) {
GST_ERROR_OBJECT (self, "Couldn't activate pool");
goto error;
}
priv->internal_pool = pool;
return TRUE;
error:
if (alloc_params)
gst_d3d11_allocation_params_free (alloc_params);
if (pool)
gst_object_unref (pool);
if (caps)
gst_caps_unref (caps);
return FALSE;
}
gboolean
gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Decoder * decoder,
const GUID ** decoder_profiles, guint profile_size, GUID * selected_profile)
{
GstD3D11DecoderPrivate *priv;
GUID *guid_list = NULL;
const GUID *profile = NULL;
guint available_profile_count;
gint i, j;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (decoder_profiles != NULL, FALSE);
g_return_val_if_fail (profile_size > 0, FALSE);
g_return_val_if_fail (selected_profile != NULL, FALSE);
priv = decoder->priv;
available_profile_count =
ID3D11VideoDevice_GetVideoDecoderProfileCount (priv->video_device);
if (available_profile_count == 0) {
GST_WARNING_OBJECT (decoder, "No available decoder profile");
return FALSE;
}
GST_DEBUG_OBJECT (decoder,
"Have %u available decoder profiles", available_profile_count);
guid_list = g_alloca (sizeof (GUID) * available_profile_count);
for (i = 0; i < available_profile_count; i++) {
hr = ID3D11VideoDevice_GetVideoDecoderProfile (priv->video_device,
i, &guid_list[i]);
if (!gst_d3d11_result (hr, priv->device)) {
GST_WARNING_OBJECT (decoder, "Failed to get %d th decoder profile", i);
return FALSE;
}
}
#ifndef GST_DISABLE_GST_DEBUG
GST_LOG_OBJECT (decoder, "Supported decoder GUID");
for (i = 0; i < available_profile_count; i++) {
const GUID *guid = &guid_list[i];
GST_LOG_OBJECT (decoder,
"\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
(guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
GST_LOG_OBJECT (decoder, "Requested decoder GUID");
for (i = 0; i < profile_size; i++) {
const GUID *guid = decoder_profiles[i];
GST_LOG_OBJECT (decoder,
"\t { %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
(guint) guid->Data1, (guint) guid->Data2, (guint) guid->Data3,
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
}
#endif
for (i = 0; i < profile_size; i++) {
for (j = 0; j < available_profile_count; j++) {
if (IsEqualGUID (decoder_profiles[i], &guid_list[j])) {
profile = decoder_profiles[i];
break;
}
}
}
if (!profile) {
GST_WARNING_OBJECT (decoder, "No supported decoder profile");
return FALSE;
}
*selected_profile = *profile;
GST_DEBUG_OBJECT (decoder,
"Selected guid "
"{ %8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x }",
(guint) selected_profile->Data1, (guint) selected_profile->Data2,
(guint) selected_profile->Data3,
selected_profile->Data4[0], selected_profile->Data4[1],
selected_profile->Data4[2], selected_profile->Data4[3],
selected_profile->Data4[4], selected_profile->Data4[5],
selected_profile->Data4[6], selected_profile->Data4[7]);
return TRUE;
}
gboolean
gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
GstVideoInfo * info, guint coded_width, guint coded_height,
guint pool_size, const GUID ** decoder_profiles, guint profile_size)
{
GstD3D11DecoderPrivate *priv;
const GstD3D11Format *d3d11_format;
HRESULT hr;
BOOL can_support = FALSE;
guint config_count;
D3D11_VIDEO_DECODER_CONFIG *config_list;
D3D11_VIDEO_DECODER_CONFIG *best_config = NULL;
D3D11_VIDEO_DECODER_DESC decoder_desc = { 0, };
D3D11_TEXTURE2D_DESC staging_desc = { 0, };
GUID selected_profile;
gint i;
guint aligned_width, aligned_height;
guint alignment;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (codec > GST_D3D11_CODEC_NONE, FALSE);
g_return_val_if_fail (codec < GST_D3D11_CODEC_LAST, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (coded_width >= GST_VIDEO_INFO_WIDTH (info), FALSE);
g_return_val_if_fail (coded_height >= GST_VIDEO_INFO_HEIGHT (info), FALSE);
g_return_val_if_fail (pool_size > 0, FALSE);
g_return_val_if_fail (decoder_profiles != NULL, FALSE);
g_return_val_if_fail (profile_size > 0, FALSE);
priv = decoder->priv;
decoder->opened = FALSE;
d3d11_format = gst_d3d11_device_format_from_gst (priv->device,
GST_VIDEO_INFO_FORMAT (info));
if (!d3d11_format || d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN) {
GST_ERROR_OBJECT (decoder, "Could not determine dxgi format from %s",
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
return FALSE;
}
gst_d3d11_device_lock (priv->device);
if (!gst_d3d11_decoder_get_supported_decoder_profile (decoder,
decoder_profiles, profile_size, &selected_profile)) {
goto error;
}
hr = ID3D11VideoDevice_CheckVideoDecoderFormat (priv->video_device,
&selected_profile, d3d11_format->dxgi_format, &can_support);
if (!gst_d3d11_result (hr, priv->device) || !can_support) {
GST_ERROR_OBJECT (decoder,
"VideoDevice could not support dxgi format %d, hr: 0x%x",
d3d11_format->dxgi_format, (guint) hr);
goto error;
}
gst_d3d11_decoder_reset_unlocked (decoder);
/* NOTE: other dxva implementations (ffmpeg and vlc) do this
* and they say the required alignment were mentioned by dxva spec.
* See ff_dxva2_common_frame_params() in dxva.c of ffmpeg and
* directx_va_Setup() in directx_va.c of vlc.
* But... where it is? */
switch (codec) {
case GST_D3D11_CODEC_H265:
alignment = 128;
break;
default:
alignment = 16;
break;
}
aligned_width = GST_ROUND_UP_N (coded_width, alignment);
aligned_height = GST_ROUND_UP_N (coded_height, alignment);
if (aligned_width != coded_width || aligned_height != coded_height) {
GST_DEBUG_OBJECT (decoder,
"coded resolution %dx%d is not aligned to %d, adjust to %dx%d",
coded_width, coded_height, alignment, aligned_width, aligned_height);
}
decoder_desc.SampleWidth = aligned_width;
decoder_desc.SampleHeight = aligned_height;
decoder_desc.OutputFormat = d3d11_format->dxgi_format;
decoder_desc.Guid = selected_profile;
hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device,
&decoder_desc, &config_count);
if (!gst_d3d11_result (hr, priv->device) || config_count == 0) {
GST_ERROR_OBJECT (decoder, "Could not get decoder config count, hr: 0x%x",
(guint) hr);
goto error;
}
GST_DEBUG_OBJECT (decoder, "Total %d config available", config_count);
config_list = g_alloca (sizeof (D3D11_VIDEO_DECODER_CONFIG) * config_count);
for (i = 0; i < config_count; i++) {
hr = ID3D11VideoDevice_GetVideoDecoderConfig (priv->video_device,
&decoder_desc, i, &config_list[i]);
if (!gst_d3d11_result (hr, priv->device)) {
GST_ERROR_OBJECT (decoder, "Could not get decoder %dth config, hr: 0x%x",
i, (guint) hr);
goto error;
}
/* FIXME: need support DXVA_Slice_H264_Long ?? */
/* this config uses DXVA_Slice_H264_Short */
if (codec == GST_D3D11_CODEC_H264 && config_list[i].ConfigBitstreamRaw == 2) {
best_config = &config_list[i];
break;
}
if ((codec == GST_D3D11_CODEC_VP9 || codec == GST_D3D11_CODEC_H265)
&& config_list[i].ConfigBitstreamRaw == 1) {
best_config = &config_list[i];
break;
}
}
if (best_config == NULL) {
GST_ERROR_OBJECT (decoder, "Could not determine decoder config");
goto error;
}
if (!gst_d3d11_decoder_prepare_output_view_pool (decoder,
info, aligned_width, aligned_height, pool_size, &selected_profile)) {
GST_ERROR_OBJECT (decoder, "Couldn't prepare output view pool");
goto error;
}
hr = ID3D11VideoDevice_CreateVideoDecoder (priv->video_device,
&decoder_desc, best_config, &priv->decoder);
if (!gst_d3d11_result (hr, priv->device) || !priv->decoder) {
GST_ERROR_OBJECT (decoder,
"Could not create decoder object, hr: 0x%x", (guint) hr);
goto error;
}
GST_DEBUG_OBJECT (decoder, "Decoder object %p created", priv->decoder);
/* create stage texture to copy out */
staging_desc.Width = aligned_width;
staging_desc.Height = aligned_height;
staging_desc.MipLevels = 1;
staging_desc.Format = d3d11_format->dxgi_format;
staging_desc.SampleDesc.Count = 1;
staging_desc.ArraySize = 1;
staging_desc.Usage = D3D11_USAGE_STAGING;
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
priv->staging = gst_d3d11_device_create_texture (priv->device,
&staging_desc, NULL);
if (!priv->staging) {
GST_ERROR_OBJECT (decoder, "Couldn't create staging texture");
goto error;
}
memset (priv->staging_texture_offset,
0, sizeof (priv->staging_texture_offset));
memset (priv->stating_texture_stride,
0, sizeof (priv->stating_texture_stride));
priv->decoder_profile = selected_profile;
decoder->opened = TRUE;
gst_d3d11_device_unlock (priv->device);
return TRUE;
error:
gst_d3d11_device_unlock (priv->device);
return FALSE;
}
gboolean
gst_d3d11_decoder_begin_frame (GstD3D11Decoder * decoder,
GstD3D11DecoderOutputView * output_view, guint content_key_size,
gconstpointer content_key)
{
GstD3D11DecoderPrivate *priv;
guint retry_count = 0;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (output_view != NULL, FALSE);
g_return_val_if_fail (output_view->handle != NULL, FALSE);
priv = decoder->priv;
do {
GST_LOG_OBJECT (decoder, "Try begin frame, retry count %d", retry_count);
gst_d3d11_device_lock (priv->device);
hr = ID3D11VideoContext_DecoderBeginFrame (priv->video_context,
priv->decoder, output_view->handle, content_key_size, content_key);
gst_d3d11_device_unlock (priv->device);
if (hr == E_PENDING && retry_count < 50) {
GST_LOG_OBJECT (decoder, "GPU busy, try again");
/* HACK: no better idea other than sleep...
* 1ms waiting like msdkdec */
g_usleep (1000);
} else {
if (gst_d3d11_result (hr, priv->device))
GST_LOG_OBJECT (decoder, "Success with retry %d", retry_count);
break;
}
retry_count++;
} while (TRUE);
if (!gst_d3d11_result (hr, priv->device)) {
GST_ERROR_OBJECT (decoder, "Failed to begin frame, hr: 0x%x", (guint) hr);
return FALSE;
}
return TRUE;
}
gboolean
gst_d3d11_decoder_end_frame (GstD3D11Decoder * decoder)
{
GstD3D11DecoderPrivate *priv;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
priv = decoder->priv;
gst_d3d11_device_lock (priv->device);
hr = ID3D11VideoContext_DecoderEndFrame (priv->video_context, priv->decoder);
gst_d3d11_device_unlock (priv->device);
if (!gst_d3d11_result (hr, priv->device)) {
GST_WARNING_OBJECT (decoder, "EndFrame failed, hr: 0x%x", (guint) hr);
return FALSE;
}
return TRUE;
}
gboolean
gst_d3d11_decoder_get_decoder_buffer (GstD3D11Decoder * decoder,
D3D11_VIDEO_DECODER_BUFFER_TYPE type, guint * buffer_size,
gpointer * buffer)
{
GstD3D11DecoderPrivate *priv;
UINT size;
void *decoder_buffer;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
priv = decoder->priv;
gst_d3d11_device_lock (priv->device);
hr = ID3D11VideoContext_GetDecoderBuffer (priv->video_context,
priv->decoder, type, &size, &decoder_buffer);
gst_d3d11_device_unlock (priv->device);
if (!gst_d3d11_result (hr, priv->device)) {
GST_WARNING_OBJECT (decoder, "Getting buffer type %d error, hr: 0x%x",
type, (guint) hr);
return FALSE;
}
*buffer_size = size;
*buffer = decoder_buffer;
return TRUE;
}
gboolean
gst_d3d11_decoder_release_decoder_buffer (GstD3D11Decoder * decoder,
D3D11_VIDEO_DECODER_BUFFER_TYPE type)
{
GstD3D11DecoderPrivate *priv;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
priv = decoder->priv;
gst_d3d11_device_lock (priv->device);
hr = ID3D11VideoContext_ReleaseDecoderBuffer (priv->video_context,
priv->decoder, type);
gst_d3d11_device_unlock (priv->device);
if (!gst_d3d11_result (hr, priv->device)) {
GST_WARNING_OBJECT (decoder, "ReleaseDecoderBuffer failed, hr: 0x%x",
(guint) hr);
return FALSE;
}
return TRUE;
}
gboolean
gst_d3d11_decoder_submit_decoder_buffers (GstD3D11Decoder * decoder,
guint buffer_count, const D3D11_VIDEO_DECODER_BUFFER_DESC * buffers)
{
GstD3D11DecoderPrivate *priv;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
priv = decoder->priv;
gst_d3d11_device_lock (priv->device);
hr = ID3D11VideoContext_SubmitDecoderBuffers (priv->video_context,
priv->decoder, buffer_count, buffers);
gst_d3d11_device_unlock (priv->device);
if (!gst_d3d11_result (hr, priv->device)) {
GST_WARNING_OBJECT (decoder, "SubmitDecoderBuffers failed, hr: 0x%x",
(guint) hr);
return FALSE;
}
return TRUE;
}
GstBuffer *
gst_d3d11_decoder_get_output_view_buffer (GstD3D11Decoder * decoder)
{
GstD3D11DecoderPrivate *priv;
GstBuffer *buf = NULL;
GstFlowReturn ret;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
priv = decoder->priv;
ret = gst_buffer_pool_acquire_buffer (priv->internal_pool, &buf, NULL);
if (ret != GST_FLOW_OK || !buf) {
GST_ERROR_OBJECT (decoder, "Couldn't get buffer from pool, ret %s",
gst_flow_get_name (ret));
return NULL;
}
if (!gst_d3d11_decoder_ensure_output_view (decoder, buf)) {
GST_ERROR_OBJECT (decoder, "Output view unavailable");
gst_buffer_unref (buf);
return NULL;
}
return buf;
}
GstD3D11DecoderOutputView *
gst_d3d11_decoder_get_output_view_from_buffer (GstD3D11Decoder * decoder,
GstBuffer * buffer)
{
GstMemory *mem;
GstD3D11DecoderOutputView *view;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), NULL);
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
mem = gst_buffer_peek_memory (buffer, 0);
if (!gst_is_d3d11_memory (mem)) {
GST_WARNING_OBJECT (decoder, "nemory is not d3d11 memory");
return NULL;
}
view = (GstD3D11DecoderOutputView *)
gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem), OUTPUT_VIEW_QUARK);
if (!view) {
GST_WARNING_OBJECT (decoder, "memory does not have output view");
}
return view;
}
guint
gst_d3d11_decoder_get_output_view_index (GstD3D11Decoder * decoder,
ID3D11VideoDecoderOutputView * view_handle)
{
D3D11_VIDEO_DECODER_OUTPUT_VIEW_DESC view_desc;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), 0xff);
g_return_val_if_fail (view_handle != NULL, 0xff);
ID3D11VideoDecoderOutputView_GetDesc (view_handle, &view_desc);
return view_desc.Texture2D.ArraySlice;
}
static gboolean
copy_to_system (GstD3D11Decoder * self, GstVideoInfo * info,
GstBuffer * decoder_buffer, GstBuffer * output)
{
GstD3D11DecoderPrivate *priv = self->priv;
GstVideoFrame out_frame;
gint i;
GstD3D11Memory *in_mem;
D3D11_MAPPED_SUBRESOURCE map;
HRESULT hr;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (priv->device);
if (!gst_video_frame_map (&out_frame, info, output, GST_MAP_WRITE)) {
GST_ERROR_OBJECT (self, "Couldn't map output buffer");
return FALSE;
}
in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, 0);
gst_d3d11_device_lock (priv->device);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
(ID3D11Resource *) priv->staging, 0, 0, 0, 0,
(ID3D11Resource *) in_mem->texture, in_mem->subresource_index, NULL);
hr = ID3D11DeviceContext_Map (device_context,
(ID3D11Resource *) priv->staging, 0, D3D11_MAP_READ, 0, &map);
if (!gst_d3d11_result (hr, priv->device)) {
GST_ERROR_OBJECT (self, "Failed to map, hr: 0x%x", (guint) hr);
gst_d3d11_device_unlock (priv->device);
return FALSE;
}
/* calculate stride and offset only once */
if (priv->stating_texture_stride[0] == 0) {
D3D11_TEXTURE2D_DESC desc;
gsize dummy;
ID3D11Texture2D_GetDesc (priv->staging, &desc);
gst_d3d11_dxgi_format_get_size (desc.Format, desc.Width, desc.Height,
map.RowPitch, priv->staging_texture_offset,
priv->stating_texture_stride, &dummy);
}
for (i = 0; i < GST_VIDEO_FRAME_N_PLANES (&out_frame); i++) {
guint8 *src, *dst;
gint j;
gint width;
src = (guint8 *) map.pData + priv->staging_texture_offset[i];
dst = GST_VIDEO_FRAME_PLANE_DATA (&out_frame, i);
width = GST_VIDEO_FRAME_COMP_WIDTH (&out_frame, i) *
GST_VIDEO_FRAME_COMP_PSTRIDE (&out_frame, i);
for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (&out_frame, i); j++) {
memcpy (dst, src, width);
dst += GST_VIDEO_FRAME_PLANE_STRIDE (&out_frame, i);
src += priv->stating_texture_stride[i];
}
}
gst_video_frame_unmap (&out_frame);
ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) priv->staging,
0);
gst_d3d11_device_unlock (priv->device);
return TRUE;
}
static gboolean
copy_to_d3d11 (GstD3D11Decoder * self, GstVideoInfo * info,
GstBuffer * decoder_buffer, GstBuffer * output)
{
GstD3D11DecoderPrivate *priv = self->priv;
gint i;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (priv->device);
gst_d3d11_device_lock (priv->device);
for (i = 0; i < gst_buffer_n_memory (output); i++) {
GstD3D11Memory *in_mem;
GstD3D11Memory *out_mem;
D3D11_BOX src_box;
D3D11_TEXTURE2D_DESC desc;
in_mem = (GstD3D11Memory *) gst_buffer_peek_memory (decoder_buffer, i);
out_mem = (GstD3D11Memory *) gst_buffer_peek_memory (output, i);
ID3D11Texture2D_GetDesc (out_mem->texture, &desc);
src_box.left = 0;
src_box.top = 0;
src_box.front = 0;
src_box.back = 1;
src_box.right = desc.Width;
src_box.bottom = desc.Height;
ID3D11DeviceContext_CopySubresourceRegion (device_context,
(ID3D11Resource *) out_mem->texture,
out_mem->subresource_index, 0, 0, 0,
(ID3D11Resource *) in_mem->texture, in_mem->subresource_index,
&src_box);
GST_MINI_OBJECT_FLAG_SET (out_mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
gst_d3d11_device_unlock (priv->device);
return TRUE;
}
gboolean
gst_d3d11_decoder_copy_decoder_buffer (GstD3D11Decoder * decoder,
GstVideoInfo * info, GstBuffer * decoder_buffer, GstBuffer * output)
{
GstD3D11DecoderPrivate *priv;
gboolean can_device_copy = TRUE;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (decoder_buffer), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (output), FALSE);
priv = decoder->priv;
if (gst_buffer_n_memory (decoder_buffer) == gst_buffer_n_memory (output)) {
gint i;
for (i = 0; i < gst_buffer_n_memory (output); i++) {
GstMemory *mem;
GstD3D11Memory *dmem;
mem = gst_buffer_peek_memory (output, i);
if (!gst_is_d3d11_memory (mem)) {
can_device_copy = FALSE;
break;
}
dmem = (GstD3D11Memory *) mem;
if (dmem->device != priv->device) {
can_device_copy = FALSE;
break;
}
}
} else {
can_device_copy = FALSE;
}
if (can_device_copy) {
return copy_to_d3d11 (decoder, info, decoder_buffer, output);
}
return copy_to_system (decoder, info, decoder_buffer, output);
}
static const gchar *
gst_d3d11_decoder_status_code_to_verbose_string (guint status_code)
{
const gchar *status = NULL;
switch (status_code) {
case 0:
status = "The operation succeeded";
break;
case 1:
status = "Minor problem in the data format. "
"The host decoder should continue processing";
break;
case 2:
status = "Significant problem in the data format. The host decoder may "
"continue executing or skip the display of the output picture";
break;
case 3:
status = "Severe problem in the data format. The host decoder should "
"restart the entire decoding process, starting at a sequence or "
"random-access entry point";
break;
case 4:
status =
"Other severe problem. The host decoder should restart the entire "
"decoding process, starting at a sequence or random-access entry point";
break;
default:
status = "Unknown status";
break;
}
return status;
}
gboolean
gst_d3d11_decoder_get_status_report (GstD3D11Decoder * decoder,
GstDXVAStatus * status, GError ** err)
{
GstD3D11DecoderPrivate *priv;
HRESULT hr;
D3D11_VIDEO_DECODER_EXTENSION extension = { 0, };
gboolean ret;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (status != NULL, FALSE);
priv = decoder->priv;
/* For status report */
extension.Function = 7;
extension.pPrivateOutputData = (PVOID) status;
extension.PrivateOutputDataSize = sizeof (GstDXVAStatus);
gst_d3d11_device_lock (priv->device);
hr = ID3D11VideoContext_DecoderExtension (priv->video_context, priv->decoder,
&extension);
gst_d3d11_device_unlock (priv->device);
ret = gst_d3d11_result (hr, priv->device);
if (ret && status->bStatus != 0) {
/* TODO: if status code is 3 or 4, we might need to restart decoding
* from new keyframe */
GST_WARNING_OBJECT (decoder,
"Status code: %d, StatusReportFeedbackNumber: %d, "
"CurrPic.Index7Bits: %d, CurrPic.AssociatedFlag: %d, bBufType: %d, "
"wNumMbsAffected: %d", status->bStatus,
status->StatusReportFeedbackNumber,
status->CurrPic.Index7Bits, status->CurrPic.AssociatedFlag,
status->bBufType, status->wNumMbsAffected);
if (status->bStatus > 1) {
const gchar *status_str =
gst_d3d11_decoder_status_code_to_verbose_string (status->bStatus);
g_set_error_literal (err, GST_STREAM_ERROR,
GST_STREAM_ERROR_DECODE, status_str);
}
}
return ret;
}
/* Keep sync with chromium and keep in sorted order.
* See supported_profile_helpers.cc in chromium */
static const guint legacy_amd_list[] = {
0x130f, 0x6700, 0x6701, 0x6702, 0x6703, 0x6704, 0x6705, 0x6706, 0x6707,
0x6708, 0x6709, 0x6718, 0x6719, 0x671c, 0x671d, 0x671f, 0x6720, 0x6721,
0x6722, 0x6723, 0x6724, 0x6725, 0x6726, 0x6727, 0x6728, 0x6729, 0x6738,
0x6739, 0x673e, 0x6740, 0x6741, 0x6742, 0x6743, 0x6744, 0x6745, 0x6746,
0x6747, 0x6748, 0x6749, 0x674a, 0x6750, 0x6751, 0x6758, 0x6759, 0x675b,
0x675d, 0x675f, 0x6760, 0x6761, 0x6762, 0x6763, 0x6764, 0x6765, 0x6766,
0x6767, 0x6768, 0x6770, 0x6771, 0x6772, 0x6778, 0x6779, 0x677b, 0x6798,
0x67b1, 0x6821, 0x683d, 0x6840, 0x6841, 0x6842, 0x6843, 0x6849, 0x6850,
0x6858, 0x6859, 0x6880, 0x6888, 0x6889, 0x688a, 0x688c, 0x688d, 0x6898,
0x6899, 0x689b, 0x689c, 0x689d, 0x689e, 0x68a0, 0x68a1, 0x68a8, 0x68a9,
0x68b0, 0x68b8, 0x68b9, 0x68ba, 0x68be, 0x68bf, 0x68c0, 0x68c1, 0x68c7,
0x68c8, 0x68c9, 0x68d8, 0x68d9, 0x68da, 0x68de, 0x68e0, 0x68e1, 0x68e4,
0x68e5, 0x68e8, 0x68e9, 0x68f1, 0x68f2, 0x68f8, 0x68f9, 0x68fa, 0x68fe,
0x9400, 0x9401, 0x9402, 0x9403, 0x9405, 0x940a, 0x940b, 0x940f, 0x9440,
0x9441, 0x9442, 0x9443, 0x9444, 0x9446, 0x944a, 0x944b, 0x944c, 0x944e,
0x9450, 0x9452, 0x9456, 0x945a, 0x945b, 0x945e, 0x9460, 0x9462, 0x946a,
0x946b, 0x947a, 0x947b, 0x9480, 0x9487, 0x9488, 0x9489, 0x948a, 0x948f,
0x9490, 0x9491, 0x9495, 0x9498, 0x949c, 0x949e, 0x949f, 0x94a0, 0x94a1,
0x94a3, 0x94b1, 0x94b3, 0x94b4, 0x94b5, 0x94b9, 0x94c0, 0x94c1, 0x94c3,
0x94c4, 0x94c5, 0x94c6, 0x94c7, 0x94c8, 0x94c9, 0x94cb, 0x94cc, 0x94cd,
0x9500, 0x9501, 0x9504, 0x9505, 0x9506, 0x9507, 0x9508, 0x9509, 0x950f,
0x9511, 0x9515, 0x9517, 0x9519, 0x9540, 0x9541, 0x9542, 0x954e, 0x954f,
0x9552, 0x9553, 0x9555, 0x9557, 0x955f, 0x9580, 0x9581, 0x9583, 0x9586,
0x9587, 0x9588, 0x9589, 0x958a, 0x958b, 0x958c, 0x958d, 0x958e, 0x958f,
0x9590, 0x9591, 0x9593, 0x9595, 0x9596, 0x9597, 0x9598, 0x9599, 0x959b,
0x95c0, 0x95c2, 0x95c4, 0x95c5, 0x95c6, 0x95c7, 0x95c9, 0x95cc, 0x95cd,
0x95ce, 0x95cf, 0x9610, 0x9611, 0x9612, 0x9613, 0x9614, 0x9615, 0x9616,
0x9640, 0x9641, 0x9642, 0x9643, 0x9644, 0x9645, 0x9647, 0x9648, 0x9649,
0x964a, 0x964b, 0x964c, 0x964e, 0x964f, 0x9710, 0x9711, 0x9712, 0x9713,
0x9714, 0x9715, 0x9802, 0x9803, 0x9804, 0x9805, 0x9806, 0x9807, 0x9808,
0x9809, 0x980a, 0x9830, 0x983d, 0x9850, 0x9851, 0x9874, 0x9900, 0x9901,
0x9903, 0x9904, 0x9905, 0x9906, 0x9907, 0x9908, 0x9909, 0x990a, 0x990b,
0x990c, 0x990d, 0x990e, 0x990f, 0x9910, 0x9913, 0x9917, 0x9918, 0x9919,
0x9990, 0x9991, 0x9992, 0x9993, 0x9994, 0x9995, 0x9996, 0x9997, 0x9998,
0x9999, 0x999a, 0x999b, 0x999c, 0x999d, 0x99a0, 0x99a2, 0x99a4
};
static const guint legacy_intel_list[] = {
0x102, 0x106, 0x116, 0x126, 0x152, 0x156, 0x166,
0x402, 0x406, 0x416, 0x41e, 0xa06, 0xa16, 0xf31,
};
static gint
binary_search_compare (const guint * a, const guint * b)
{
return *a - *b;
}
/* Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and some second
* generation Intel GPU drivers crash if we create a video device with a
* resolution higher then 1920 x 1088. This function checks if the GPU is in
* this list and if yes returns true. */
gboolean
gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device)
{
const guint amd_id[] = { 0x1002, 0x1022 };
const guint intel_id = 0x8086;
guint device_id = 0;
guint vendor_id = 0;
guint *match = NULL;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), FALSE);
g_object_get (device, "device-id", &device_id, "vendor-id", &vendor_id, NULL);
if (vendor_id == amd_id[0] || vendor_id == amd_id[1]) {
match =
(guint *) gst_util_array_binary_search ((gpointer) legacy_amd_list,
G_N_ELEMENTS (legacy_amd_list), sizeof (guint),
(GCompareDataFunc) binary_search_compare,
GST_SEARCH_MODE_EXACT, &device_id, NULL);
} else if (vendor_id == intel_id) {
match =
(guint *) gst_util_array_binary_search ((gpointer) legacy_intel_list,
G_N_ELEMENTS (legacy_intel_list), sizeof (guint),
(GCompareDataFunc) binary_search_compare,
GST_SEARCH_MODE_EXACT, &device_id, NULL);
}
if (match) {
GST_DEBUG_OBJECT (device, "it's legacy device");
return TRUE;
}
return FALSE;
}
gboolean
gst_d3d11_decoder_supports_format (GstD3D11Decoder * decoder,
const GUID * decoder_profile, DXGI_FORMAT format)
{
GstD3D11DecoderPrivate *priv;
HRESULT hr;
BOOL can_support = FALSE;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (decoder_profile != NULL, FALSE);
g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
priv = decoder->priv;
hr = ID3D11VideoDevice_CheckVideoDecoderFormat (priv->video_device,
decoder_profile, format, &can_support);
if (!gst_d3d11_result (hr, priv->device) || !can_support) {
GST_DEBUG_OBJECT (decoder,
"VideoDevice could not support dxgi format %d, hr: 0x%x",
format, (guint) hr);
return FALSE;
}
return TRUE;
}
/* Don't call this method with legacy device */
gboolean
gst_d3d11_decoder_supports_resolution (GstD3D11Decoder * decoder,
const GUID * decoder_profile, DXGI_FORMAT format, guint width, guint height)
{
D3D11_VIDEO_DECODER_DESC desc;
GstD3D11DecoderPrivate *priv;
HRESULT hr;
UINT config_count;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE);
g_return_val_if_fail (decoder_profile != NULL, FALSE);
g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
priv = decoder->priv;
desc.SampleWidth = width;
desc.SampleHeight = height;
desc.OutputFormat = format;
desc.Guid = *decoder_profile;
hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device,
&desc, &config_count);
if (!gst_d3d11_result (hr, priv->device) || config_count == 0) {
GST_DEBUG_OBJECT (decoder, "Could not get decoder config count, hr: 0x%x",
(guint) hr);
return FALSE;
}
return TRUE;
}
/**
* gst_d3d11_decoder_class_data_new:
* @device: (transfer none): a #GstD3D11Device
* @sink_caps: (transfer full): a #GstCaps
* @src_caps: (transfer full): a #GstCaps
*
* Create new #GstD3D11DecoderClassData
*
* Returns: (transfer full): the new #GstD3D11DecoderClassData
*/
GstD3D11DecoderClassData *
gst_d3d11_decoder_class_data_new (GstD3D11Device * device,
GstCaps * sink_caps, GstCaps * src_caps)
{
GstD3D11DecoderClassData *ret;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
g_return_val_if_fail (sink_caps != NULL, NULL);
g_return_val_if_fail (src_caps != NULL, NULL);
ret = g_new0 (GstD3D11DecoderClassData, 1);
/* class data will be leaked if the element never gets instantiated */
GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
g_object_get (device, "adapter", &ret->adapter,
"device-id", &ret->device_id, "vendor-id", &ret->vendor_id,
"description", &ret->description, NULL);
ret->sink_caps = sink_caps;
ret->src_caps = src_caps;
return ret;
}
void
gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data)
{
if (!data)
return;
gst_clear_caps (&data->sink_caps);
gst_clear_caps (&data->src_caps);
g_free (data->description);
g_free (data);
}