d3d11decoder: Register elements per GPU device with capability check

This implementation is similar to what we've done for nvcodec plugin.
Since supported resolution, profiles, and formats are device dependent ones,
single template caps cannot represent them, so this modification
will help autoplugging and fallback.

Note that the legacy gpu list and list of resolution to query were
taken from chromium's code.
This commit is contained in:
Seungha Yang 2020-02-15 01:23:32 +09:00 committed by GStreamer Merge Bot
parent 13586bc77a
commit fe72bf6053
10 changed files with 1105 additions and 488 deletions

View file

@ -87,15 +87,6 @@ typedef struct _GstD3D11Decoder GstD3D11Decoder;
typedef struct _GstD3D11DecoderClass GstD3D11DecoderClass;
typedef struct _GstD3D11DecoderPrivate GstD3D11DecoderPrivate;
typedef struct _GstD3D11H264Dec GstD3D11H264Dec;
typedef struct _GstD3D11H264DecClass GstD3D11H264DecClass;
typedef struct _GstD3D11Vp9Dec GstD3D11Vp9Dec;
typedef struct _GstD3D11Vp9DecClass GstD3D11Vp9DecClass;
typedef struct _GstD3D11H265Dec GstD3D11H265Dec;
typedef struct _GstD3D11H265DecClass GstD3D11H265DecClass;
G_END_DECLS
#endif /* __GST_D3D11_FWD_H__ */

View file

@ -15,6 +15,36 @@
* 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
@ -425,51 +455,29 @@ error:
}
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)
gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Decoder * decoder,
const GUID ** decoder_profiles, guint profile_size, GUID * selected_profile)
{
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, };
const GUID *selected_profile = NULL;
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 (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);
g_return_val_if_fail (selected_profile != NULL, 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);
available_profile_count =
ID3D11VideoDevice_GetVideoDecoderProfileCount (priv->video_device);
if (available_profile_count == 0) {
GST_ERROR_OBJECT (decoder, "No available decoder profile");
goto error;
GST_WARNING_OBJECT (decoder, "No available decoder profile");
return FALSE;
}
GST_DEBUG_OBJECT (decoder,
@ -480,8 +488,8 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
hr = ID3D11VideoDevice_GetVideoDecoderProfile (priv->video_device,
i, &guid_list[i]);
if (!gst_d3d11_result (hr, priv->device)) {
GST_ERROR_OBJECT (decoder, "Failed to get %d th decoder profile", i);
goto error;
GST_WARNING_OBJECT (decoder, "Failed to get %d th decoder profile", i);
return FALSE;
}
}
@ -512,29 +520,77 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
for (i = 0; i < profile_size; i++) {
for (j = 0; j < available_profile_count; j++) {
if (IsEqualGUID (decoder_profiles[i], &guid_list[j])) {
selected_profile = decoder_profiles[i];
profile = decoder_profiles[i];
break;
}
}
}
if (!selected_profile) {
GST_ERROR_OBJECT (decoder, "No supported decoder profile");
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, };
GUID selected_profile;
gint i;
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;
} else {
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]);
}
hr = ID3D11VideoDevice_CheckVideoDecoderFormat (priv->video_device,
selected_profile, d3d11_format->dxgi_format, &can_support);
&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",
@ -547,7 +603,7 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
decoder_desc.SampleWidth = coded_width;
decoder_desc.SampleHeight = coded_height;
decoder_desc.OutputFormat = d3d11_format->dxgi_format;
decoder_desc.Guid = *selected_profile;
decoder_desc.Guid = selected_profile;
hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device,
&decoder_desc, &config_count);
@ -590,7 +646,7 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
}
if (!gst_d3d11_decoder_prepare_output_view_pool (decoder,
info, coded_width, coded_height, pool_size, selected_profile)) {
info, coded_width, coded_height, pool_size, &selected_profile)) {
GST_ERROR_OBJECT (decoder, "Couldn't prepare output view pool");
goto error;
}
@ -635,7 +691,7 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
priv->staging_box.right = GST_VIDEO_INFO_WIDTH (info);
priv->staging_box.bottom = GST_VIDEO_INFO_HEIGHT (info);
priv->decoder_profile = *selected_profile;
priv->decoder_profile = selected_profile;
decoder->opened = TRUE;
gst_d3d11_device_unlock (priv->device);
@ -1017,3 +1073,199 @@ gst_d3d11_decoder_copy_decoder_buffer (GstD3D11Decoder * decoder,
return copy_to_system (decoder, info, decoder_buffer, output);
}
/* 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);
}

View file

@ -61,6 +61,16 @@ typedef enum
GST_D3D11_CODEC_LAST
} GstD3D11Codec;
typedef struct
{
GstCaps *sink_caps;
GstCaps *src_caps;
guint adapter;
guint device_id;
guint vendor_id;
gchar *description;
} GstD3D11DecoderClassData;
struct _GstD3D11Decoder
{
GstObject parent;
@ -125,6 +135,30 @@ gboolean gst_d3d11_decoder_copy_decoder_buffer (GstD3D11Decoder * decod
GstBuffer * decoder_buffer,
GstBuffer * output);
/* Utils for class registration */
gboolean gst_d3d11_decoder_util_is_legacy_device (GstD3D11Device * device);
gboolean gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Decoder * decoder,
const GUID ** decoder_profiles,
guint profile_size,
GUID * selected_profile);
gboolean gst_d3d11_decoder_supports_format (GstD3D11Decoder * decoder,
const GUID * decoder_profile,
DXGI_FORMAT format);
gboolean gst_d3d11_decoder_supports_resolution (GstD3D11Decoder * decoder,
const GUID * decoder_profile,
DXGI_FORMAT format,
guint width,
guint height);
GstD3D11DecoderClassData * gst_d3d11_decoder_class_data_new (GstD3D11Device * device,
GstCaps * sink_caps,
GstCaps * src_caps);
void gst_d3d11_decoder_class_data_free (GstD3D11DecoderClassData * data);
G_END_DECLS
#endif /* __GST_D3D11_DECODER_H__ */

View file

@ -51,6 +51,8 @@
#include <config.h>
#endif
#include "gsth264decoder.h"
#include "gsth264picture.h"
#include "gstd3d11h264dec.h"
#include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h"
@ -70,11 +72,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_h264_dec_debug);
enum
{
PROP_0,
PROP_ADAPTER
PROP_ADAPTER,
PROP_DEVICE_ID,
PROP_VENDOR_ID,
};
#define DEFAULT_ADAPTER -1
/* copied from d3d11.h since mingw header doesn't define them */
DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0x1b81be67, 0xa0c7,
0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);
@ -86,37 +88,53 @@ DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT, 0x1b81be69, 0xa0c7,
/* worst case 16 (non-interlaced) + 4 margin */
#define NUM_OUTPUT_VIEW 20
static GstStaticPadTemplate sink_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h264, "
"stream-format=(string) { avc, avc3, byte-stream }, "
"alignment=(string) au, profile = (string) { high, main }")
);
static GstStaticPadTemplate src_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME,
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, "{ NV12, P010_10LE }") "; "
GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }")));
struct _GstD3D11H264DecPrivate
typedef struct _GstD3D11H264Dec
{
/* Need to hide DXVA_PicEntry_H264 structure from header for UWP */
GstH264Decoder parent;
GstVideoCodecState *output_state;
GstD3D11Device *device;
guint width, height;
guint coded_width, coded_height;
guint bitdepth;
guint chroma_format_idc;
GstVideoFormat out_format;
/* Array of DXVA_Slice_H264_Short */
GArray *slice_list;
GstD3D11Decoder *d3d11_decoder;
/* Pointing current bitstream buffer */
guint current_offset;
guint bitstream_buffer_size;
guint8 *bitstream_buffer_bytes;
gboolean use_d3d11_output;
DXVA_PicEntry_H264 ref_frame_list[16];
INT field_order_cnt_list[16][2];
USHORT frame_num_list[16];
UINT used_for_reference_flags;
USHORT non_existing_frame_flags;
};
} GstD3D11H264Dec;
#define parent_class gst_d3d11_h264_dec_parent_class
G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11H264Dec,
gst_d3d11_h264_dec, GST_TYPE_H264_DECODER);
typedef struct _GstD3D11H264DecClass
{
GstH264DecoderClass parent_class;
guint adapter;
guint device_id;
guint vendor_id;
} GstD3D11H264DecClass;
static GstElementClass *parent_class = NULL;
#define GST_D3D11_H264_DEC(object) ((GstD3D11H264Dec *) (object))
#define GST_D3D11_H264_DEC_GET_CLASS(object) \
(G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstD3D11H264DecClass))
static void gst_d3d11_h264_dec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_d3d11_h264_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_d3d11_h264_dec_dispose (GObject * object);
@ -146,35 +164,56 @@ static gboolean gst_d3d11_h264_dec_end_picture (GstH264Decoder * decoder,
GstH264Picture * picture);
static void
gst_d3d11_h264_dec_class_init (GstD3D11H264DecClass * klass)
gst_d3d11_h264_dec_class_init (GstD3D11H264DecClass * klass, gpointer data)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstH264DecoderClass *h264decoder_class = GST_H264_DECODER_CLASS (klass);
GstD3D11DecoderClassData *cdata = (GstD3D11DecoderClassData *) data;
gchar *long_name;
gobject_class->set_property = gst_d3d11_h264_dec_set_property;
gobject_class->get_property = gst_d3d11_h264_dec_get_property;
gobject_class->dispose = gst_d3d11_h264_dec_dispose;
g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)",
-1, G_MAXINT32, DEFAULT_ADAPTER,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
g_param_spec_uint ("adapter", "Adapter",
"DXGI Adapter index for creating device",
0, G_MAXUINT32, cdata->adapter,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
g_param_spec_uint ("device-id", "Device Id",
"DXGI Device ID", 0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VENDOR_ID,
g_param_spec_uint ("vendor-id", "Vendor Id",
"DXGI Vendor ID", 0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
parent_class = g_type_class_peek_parent (klass);
klass->adapter = cdata->adapter;
klass->device_id = cdata->device_id;
klass->vendor_id = cdata->vendor_id;
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_set_context);
gst_element_class_set_static_metadata (element_class,
"Direct3D11 H.264 Video Decoder",
long_name = g_strdup_printf ("Direct3D11 H.264 %s Decoder",
cdata->description);
gst_element_class_set_metadata (element_class, long_name,
"Codec/Decoder/Video/Hardware",
"A Direct3D11 based H.264 video decoder",
"Seungha Yang <seungha.yang@navercorp.com>");
g_free (long_name);
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
cdata->sink_caps));
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
cdata->src_caps));
gst_d3d11_decoder_class_data_free (cdata);
decoder_class->open = GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_close);
@ -200,36 +239,24 @@ gst_d3d11_h264_dec_class_init (GstD3D11H264DecClass * klass)
static void
gst_d3d11_h264_dec_init (GstD3D11H264Dec * self)
{
self->priv = gst_d3d11_h264_dec_get_instance_private (self);
self->slice_list = g_array_new (FALSE, TRUE, sizeof (DXVA_Slice_H264_Short));
self->adapter = DEFAULT_ADAPTER;
}
static void
gst_d3d11_h264_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (object);
switch (prop_id) {
case PROP_ADAPTER:
self->adapter = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_d3d11_h264_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (object);
GstD3D11H264DecClass *klass = GST_D3D11_H264_DEC_GET_CLASS (object);
switch (prop_id) {
case PROP_ADAPTER:
g_value_set_int (value, self->adapter);
g_value_set_uint (value, klass->adapter);
break;
case PROP_DEVICE_ID:
g_value_set_uint (value, klass->device_id);
break;
case PROP_VENDOR_ID:
g_value_set_uint (value, klass->vendor_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -254,8 +281,10 @@ static void
gst_d3d11_h264_dec_set_context (GstElement * element, GstContext * context)
{
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (element);
GstD3D11H264DecClass *klass = GST_D3D11_H264_DEC_GET_CLASS (self);
gst_d3d11_handle_set_context (element, context, self->adapter, &self->device);
gst_d3d11_handle_set_context (element, context, klass->adapter,
&self->device);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
@ -264,8 +293,9 @@ static gboolean
gst_d3d11_h264_dec_open (GstVideoDecoder * decoder)
{
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
GstD3D11H264DecClass *klass = GST_D3D11_H264_DEC_GET_CLASS (self);
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), self->adapter,
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), klass->adapter,
&self->device)) {
GST_ERROR_OBJECT (self, "Cannot create d3d11device");
return FALSE;
@ -577,7 +607,6 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb)
{
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
GstD3D11H264DecPrivate *priv = self->priv;
GstD3D11DecoderOutputView *view;
gint i;
GArray *dpb_array;
@ -596,13 +625,13 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
}
for (i = 0; i < 16; i++) {
priv->ref_frame_list[i].bPicEntry = 0xFF;
priv->field_order_cnt_list[i][0] = 0;
priv->field_order_cnt_list[i][1] = 0;
priv->frame_num_list[i] = 0;
self->ref_frame_list[i].bPicEntry = 0xFF;
self->field_order_cnt_list[i][0] = 0;
self->field_order_cnt_list[i][1] = 0;
self->frame_num_list[i] = 0;
}
priv->used_for_reference_flags = 0;
priv->non_existing_frame_flags = 0;
self->used_for_reference_flags = 0;
self->non_existing_frame_flags = 0;
dpb_array = gst_h264_dpb_get_pictures_all (dpb);
@ -620,14 +649,14 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
if (other_view)
id = other_view->view_id;
priv->ref_frame_list[i].Index7Bits = id;
priv->ref_frame_list[i].AssociatedFlag = other->long_term;
priv->field_order_cnt_list[i][0] = other->top_field_order_cnt;
priv->field_order_cnt_list[i][1] = other->bottom_field_order_cnt;
priv->frame_num_list[i] = priv->ref_frame_list[i].AssociatedFlag
self->ref_frame_list[i].Index7Bits = id;
self->ref_frame_list[i].AssociatedFlag = other->long_term;
self->field_order_cnt_list[i][0] = other->top_field_order_cnt;
self->field_order_cnt_list[i][1] = other->bottom_field_order_cnt;
self->frame_num_list[i] = self->ref_frame_list[i].AssociatedFlag
? other->long_term_pic_num : other->frame_num;
priv->used_for_reference_flags |= ref << (2 * i);
priv->non_existing_frame_flags |= (other->nonexisting) << i;
self->used_for_reference_flags |= ref << (2 * i);
self->non_existing_frame_flags |= (other->nonexisting) << i;
}
g_array_unref (dpb_array);
@ -968,7 +997,6 @@ gst_d3d11_h264_dec_decode_slice (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice)
{
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
GstD3D11H264DecPrivate *priv = self->priv;
GstH264SPS *sps;
GstH264PPS *pps;
DXVA_PicParams_H264 pic_params = { 0, };
@ -1005,15 +1033,15 @@ gst_d3d11_h264_dec_decode_slice (GstH264Decoder * decoder,
pic_params.CurrFieldOrderCnt[1] = picture->bottom_field_order_cnt;
}
memcpy (pic_params.RefFrameList, priv->ref_frame_list,
memcpy (pic_params.RefFrameList, self->ref_frame_list,
sizeof (pic_params.RefFrameList));
memcpy (pic_params.FieldOrderCntList, priv->field_order_cnt_list,
memcpy (pic_params.FieldOrderCntList, self->field_order_cnt_list,
sizeof (pic_params.FieldOrderCntList));
memcpy (pic_params.FrameNumList, priv->frame_num_list,
memcpy (pic_params.FrameNumList, self->frame_num_list,
sizeof (pic_params.FrameNumList));
pic_params.UsedForReferenceFlags = priv->used_for_reference_flags;
pic_params.NonExistingFrameFlags = priv->non_existing_frame_flags;
pic_params.UsedForReferenceFlags = self->used_for_reference_flags;
pic_params.NonExistingFrameFlags = self->non_existing_frame_flags;
GST_TRACE_OBJECT (self, "Getting picture param decoder buffer");
@ -1159,39 +1187,133 @@ gst_d3d11_h264_dec_decode_slice (GstH264Decoder * decoder,
return TRUE;
}
typedef struct
{
guint width;
guint height;
} GstD3D11H264DecResolution;
void
gst_d3d11_h264_dec_register (GstPlugin * plugin, GstD3D11Device * device,
guint rank)
GstD3D11Decoder * decoder, guint rank, gboolean legacy)
{
GstD3D11Decoder *decoder;
GstVideoInfo info;
GType type;
gchar *type_name;
gchar *feature_name;
guint index = 0;
guint i;
gboolean ret;
GUID profile;
GTypeInfo type_info = {
sizeof (GstD3D11H264DecClass),
NULL,
NULL,
(GClassInitFunc) gst_d3d11_h264_dec_class_init,
NULL,
NULL,
sizeof (GstD3D11H264Dec),
0,
(GInstanceInitFunc) gst_d3d11_h264_dec_init,
};
static const GUID *supported_profiles[] = {
&GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT,
&GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
&GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT
};
/* values were taken from chromium. See supported_profile_helper.cc */
GstD3D11H264DecResolution resolutions_to_check[] = {
{1920, 1088}, {2560, 1440}, {3840, 2160}, {4096, 2160},
{4096, 2304}
};
GstCaps *sink_caps = NULL;
GstCaps *src_caps = NULL;
guint max_width = 0;
guint max_height = 0;
guint resolution;
decoder = gst_d3d11_decoder_new (device);
if (!decoder) {
GST_WARNING_OBJECT (device, "decoder interface unavailable");
return;
}
/* FIXME: DXVA does not provide API for query supported resolution
* maybe we need some tries per standard resolution (e.g., HD, FullHD ...)
* to check supported resolution */
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_NV12, 1280, 720);
ret = gst_d3d11_decoder_open (decoder, GST_D3D11_CODEC_H264,
&info, 1280, 720, NUM_OUTPUT_VIEW, supported_profiles,
G_N_ELEMENTS (supported_profiles));
gst_object_unref (decoder);
ret = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
supported_profiles, G_N_ELEMENTS (supported_profiles), &profile);
if (!ret) {
GST_WARNING_OBJECT (device, "cannot open decoder device");
GST_WARNING_OBJECT (device, "decoder profile unavailable");
return;
}
gst_element_register (plugin, "d3d11h264dec", rank, GST_TYPE_D3D11_H264_DEC);
ret = gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_NV12);
if (!ret) {
GST_FIXME_OBJECT (device, "device does not support NV12 format");
return;
}
/* we will not check the maximum resolution for legacy devices.
* it might cause crash */
if (legacy) {
max_width = resolutions_to_check[0].width;
max_height = resolutions_to_check[0].height;
} else {
for (i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) {
if (gst_d3d11_decoder_supports_resolution (decoder, &profile,
DXGI_FORMAT_NV12, resolutions_to_check[i].width,
resolutions_to_check[i].height)) {
max_width = resolutions_to_check[i].width;
max_height = resolutions_to_check[i].height;
GST_DEBUG_OBJECT (device,
"device support resolution %dx%d", max_width, max_height);
} else {
break;
}
}
}
if (max_width == 0 || max_height == 0) {
GST_WARNING_OBJECT (device, "Couldn't query supported resolution");
return;
}
sink_caps = gst_caps_from_string ("video/x-h264, "
"stream-format= (string) { avc, avc3, byte-stream }, "
"alignment= (string) au, profile = (string) { high, main }, "
"framerate = " GST_VIDEO_FPS_RANGE);
src_caps = gst_caps_from_string ("video/x-raw("
GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY "), format = (string) NV12, "
"framerate = " GST_VIDEO_FPS_RANGE ";"
"video/x-raw, format = (string) NV12, "
"framerate = " GST_VIDEO_FPS_RANGE);
/* To cover both landscape and portrait, select max value */
resolution = MAX (max_width, max_height);
gst_caps_set_simple (sink_caps,
"width", GST_TYPE_INT_RANGE, 64, resolution,
"height", GST_TYPE_INT_RANGE, 64, resolution, NULL);
gst_caps_set_simple (src_caps,
"width", GST_TYPE_INT_RANGE, 64, resolution,
"height", GST_TYPE_INT_RANGE, 64, resolution, NULL);
type_info.class_data =
gst_d3d11_decoder_class_data_new (device, sink_caps, src_caps);
type_name = g_strdup ("GstD3D11H264Dec");
feature_name = g_strdup ("d3d11h264dec");
while (g_type_from_name (type_name)) {
index++;
g_free (type_name);
g_free (feature_name);
type_name = g_strdup_printf ("GstD3D11H264Device%dDec", index);
feature_name = g_strdup_printf ("d3d11h264device%ddec", index);
}
type = g_type_register_static (GST_TYPE_H264_DECODER,
type_name, &type_info, 0);
/* make lower rank than default device */
if (rank > 0 && index != 0)
rank--;
if (!gst_element_register (plugin, feature_name, rank, type))
GST_WARNING ("Failed to register plugin '%s'", type_name);
g_free (type_name);
g_free (feature_name);
}

View file

@ -20,67 +20,15 @@
#ifndef __GST_D3D11_H264_DEC_H__
#define __GST_D3D11_H264_DEC_H__
#include "gsth264decoder.h"
#include "gsth264picture.h"
#include "gstd3d11decoder.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D11_H264_DEC \
(gst_d3d11_h264_dec_get_type())
#define GST_D3D11_H264_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_D3D11_H264_DEC,GstD3D11H264Dec))
#define GST_D3D11_H264_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_D3D11_H264_DEC,GstD3D11H264DecClass))
#define GST_D3D11_H264_DEC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_D3D11_H264_DEC,GstD3D11H264DecClass))
#define GST_IS_D3D11_H264_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_D3D11_H264_DEC))
#define GST_IS_D3D11_H264_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_D3D11_H264_DEC))
typedef struct _GstD3D11H264DecPrivate GstD3D11H264DecPrivate;
struct _GstD3D11H264Dec
{
GstH264Decoder parent;
GstVideoCodecState *output_state;
GstD3D11Device *device;
gint adapter;
guint width, height;
guint coded_width, coded_height;
guint bitdepth;
guint chroma_format_idc;
GstVideoFormat out_format;
/* Array of DXVA_Slice_H264_Short */
GArray *slice_list;
GstD3D11Decoder *d3d11_decoder;
/* Pointing current bitstream buffer */
guint current_offset;
guint bitstream_buffer_size;
guint8 * bitstream_buffer_bytes;
gboolean use_d3d11_output;
GstD3D11H264DecPrivate *priv;
};
struct _GstD3D11H264DecClass
{
GstH264DecoderClass parent_class;
};
GType gst_d3d11_h264_dec_get_type (void);
void gst_d3d11_h264_dec_register (GstPlugin * plugin,
GstD3D11Device * device,
guint rank);
GstD3D11Decoder * decoder,
guint rank,
gboolean legacy);
G_END_DECLS

View file

@ -21,6 +21,8 @@
#include <config.h>
#endif
#include "gsth265decoder.h"
#include "gsth265picture.h"
#include "gstd3d11h265dec.h"
#include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h"
@ -40,11 +42,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_h265_dec_debug);
enum
{
PROP_0,
PROP_ADAPTER
PROP_ADAPTER,
PROP_DEVICE_ID,
PROP_VENDOR_ID,
};
#define DEFAULT_ADAPTER -1
/* copied from d3d11.h since mingw header doesn't define them */
DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0);
@ -54,36 +56,54 @@ DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10,
/* worst case 16 + 4 margin */
#define NUM_OUTPUT_VIEW 20
static GstStaticPadTemplate sink_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-h265, "
"stream-format=(string) { hev1, hvc1, byte-stream }, "
"alignment=(string) au, " "profile = (string) { main-10, main }")
);
static GstStaticPadTemplate src_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME,
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, "{ NV12, P010_10LE }") "; "
GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }")));
struct _GstD3D11H265DecPrivate
typedef struct _GstD3D11H265Dec
{
GstH265Decoder parent;
GstVideoCodecState *output_state;
GstD3D11Device *device;
guint width, height;
guint coded_width, coded_height;
guint bitdepth;
guint chroma_format_idc;
GstVideoFormat out_format;
/* Array of DXVA_Slice_HEVC_Short */
GArray *slice_list;
gboolean submit_iq_data;
GstD3D11Decoder *d3d11_decoder;
/* Pointing current bitstream buffer */
guint current_offset;
guint bitstream_buffer_size;
guint8 *bitstream_buffer_bytes;
gboolean use_d3d11_output;
DXVA_PicEntry_HEVC ref_pic_list[15];
INT pic_order_cnt_val_list[15];
UCHAR ref_pic_set_st_curr_before[8];
UCHAR ref_pic_set_st_curr_after[8];
UCHAR ref_pic_set_lt_curr[8];
};
} GstD3D11H265Dec;
#define parent_class gst_d3d11_h265_dec_parent_class
G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11H265Dec,
gst_d3d11_h265_dec, GST_TYPE_H265_DECODER);
typedef struct _GstD3D11H265DecClass
{
GstH265DecoderClass parent_class;
guint adapter;
guint device_id;
guint vendor_id;
} GstD3D11H265DecClass;
static GstElementClass *parent_class = NULL;
#define GST_D3D11_H265_DEC(object) ((GstD3D11H265Dec *) (object))
#define GST_D3D11_H265_DEC_GET_CLASS(object) \
(G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstD3D11H265DecClass))
static void gst_d3d11_h265_dec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_d3d11_h265_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_d3d11_h265_dec_dispose (GObject * object);
@ -113,35 +133,56 @@ static gboolean gst_d3d11_h265_dec_end_picture (GstH265Decoder * decoder,
GstH265Picture * picture);
static void
gst_d3d11_h265_dec_class_init (GstD3D11H265DecClass * klass)
gst_d3d11_h265_dec_class_init (GstD3D11H265DecClass * klass, gpointer data)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstH265DecoderClass *h265decoder_class = GST_H265_DECODER_CLASS (klass);
GstD3D11DecoderClassData *cdata = (GstD3D11DecoderClassData *) data;
gchar *long_name;
gobject_class->set_property = gst_d3d11_h265_dec_set_property;
gobject_class->get_property = gst_d3d11_h265_dec_get_property;
gobject_class->dispose = gst_d3d11_h265_dec_dispose;
g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)",
-1, G_MAXINT32, DEFAULT_ADAPTER,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
g_param_spec_uint ("adapter", "Adapter",
"DXGI Adapter index for creating device",
0, G_MAXUINT32, cdata->adapter,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
g_param_spec_uint ("device-id", "Device Id",
"DXGI Device ID", 0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VENDOR_ID,
g_param_spec_uint ("vendor-id", "Vendor Id",
"DXGI Vendor ID", 0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
parent_class = g_type_class_peek_parent (klass);
klass->adapter = cdata->adapter;
klass->device_id = cdata->device_id;
klass->vendor_id = cdata->vendor_id;
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_set_context);
gst_element_class_set_static_metadata (element_class,
"Direct3D11 H.265 Video Decoder",
long_name = g_strdup_printf ("Direct3D11 H.265 %s Decoder",
cdata->description);
gst_element_class_set_metadata (element_class, long_name,
"Codec/Decoder/Video/Hardware",
"A Direct3D11 based H.265 video decoder",
"Seungha Yang <seungha.yang@navercorp.com>");
g_free (long_name);
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
cdata->sink_caps));
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
cdata->src_caps));
gst_d3d11_decoder_class_data_free (cdata);
decoder_class->open = GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_close);
@ -167,36 +208,24 @@ gst_d3d11_h265_dec_class_init (GstD3D11H265DecClass * klass)
static void
gst_d3d11_h265_dec_init (GstD3D11H265Dec * self)
{
self->priv = gst_d3d11_h265_dec_get_instance_private (self);
self->slice_list = g_array_new (FALSE, TRUE, sizeof (DXVA_Slice_HEVC_Short));
self->adapter = DEFAULT_ADAPTER;
}
static void
gst_d3d11_h265_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (object);
switch (prop_id) {
case PROP_ADAPTER:
self->adapter = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_d3d11_h265_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (object);
GstD3D11H265DecClass *klass = GST_D3D11_H265_DEC_GET_CLASS (object);
switch (prop_id) {
case PROP_ADAPTER:
g_value_set_int (value, self->adapter);
g_value_set_uint (value, klass->adapter);
break;
case PROP_DEVICE_ID:
g_value_set_uint (value, klass->device_id);
break;
case PROP_VENDOR_ID:
g_value_set_uint (value, klass->vendor_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -221,8 +250,10 @@ static void
gst_d3d11_h265_dec_set_context (GstElement * element, GstContext * context)
{
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (element);
GstD3D11H265DecClass *klass = GST_D3D11_H265_DEC_GET_CLASS (self);
gst_d3d11_handle_set_context (element, context, self->adapter, &self->device);
gst_d3d11_handle_set_context (element, context, klass->adapter,
&self->device);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
@ -231,8 +262,9 @@ static gboolean
gst_d3d11_h265_dec_open (GstVideoDecoder * decoder)
{
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstD3D11H265DecClass *klass = GST_D3D11_H265_DEC_GET_CLASS (self);
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), self->adapter,
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), klass->adapter,
&self->device)) {
GST_ERROR_OBJECT (self, "Cannot create d3d11device");
return FALSE;
@ -543,11 +575,9 @@ gst_d3d11_h265_dec_get_output_view_from_picture (GstD3D11H265Dec * self,
static gint
gst_d3d11_h265_dec_get_ref_index (GstD3D11H265Dec * self, gint view_id)
{
GstD3D11H265DecPrivate *priv = self->priv;
gint i;
for (i = 0; i < G_N_ELEMENTS (priv->ref_pic_list); i++) {
if (priv->ref_pic_list[i].Index7Bits == view_id)
for (i = 0; i < G_N_ELEMENTS (self->ref_pic_list); i++) {
if (self->ref_pic_list[i].Index7Bits == view_id)
return i;
}
@ -559,7 +589,6 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
{
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstD3D11H265DecPrivate *priv = self->priv;
GstD3D11DecoderOutputView *view;
gint i, j;
GArray *dpb_array;
@ -578,21 +607,21 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
}
for (i = 0; i < 15; i++) {
priv->ref_pic_list[i].bPicEntry = 0xff;
priv->pic_order_cnt_val_list[i] = 0;
self->ref_pic_list[i].bPicEntry = 0xff;
self->pic_order_cnt_val_list[i] = 0;
}
for (i = 0; i < 8; i++) {
priv->ref_pic_set_st_curr_before[i] = 0xff;
priv->ref_pic_set_st_curr_after[i] = 0xff;
priv->ref_pic_set_lt_curr[i] = 0xff;
self->ref_pic_set_st_curr_before[i] = 0xff;
self->ref_pic_set_st_curr_after[i] = 0xff;
self->ref_pic_set_lt_curr[i] = 0xff;
}
dpb_array = gst_h265_dpb_get_pictures_all (dpb);
GST_LOG_OBJECT (self, "DPB size %d", dpb_array->len);
for (i = 0; i < dpb_array->len && i < G_N_ELEMENTS (priv->ref_pic_list); i++) {
for (i = 0; i < dpb_array->len && i < G_N_ELEMENTS (self->ref_pic_list); i++) {
GstH265Picture *other = g_array_index (dpb_array, GstH265Picture *, i);
GstD3D11DecoderOutputView *other_view;
gint id = 0xff;
@ -607,12 +636,12 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
if (other_view)
id = other_view->view_id;
priv->ref_pic_list[i].Index7Bits = id;
priv->ref_pic_list[i].AssociatedFlag = other->long_term;
priv->pic_order_cnt_val_list[i] = other->pic_order_cnt;
self->ref_pic_list[i].Index7Bits = id;
self->ref_pic_list[i].AssociatedFlag = other->long_term;
self->pic_order_cnt_val_list[i] = other->pic_order_cnt;
}
for (i = 0, j = 0; i < G_N_ELEMENTS (priv->ref_pic_set_st_curr_before); i++) {
for (i = 0, j = 0; i < G_N_ELEMENTS (self->ref_pic_set_st_curr_before); i++) {
GstH265Picture *other = NULL;
gint id = 0xff;
@ -629,10 +658,10 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
id = gst_d3d11_h265_dec_get_ref_index (self, other_view->view_id);
}
priv->ref_pic_set_st_curr_before[i] = id;
self->ref_pic_set_st_curr_before[i] = id;
}
for (i = 0, j = 0; i < G_N_ELEMENTS (priv->ref_pic_set_st_curr_after); i++) {
for (i = 0, j = 0; i < G_N_ELEMENTS (self->ref_pic_set_st_curr_after); i++) {
GstH265Picture *other = NULL;
gint id = 0xff;
@ -649,10 +678,10 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
id = gst_d3d11_h265_dec_get_ref_index (self, other_view->view_id);
}
priv->ref_pic_set_st_curr_after[i] = id;
self->ref_pic_set_st_curr_after[i] = id;
}
for (i = 0, j = 0; i < G_N_ELEMENTS (priv->ref_pic_set_lt_curr); i++) {
for (i = 0, j = 0; i < G_N_ELEMENTS (self->ref_pic_set_lt_curr); i++) {
GstH265Picture *other = NULL;
gint id = 0xff;
@ -669,7 +698,7 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
id = gst_d3d11_h265_dec_get_ref_index (self, other_view->view_id);
}
priv->ref_pic_set_lt_curr[i] = id;
self->ref_pic_set_lt_curr[i] = id;
}
g_array_unref (dpb_array);
@ -1184,7 +1213,6 @@ gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder,
GstH265Picture * picture, GstH265Slice * slice)
{
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstD3D11H265DecPrivate *priv = self->priv;
GstH265PPS *pps;
DXVA_PicParams_HEVC pic_params = { 0, };
DXVA_Qmatrix_HEVC iq_matrix = { 0, };
@ -1210,15 +1238,15 @@ gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder,
pic_params.IntraPicFlag = IS_IRAP (slice->nalu.type);
pic_params.CurrPicOrderCntVal = picture->pic_order_cnt;
memcpy (pic_params.RefPicList, priv->ref_pic_list,
memcpy (pic_params.RefPicList, self->ref_pic_list,
sizeof (pic_params.RefPicList));
memcpy (pic_params.PicOrderCntValList, priv->pic_order_cnt_val_list,
memcpy (pic_params.PicOrderCntValList, self->pic_order_cnt_val_list,
sizeof (pic_params.PicOrderCntValList));
memcpy (pic_params.RefPicSetStCurrBefore, priv->ref_pic_set_st_curr_before,
memcpy (pic_params.RefPicSetStCurrBefore, self->ref_pic_set_st_curr_before,
sizeof (pic_params.RefPicSetStCurrBefore));
memcpy (pic_params.RefPicSetStCurrAfter, priv->ref_pic_set_st_curr_after,
memcpy (pic_params.RefPicSetStCurrAfter, self->ref_pic_set_st_curr_after,
sizeof (pic_params.RefPicSetStCurrAfter));
memcpy (pic_params.RefPicSetLtCurr, priv->ref_pic_set_lt_curr,
memcpy (pic_params.RefPicSetLtCurr, self->ref_pic_set_lt_curr,
sizeof (pic_params.RefPicSetLtCurr));
#ifndef GST_DISABLE_GST_DEBUG
@ -1380,37 +1408,190 @@ gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder,
return TRUE;
}
typedef struct
{
guint width;
guint height;
} GstD3D11H265DecResolution;
void
gst_d3d11_h265_dec_register (GstPlugin * plugin, GstD3D11Device * device,
guint rank)
GstD3D11Decoder * decoder, guint rank)
{
GstD3D11Decoder *decoder;
GstVideoInfo info;
gboolean ret;
static const GUID *supported_profiles[] = {
&GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
GType type;
gchar *type_name;
gchar *feature_name;
guint index = 0;
guint i;
GUID profile;
GTypeInfo type_info = {
sizeof (GstD3D11H265DecClass),
NULL,
NULL,
(GClassInitFunc) gst_d3d11_h265_dec_class_init,
NULL,
NULL,
sizeof (GstD3D11H265Dec),
0,
(GInstanceInitFunc) gst_d3d11_h265_dec_init,
};
static const GUID *main_10_guid =
&GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN10;
static const GUID *main_guid = &GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN;
/* values were taken from chromium.
* Note that since chromium does not support hevc decoding, this list is
* the combination of lists for avc and vp9.
* See supported_profile_helper.cc */
GstD3D11H265DecResolution resolutions_to_check[] = {
{1920, 1088}, {2560, 1440}, {3840, 2160}, {4096, 2160},
{4096, 2304}, {7680, 4320}, {8192, 4320}, {8192, 8192}
};
GstCaps *sink_caps = NULL;
GstCaps *src_caps = NULL;
guint max_width = 0;
guint max_height = 0;
guint resolution;
gboolean have_main10 = FALSE;
gboolean have_main = FALSE;
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
decoder = gst_d3d11_decoder_new (device);
if (!decoder) {
GST_WARNING_OBJECT (device, "decoder interface unavailable");
have_main10 = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
&main_10_guid, 1, &profile);
if (!have_main10) {
GST_DEBUG_OBJECT (device, "decoder does not support HEVC_VLD_MAIN10");
} else {
have_main10 &=
gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_P010);
have_main10 &=
gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_NV12);
if (!have_main10) {
GST_FIXME_OBJECT (device,
"device does not support P010 and/or NV12 format");
}
}
have_main = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
&main_guid, 1, &profile);
if (!have_main) {
GST_DEBUG_OBJECT (device, "decoder does not support HEVC_VLD_MAIN");
} else {
have_main =
gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_NV12);
if (!have_main) {
GST_FIXME_OBJECT (device, "device does not support NV12 format");
}
}
if (!have_main10 && !have_main) {
GST_INFO_OBJECT (device, "device does not support h.265 decoding");
return;
}
/* FIXME: DXVA does not provide API for query supported resolution
* maybe we need some tries per standard resolution (e.g., HD, FullHD ...)
* to check supported resolution */
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_NV12, 1280, 720);
if (have_main) {
profile = *main_guid;
format = DXGI_FORMAT_NV12;
} else {
profile = *main_10_guid;
format = DXGI_FORMAT_P010;
}
ret = gst_d3d11_decoder_open (decoder, GST_D3D11_CODEC_H265,
&info, 1280, 720, NUM_OUTPUT_VIEW, supported_profiles,
G_N_ELEMENTS (supported_profiles));
gst_object_unref (decoder);
for (i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) {
if (gst_d3d11_decoder_supports_resolution (decoder, &profile,
format, resolutions_to_check[i].width,
resolutions_to_check[i].height)) {
max_width = resolutions_to_check[i].width;
max_height = resolutions_to_check[i].height;
if (!ret) {
GST_WARNING_OBJECT (device, "cannot open decoder device");
GST_DEBUG_OBJECT (device,
"device support resolution %dx%d", max_width, max_height);
} else {
break;
}
}
if (max_width == 0 || max_height == 0) {
GST_WARNING_OBJECT (device, "Couldn't query supported resolution");
return;
}
gst_element_register (plugin, "d3d11h265dec", rank, GST_TYPE_D3D11_H265_DEC);
sink_caps = gst_caps_from_string ("video/x-h265, "
"stream-format=(string) { hev1, hvc1, byte-stream }, "
"alignment= (string) au, " "framerate = " GST_VIDEO_FPS_RANGE);
src_caps = gst_caps_from_string ("video/x-raw("
GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY "), "
"framerate = " GST_VIDEO_FPS_RANGE ";"
"video/x-raw, " "framerate = " GST_VIDEO_FPS_RANGE);
if (have_main10) {
/* main10 profile covers main and main10 */
GValue profile_list = G_VALUE_INIT;
GValue profile_value = G_VALUE_INIT;
GValue format_list = G_VALUE_INIT;
GValue format_value = G_VALUE_INIT;
g_value_init (&profile_list, GST_TYPE_LIST);
g_value_init (&profile_value, G_TYPE_STRING);
g_value_set_string (&profile_value, "main");
gst_value_list_append_and_take_value (&profile_list, &profile_value);
g_value_init (&profile_value, G_TYPE_STRING);
g_value_set_string (&profile_value, "main-10");
gst_value_list_append_and_take_value (&profile_list, &profile_value);
g_value_init (&format_list, GST_TYPE_LIST);
g_value_init (&format_value, G_TYPE_STRING);
g_value_set_string (&format_value, "NV12");
gst_value_list_append_and_take_value (&format_list, &format_value);
g_value_init (&format_value, G_TYPE_STRING);
g_value_set_string (&format_value, "P010_10LE");
gst_value_list_append_and_take_value (&format_list, &format_value);
gst_caps_set_value (sink_caps, "profile", &profile_list);
gst_caps_set_value (src_caps, "format", &format_list);
g_value_unset (&profile_list);
g_value_unset (&format_list);
} else {
gst_caps_set_simple (sink_caps, "profile", G_TYPE_STRING, "main", NULL);
gst_caps_set_simple (src_caps, "format", G_TYPE_STRING, "NV12", NULL);
}
/* To cover both landscape and portrait, select max value */
resolution = MAX (max_width, max_height);
gst_caps_set_simple (sink_caps,
"width", GST_TYPE_INT_RANGE, 64, resolution,
"height", GST_TYPE_INT_RANGE, 64, resolution, NULL);
gst_caps_set_simple (src_caps,
"width", GST_TYPE_INT_RANGE, 64, resolution,
"height", GST_TYPE_INT_RANGE, 64, resolution, NULL);
type_info.class_data =
gst_d3d11_decoder_class_data_new (device, sink_caps, src_caps);
type_name = g_strdup ("GstD3D11H265Dec");
feature_name = g_strdup ("d3d11h265dec");
while (g_type_from_name (type_name)) {
index++;
g_free (type_name);
g_free (feature_name);
type_name = g_strdup_printf ("GstD3D11H265Device%dDec", index);
feature_name = g_strdup_printf ("d3d11h265device%ddec", index);
}
type = g_type_register_static (GST_TYPE_H265_DECODER,
type_name, &type_info, 0);
/* make lower rank than default device */
if (rank > 0 && index != 0)
rank--;
if (!gst_element_register (plugin, feature_name, rank, type))
GST_WARNING ("Failed to register plugin '%s'", type_name);
g_free (type_name);
g_free (feature_name);
}

View file

@ -20,67 +20,13 @@
#ifndef __GST_D3D11_H265_DEC_H__
#define __GST_D3D11_H265_DEC_H__
#include "gsth265decoder.h"
#include "gsth265picture.h"
#include "gstd3d11decoder.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D11_H265_DEC \
(gst_d3d11_h265_dec_get_type())
#define GST_D3D11_H265_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_D3D11_H265_DEC,GstD3D11H265Dec))
#define GST_D3D11_H265_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_D3D11_H265_DEC,GstD3D11H265DecClass))
#define GST_D3D11_H265_DEC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_D3D11_H265_DEC,GstD3D11H265DecClass))
#define GST_IS_D3D11_H265_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_D3D11_H265_DEC))
#define GST_IS_D3D11_H265_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_D3D11_H265_DEC))
typedef struct _GstD3D11H265DecPrivate GstD3D11H265DecPrivate;
struct _GstD3D11H265Dec
{
GstH265Decoder parent;
GstVideoCodecState *output_state;
GstD3D11Device *device;
gint adapter;
guint width, height;
guint coded_width, coded_height;
guint bitdepth;
guint chroma_format_idc;
GstVideoFormat out_format;
/* Array of DXVA_Slice_HEVC_Short */
GArray *slice_list;
gboolean submit_iq_data;
GstD3D11Decoder *d3d11_decoder;
/* Pointing current bitstream buffer */
guint current_offset;
guint bitstream_buffer_size;
guint8 * bitstream_buffer_bytes;
gboolean use_d3d11_output;
GstD3D11H265DecPrivate *priv;
};
struct _GstD3D11H265DecClass
{
GstH265DecoderClass parent_class;
};
GType gst_d3d11_h265_dec_get_type (void);
void gst_d3d11_h265_dec_register (GstPlugin * plugin,
GstD3D11Device * device,
GstD3D11Decoder * decoder,
guint rank);
G_END_DECLS

View file

@ -52,6 +52,8 @@
#endif
#include "gstd3d11vp9dec.h"
#include "gstvp9decoder.h"
#include "gstvp9picture.h"
#include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h"
#include <string.h>
@ -70,11 +72,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_vp9_dec_debug);
enum
{
PROP_0,
PROP_ADAPTER
PROP_ADAPTER,
PROP_DEVICE_ID,
PROP_VENDOR_ID,
};
#define DEFAULT_ADAPTER -1
/* copied from d3d11.h since mingw header doesn't define them */
DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e);
@ -84,24 +86,38 @@ DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2,
/* reference list 8 + 4 margin */
#define NUM_OUTPUT_VIEW 12
static GstStaticPadTemplate sink_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME,
GST_PAD_SINK, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-vp9")
);
typedef struct _GstD3D11Vp9Dec
{
GstVp9Decoder parent;
static GstStaticPadTemplate src_template =
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SRC_NAME,
GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
(GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY, "{ NV12, P010_10LE }") "; "
GST_VIDEO_CAPS_MAKE ("{ NV12, P010_10LE }")));
GstVideoCodecState *output_state;
#define parent_class gst_d3d11_vp9_dec_parent_class
G_DEFINE_TYPE (GstD3D11Vp9Dec, gst_d3d11_vp9_dec, GST_TYPE_VP9_DECODER);
GstD3D11Device *device;
GstD3D11Decoder *d3d11_decoder;
guint width, height;
GstVP9Profile profile;
GstVideoFormat out_format;
gboolean use_d3d11_output;
} GstD3D11Vp9Dec;
typedef struct _GstD3D11Vp9DecClass
{
GstVp9DecoderClass parent_class;
guint adapter;
guint device_id;
guint vendor_id;
} GstD3D11Vp9DecClass;
static GstElementClass *parent_class = NULL;
#define GST_D3D11_VP9_DEC(object) ((GstD3D11Vp9Dec *) (object))
#define GST_D3D11_VP9_DEC_GET_CLASS(object) \
(G_TYPE_INSTANCE_GET_CLASS ((object),G_TYPE_FROM_INSTANCE (object),GstD3D11Vp9DecClass))
static void gst_d3d11_vp9_dec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_d3d11_vp9_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_d3d11_vp9_dec_set_context (GstElement * element,
@ -132,34 +148,54 @@ static gboolean gst_d3d11_vp9_dec_end_picture (GstVp9Decoder * decoder,
GstVp9Picture * picture);
static void
gst_d3d11_vp9_dec_class_init (GstD3D11Vp9DecClass * klass)
gst_d3d11_vp9_dec_class_init (GstD3D11Vp9DecClass * klass, gpointer data)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstVp9DecoderClass *vp9decoder_class = GST_VP9_DECODER_CLASS (klass);
GstD3D11DecoderClassData *cdata = (GstD3D11DecoderClassData *) data;
gchar *long_name;
gobject_class->set_property = gst_d3d11_vp9_dec_set_property;
gobject_class->get_property = gst_d3d11_vp9_dec_get_property;
g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)",
-1, G_MAXINT32, DEFAULT_ADAPTER,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
G_PARAM_STATIC_STRINGS));
g_param_spec_uint ("adapter", "Adapter",
"DXGI Adapter index for creating device",
0, G_MAXUINT32, cdata->adapter,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
g_param_spec_uint ("device-id", "Device Id",
"DXGI Device ID", 0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VENDOR_ID,
g_param_spec_uint ("vendor-id", "Vendor Id",
"DXGI Vendor ID", 0, G_MAXUINT32, 0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
parent_class = g_type_class_peek_parent (klass);
klass->adapter = cdata->adapter;
klass->device_id = cdata->device_id;
klass->vendor_id = cdata->vendor_id;
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_set_context);
gst_element_class_set_static_metadata (element_class,
"Direct3D11 VP9 Video Decoder",
long_name = g_strdup_printf ("Direct3D11 VP9 %s Decoder", cdata->description);
gst_element_class_set_metadata (element_class, long_name,
"Codec/Decoder/Video/Hardware",
"A Direct3D11 based VP9 video decoder",
"Seungha Yang <seungha.yang@navercorp.com>");
g_free (long_name);
gst_element_class_add_static_pad_template (element_class, &sink_template);
gst_element_class_add_static_pad_template (element_class, &src_template);
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
cdata->sink_caps));
gst_element_class_add_pad_template (element_class,
gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
cdata->src_caps));
gst_d3d11_decoder_class_data_free (cdata);
decoder_class->open = GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_close);
@ -187,34 +223,23 @@ gst_d3d11_vp9_dec_class_init (GstD3D11Vp9DecClass * klass)
static void
gst_d3d11_vp9_dec_init (GstD3D11Vp9Dec * self)
{
self->adapter = DEFAULT_ADAPTER;
}
static void
gst_d3d11_vp9_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (object);
switch (prop_id) {
case PROP_ADAPTER:
self->adapter = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_d3d11_vp9_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (object);
GstD3D11Vp9DecClass *klass = GST_D3D11_VP9_DEC_GET_CLASS (object);
switch (prop_id) {
case PROP_ADAPTER:
g_value_set_int (value, self->adapter);
g_value_set_uint (value, klass->adapter);
break;
case PROP_DEVICE_ID:
g_value_set_uint (value, klass->device_id);
break;
case PROP_VENDOR_ID:
g_value_set_uint (value, klass->vendor_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -226,8 +251,10 @@ static void
gst_d3d11_vp9_dec_set_context (GstElement * element, GstContext * context)
{
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (element);
GstD3D11Vp9DecClass *klass = GST_D3D11_VP9_DEC_GET_CLASS (self);
gst_d3d11_handle_set_context (element, context, self->adapter, &self->device);
gst_d3d11_handle_set_context (element, context, klass->adapter,
&self->device);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
@ -236,8 +263,9 @@ static gboolean
gst_d3d11_vp9_dec_open (GstVideoDecoder * decoder)
{
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (decoder);
GstD3D11Vp9DecClass *klass = GST_D3D11_VP9_DEC_GET_CLASS (self);
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), self->adapter,
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), klass->adapter,
&self->device)) {
GST_ERROR_OBJECT (self, "Cannot create d3d11device");
return FALSE;
@ -1139,37 +1167,170 @@ gst_d3d11_vp9_dec_end_picture (GstVp9Decoder * decoder, GstVp9Picture * picture)
return TRUE;
}
typedef struct
{
guint width;
guint height;
} GstD3D11Vp9DecResolution;
void
gst_d3d11_vp9_dec_register (GstPlugin * plugin, GstD3D11Device * device,
guint rank)
GstD3D11Decoder * decoder, guint rank)
{
GstD3D11Decoder *decoder;
GstVideoInfo info;
gboolean ret;
static const GUID *supported_profiles[] = {
&GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
GType type;
gchar *type_name;
gchar *feature_name;
guint index = 0;
guint i;
GUID profile;
GTypeInfo type_info = {
sizeof (GstD3D11Vp9DecClass),
NULL,
NULL,
(GClassInitFunc) gst_d3d11_vp9_dec_class_init,
NULL,
NULL,
sizeof (GstD3D11Vp9Dec),
0,
(GInstanceInitFunc) gst_d3d11_vp9_dec_init,
};
static const GUID *profile2_guid =
&GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_10BIT_PROFILE2;
static const GUID *profile0_guid =
&GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0;
/* values were taken from chromium. See supported_profile_helper.cc */
GstD3D11Vp9DecResolution resolutions_to_check[] = {
{4096, 2160}, {4096, 2304}, {7680, 4320}, {8192, 4320}, {8192, 8192}
};
GstCaps *sink_caps = NULL;
GstCaps *src_caps = NULL;
guint max_width = 0;
guint max_height = 0;
guint resolution;
gboolean have_profile2 = FALSE;
gboolean have_profile0 = FALSE;
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
decoder = gst_d3d11_decoder_new (device);
if (!decoder) {
GST_WARNING_OBJECT (device, "decoder interface unavailable");
have_profile2 = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
&profile2_guid, 1, &profile);
if (!have_profile2) {
GST_DEBUG_OBJECT (device,
"decoder does not support VP9_VLD_10BIT_PROFILE2");
} else {
have_profile2 &=
gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_P010);
have_profile2 &=
gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_NV12);
if (!have_profile2) {
GST_FIXME_OBJECT (device,
"device does not support P010 and/or NV12 format");
}
}
have_profile0 = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
&profile0_guid, 1, &profile);
if (!have_profile0) {
GST_DEBUG_OBJECT (device, "decoder does not support VP9_VLD_PROFILE0");
} else {
have_profile0 =
gst_d3d11_decoder_supports_format (decoder, &profile, DXGI_FORMAT_NV12);
if (!have_profile0) {
GST_FIXME_OBJECT (device, "device does not support NV12 format");
}
}
if (!have_profile2 && !have_profile0) {
GST_INFO_OBJECT (device, "device does not support VP9 decoding");
return;
}
/* FIXME: DXVA does not provide API for query supported resolution
* maybe we need some tries per standard resolution (e.g., HD, FullHD ...)
* to check supported resolution */
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_NV12, 1280, 720);
if (have_profile0) {
profile = *profile0_guid;
format = DXGI_FORMAT_NV12;
} else {
profile = *profile2_guid;
format = DXGI_FORMAT_P010;
}
ret = gst_d3d11_decoder_open (decoder, GST_D3D11_CODEC_VP9,
&info, 1280, 720, NUM_OUTPUT_VIEW, supported_profiles,
G_N_ELEMENTS (supported_profiles));
gst_object_unref (decoder);
for (i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) {
if (gst_d3d11_decoder_supports_resolution (decoder, &profile,
format, resolutions_to_check[i].width,
resolutions_to_check[i].height)) {
max_width = resolutions_to_check[i].width;
max_height = resolutions_to_check[i].height;
if (!ret) {
GST_WARNING_OBJECT (device, "cannot open decoder device");
GST_DEBUG_OBJECT (device,
"device support resolution %dx%d", max_width, max_height);
} else {
break;
}
}
if (max_width == 0 || max_height == 0) {
GST_WARNING_OBJECT (device, "Couldn't query supported resolution");
return;
}
gst_element_register (plugin, "d3d11vp9dec", rank, GST_TYPE_D3D11_VP9_DEC);
sink_caps = gst_caps_from_string ("video/x-vp9, "
"framerate = " GST_VIDEO_FPS_RANGE);
src_caps = gst_caps_from_string ("video/x-raw("
GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY "), "
"framerate = " GST_VIDEO_FPS_RANGE ";"
"video/x-raw, " "framerate = " GST_VIDEO_FPS_RANGE);
if (have_profile2) {
GValue format_list = G_VALUE_INIT;
GValue format_value = G_VALUE_INIT;
g_value_init (&format_list, GST_TYPE_LIST);
g_value_init (&format_value, G_TYPE_STRING);
g_value_set_string (&format_value, "NV12");
gst_value_list_append_and_take_value (&format_list, &format_value);
g_value_init (&format_value, G_TYPE_STRING);
g_value_set_string (&format_value, "P010_10LE");
gst_value_list_append_and_take_value (&format_list, &format_value);
gst_caps_set_value (src_caps, "format", &format_list);
g_value_unset (&format_list);
} else {
gst_caps_set_simple (src_caps, "format", G_TYPE_STRING, "NV12", NULL);
}
/* To cover both landscape and portrait, select max value */
resolution = MAX (max_width, max_height);
gst_caps_set_simple (sink_caps,
"width", GST_TYPE_INT_RANGE, 64, resolution,
"height", GST_TYPE_INT_RANGE, 64, resolution, NULL);
gst_caps_set_simple (src_caps,
"width", GST_TYPE_INT_RANGE, 64, resolution,
"height", GST_TYPE_INT_RANGE, 64, resolution, NULL);
type_info.class_data =
gst_d3d11_decoder_class_data_new (device, sink_caps, src_caps);
type_name = g_strdup ("GstD3D11Vp9Dec");
feature_name = g_strdup ("d3d11vp9dec");
while (g_type_from_name (type_name)) {
index++;
g_free (type_name);
g_free (feature_name);
type_name = g_strdup_printf ("GstD3D11Vp9Device%dDec", index);
feature_name = g_strdup_printf ("d3d11vp9device%ddec", index);
}
type = g_type_register_static (GST_TYPE_VP9_DECODER,
type_name, &type_info, 0);
/* make lower rank than default device */
if (rank > 0 && index != 0)
rank--;
if (!gst_element_register (plugin, feature_name, rank, type))
GST_WARNING ("Failed to register plugin '%s'", type_name);
g_free (type_name);
g_free (feature_name);
}

View file

@ -20,53 +20,13 @@
#ifndef __GST_D3D11_VP9_DEC_H__
#define __GST_D3D11_VP9_DEC_H__
#include "gstvp9decoder.h"
#include "gstvp9picture.h"
#include "gstd3d11decoder.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D11_VP9_DEC \
(gst_d3d11_vp9_dec_get_type())
#define GST_D3D11_VP9_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_D3D11_VP9_DEC,GstD3D11Vp9Dec))
#define GST_D3D11_VP9_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_D3D11_VP9_DEC,GstD3D11Vp9DecClass))
#define GST_D3D11_VP9_DEC_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_D3D11_VP9_DEC,GstD3D11Vp9DecClass))
#define GST_IS_D3D11_VP9_DEC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_D3D11_VP9_DEC))
#define GST_IS_D3D11_VP9_DEC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_D3D11_VP9_DEC))
struct _GstD3D11Vp9Dec
{
GstVp9Decoder parent;
GstVideoCodecState *output_state;
GstD3D11Device *device;
gint adapter;
GstD3D11Decoder *d3d11_decoder;
guint width, height;
GstVP9Profile profile;
GstVideoFormat out_format;
gboolean use_d3d11_output;
};
struct _GstD3D11Vp9DecClass
{
GstVp9DecoderClass parent_class;
};
GType gst_d3d11_vp9_dec_get_type (void);
void gst_d3d11_vp9_dec_register (GstPlugin * plugin,
GstD3D11Device * device,
GstD3D11Decoder * decoder,
guint rank);
G_END_DECLS

View file

@ -95,7 +95,8 @@ plugin_init (GstPlugin * plugin)
#ifdef HAVE_DXVA_H
/* DXVA2 API is availble since Windows 8 */
if (gst_d3d11_is_windows_8_or_greater ()) {
GstD3D11Device *device;
GstD3D11Device *device = NULL;
gint i = 0;
GST_DEBUG_CATEGORY_INIT (gst_d3d11_h264_dec_debug,
"d3d11h264dec", 0, "Direct3D11 H.264 Video Decoder");
@ -104,13 +105,34 @@ plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (gst_d3d11_h265_dec_debug,
"d3d11h265dec", 0, "Direct3D11 H.265 Video Decoder");
device = gst_d3d11_device_new (0);
if (device) {
gst_d3d11_h264_dec_register (plugin, device, GST_RANK_SECONDARY);
gst_d3d11_h265_dec_register (plugin, device, GST_RANK_SECONDARY);
gst_d3d11_vp9_dec_register (plugin, device, GST_RANK_SECONDARY);
while ((device = gst_d3d11_device_new (i)) != NULL) {
GstD3D11Decoder *decoder = NULL;
gboolean legacy;
gboolean hardware;
gst_object_unref (device);
g_object_get (device, "hardware", &hardware, NULL);
if (!hardware)
goto clear;
decoder = gst_d3d11_decoder_new (device);
if (!decoder)
goto clear;
legacy = gst_d3d11_decoder_util_is_legacy_device (device);
gst_d3d11_h264_dec_register (plugin,
device, decoder, GST_RANK_SECONDARY, legacy);
if (!legacy) {
gst_d3d11_h265_dec_register (plugin, device, decoder,
GST_RANK_SECONDARY);
gst_d3d11_vp9_dec_register (plugin, device, decoder,
GST_RANK_SECONDARY);
}
clear:
gst_clear_object (&device);
gst_clear_object (&decoder);
i++;
}
}
#endif