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 _GstD3D11DecoderClass GstD3D11DecoderClass;
typedef struct _GstD3D11DecoderPrivate GstD3D11DecoderPrivate; 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 G_END_DECLS
#endif /* __GST_D3D11_FWD_H__ */ #endif /* __GST_D3D11_FWD_H__ */

View File

@ -15,6 +15,36 @@
* License along with this library; if not, write to the * License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA. * 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 #ifdef HAVE_CONFIG_H
@ -425,51 +455,29 @@ error:
} }
gboolean gboolean
gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec, gst_d3d11_decoder_get_supported_decoder_profile (GstD3D11Decoder * decoder,
GstVideoInfo * info, guint coded_width, guint coded_height, const GUID ** decoder_profiles, guint profile_size, GUID * selected_profile)
guint pool_size, const GUID ** decoder_profiles, guint profile_size)
{ {
GstD3D11DecoderPrivate *priv; 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; GUID *guid_list = NULL;
const GUID *profile = NULL;
guint available_profile_count; guint available_profile_count;
gint i, j; gint i, j;
HRESULT hr;
g_return_val_if_fail (GST_IS_D3D11_DECODER (decoder), FALSE); 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 (decoder_profiles != NULL, FALSE);
g_return_val_if_fail (profile_size > 0, FALSE); g_return_val_if_fail (profile_size > 0, FALSE);
g_return_val_if_fail (selected_profile != NULL, FALSE);
priv = decoder->priv; 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 = available_profile_count =
ID3D11VideoDevice_GetVideoDecoderProfileCount (priv->video_device); ID3D11VideoDevice_GetVideoDecoderProfileCount (priv->video_device);
if (available_profile_count == 0) { if (available_profile_count == 0) {
GST_ERROR_OBJECT (decoder, "No available decoder profile"); GST_WARNING_OBJECT (decoder, "No available decoder profile");
goto error; return FALSE;
} }
GST_DEBUG_OBJECT (decoder, GST_DEBUG_OBJECT (decoder,
@ -480,8 +488,8 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
hr = ID3D11VideoDevice_GetVideoDecoderProfile (priv->video_device, hr = ID3D11VideoDevice_GetVideoDecoderProfile (priv->video_device,
i, &guid_list[i]); i, &guid_list[i]);
if (!gst_d3d11_result (hr, priv->device)) { if (!gst_d3d11_result (hr, priv->device)) {
GST_ERROR_OBJECT (decoder, "Failed to get %d th decoder profile", i); GST_WARNING_OBJECT (decoder, "Failed to get %d th decoder profile", i);
goto error; return FALSE;
} }
} }
@ -512,29 +520,77 @@ gst_d3d11_decoder_open (GstD3D11Decoder * decoder, GstD3D11Codec codec,
for (i = 0; i < profile_size; i++) { for (i = 0; i < profile_size; i++) {
for (j = 0; j < available_profile_count; j++) { for (j = 0; j < available_profile_count; j++) {
if (IsEqualGUID (decoder_profiles[i], &guid_list[j])) { if (IsEqualGUID (decoder_profiles[i], &guid_list[j])) {
selected_profile = decoder_profiles[i]; profile = decoder_profiles[i];
break; break;
} }
} }
} }
if (!selected_profile) { if (!profile) {
GST_ERROR_OBJECT (decoder, "No supported decoder 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; 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, 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) { if (!gst_d3d11_result (hr, priv->device) || !can_support) {
GST_ERROR_OBJECT (decoder, GST_ERROR_OBJECT (decoder,
"VideoDevice could not support dxgi format %d, hr: 0x%x", "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.SampleWidth = coded_width;
decoder_desc.SampleHeight = coded_height; decoder_desc.SampleHeight = coded_height;
decoder_desc.OutputFormat = d3d11_format->dxgi_format; decoder_desc.OutputFormat = d3d11_format->dxgi_format;
decoder_desc.Guid = *selected_profile; decoder_desc.Guid = selected_profile;
hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device, hr = ID3D11VideoDevice_GetVideoDecoderConfigCount (priv->video_device,
&decoder_desc, &config_count); &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, 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"); GST_ERROR_OBJECT (decoder, "Couldn't prepare output view pool");
goto error; 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.right = GST_VIDEO_INFO_WIDTH (info);
priv->staging_box.bottom = GST_VIDEO_INFO_HEIGHT (info); priv->staging_box.bottom = GST_VIDEO_INFO_HEIGHT (info);
priv->decoder_profile = *selected_profile; priv->decoder_profile = selected_profile;
decoder->opened = TRUE; decoder->opened = TRUE;
gst_d3d11_device_unlock (priv->device); 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); 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 GST_D3D11_CODEC_LAST
} GstD3D11Codec; } GstD3D11Codec;
typedef struct
{
GstCaps *sink_caps;
GstCaps *src_caps;
guint adapter;
guint device_id;
guint vendor_id;
gchar *description;
} GstD3D11DecoderClassData;
struct _GstD3D11Decoder struct _GstD3D11Decoder
{ {
GstObject parent; GstObject parent;
@ -125,6 +135,30 @@ gboolean gst_d3d11_decoder_copy_decoder_buffer (GstD3D11Decoder * decod
GstBuffer * decoder_buffer, GstBuffer * decoder_buffer,
GstBuffer * output); 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 G_END_DECLS
#endif /* __GST_D3D11_DECODER_H__ */ #endif /* __GST_D3D11_DECODER_H__ */

View File

@ -51,6 +51,8 @@
#include <config.h> #include <config.h>
#endif #endif
#include "gsth264decoder.h"
#include "gsth264picture.h"
#include "gstd3d11h264dec.h" #include "gstd3d11h264dec.h"
#include "gstd3d11memory.h" #include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h" #include "gstd3d11bufferpool.h"
@ -70,11 +72,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_h264_dec_debug);
enum enum
{ {
PROP_0, 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 */ /* copied from d3d11.h since mingw header doesn't define them */
DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0x1b81be67, 0xa0c7, DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT, 0x1b81be67, 0xa0c7,
0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5); 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 */ /* worst case 16 (non-interlaced) + 4 margin */
#define NUM_OUTPUT_VIEW 20 #define NUM_OUTPUT_VIEW 20
static GstStaticPadTemplate sink_template = typedef struct _GstD3D11H264Dec
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
{ {
/* 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]; DXVA_PicEntry_H264 ref_frame_list[16];
INT field_order_cnt_list[16][2]; INT field_order_cnt_list[16][2];
USHORT frame_num_list[16]; USHORT frame_num_list[16];
UINT used_for_reference_flags; UINT used_for_reference_flags;
USHORT non_existing_frame_flags; USHORT non_existing_frame_flags;
}; } GstD3D11H264Dec;
#define parent_class gst_d3d11_h264_dec_parent_class typedef struct _GstD3D11H264DecClass
G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11H264Dec, {
gst_d3d11_h264_dec, GST_TYPE_H264_DECODER); 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, static void gst_d3d11_h264_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec); guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_d3d11_h264_dec_dispose (GObject * object); 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); GstH264Picture * picture);
static void 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); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstH264DecoderClass *h264decoder_class = GST_H264_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->get_property = gst_d3d11_h264_dec_get_property;
gobject_class->dispose = gst_d3d11_h264_dec_dispose; gobject_class->dispose = gst_d3d11_h264_dec_dispose;
g_object_class_install_property (gobject_class, PROP_ADAPTER, g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter", g_param_spec_uint ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)", "DXGI Adapter index for creating device",
-1, G_MAXINT32, DEFAULT_ADAPTER, 0, G_MAXUINT32, cdata->adapter,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
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 = element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_set_context); GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_set_context);
gst_element_class_set_static_metadata (element_class, long_name = g_strdup_printf ("Direct3D11 H.264 %s Decoder",
"Direct3D11 H.264 Video Decoder", cdata->description);
gst_element_class_set_metadata (element_class, long_name,
"Codec/Decoder/Video/Hardware", "Codec/Decoder/Video/Hardware",
"A Direct3D11 based H.264 video decoder", "A Direct3D11 based H.264 video decoder",
"Seungha Yang <seungha.yang@navercorp.com>"); "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_pad_template (element_class,
gst_element_class_add_static_pad_template (element_class, &src_template); 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->open = GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_h264_dec_close); 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 static void
gst_d3d11_h264_dec_init (GstD3D11H264Dec * self) 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->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 static void
gst_d3d11_h264_dec_get_property (GObject * object, guint prop_id, gst_d3d11_h264_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec) GValue * value, GParamSpec * pspec)
{ {
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (object); GstD3D11H264DecClass *klass = GST_D3D11_H264_DEC_GET_CLASS (object);
switch (prop_id) { switch (prop_id) {
case PROP_ADAPTER: 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; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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) gst_d3d11_h264_dec_set_context (GstElement * element, GstContext * context)
{ {
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (element); 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); GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
} }
@ -264,8 +293,9 @@ static gboolean
gst_d3d11_h264_dec_open (GstVideoDecoder * decoder) gst_d3d11_h264_dec_open (GstVideoDecoder * decoder)
{ {
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (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)) { &self->device)) {
GST_ERROR_OBJECT (self, "Cannot create d3d11device"); GST_ERROR_OBJECT (self, "Cannot create d3d11device");
return FALSE; return FALSE;
@ -577,7 +607,6 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb) GstH264Picture * picture, GstH264Slice * slice, GstH264Dpb * dpb)
{ {
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder); GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
GstD3D11H264DecPrivate *priv = self->priv;
GstD3D11DecoderOutputView *view; GstD3D11DecoderOutputView *view;
gint i; gint i;
GArray *dpb_array; GArray *dpb_array;
@ -596,13 +625,13 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
} }
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
priv->ref_frame_list[i].bPicEntry = 0xFF; self->ref_frame_list[i].bPicEntry = 0xFF;
priv->field_order_cnt_list[i][0] = 0; self->field_order_cnt_list[i][0] = 0;
priv->field_order_cnt_list[i][1] = 0; self->field_order_cnt_list[i][1] = 0;
priv->frame_num_list[i] = 0; self->frame_num_list[i] = 0;
} }
priv->used_for_reference_flags = 0; self->used_for_reference_flags = 0;
priv->non_existing_frame_flags = 0; self->non_existing_frame_flags = 0;
dpb_array = gst_h264_dpb_get_pictures_all (dpb); dpb_array = gst_h264_dpb_get_pictures_all (dpb);
@ -620,14 +649,14 @@ gst_d3d11_h264_dec_start_picture (GstH264Decoder * decoder,
if (other_view) if (other_view)
id = other_view->view_id; id = other_view->view_id;
priv->ref_frame_list[i].Index7Bits = id; self->ref_frame_list[i].Index7Bits = id;
priv->ref_frame_list[i].AssociatedFlag = other->long_term; self->ref_frame_list[i].AssociatedFlag = other->long_term;
priv->field_order_cnt_list[i][0] = other->top_field_order_cnt; self->field_order_cnt_list[i][0] = other->top_field_order_cnt;
priv->field_order_cnt_list[i][1] = other->bottom_field_order_cnt; self->field_order_cnt_list[i][1] = other->bottom_field_order_cnt;
priv->frame_num_list[i] = priv->ref_frame_list[i].AssociatedFlag self->frame_num_list[i] = self->ref_frame_list[i].AssociatedFlag
? other->long_term_pic_num : other->frame_num; ? other->long_term_pic_num : other->frame_num;
priv->used_for_reference_flags |= ref << (2 * i); self->used_for_reference_flags |= ref << (2 * i);
priv->non_existing_frame_flags |= (other->nonexisting) << i; self->non_existing_frame_flags |= (other->nonexisting) << i;
} }
g_array_unref (dpb_array); g_array_unref (dpb_array);
@ -968,7 +997,6 @@ gst_d3d11_h264_dec_decode_slice (GstH264Decoder * decoder,
GstH264Picture * picture, GstH264Slice * slice) GstH264Picture * picture, GstH264Slice * slice)
{ {
GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder); GstD3D11H264Dec *self = GST_D3D11_H264_DEC (decoder);
GstD3D11H264DecPrivate *priv = self->priv;
GstH264SPS *sps; GstH264SPS *sps;
GstH264PPS *pps; GstH264PPS *pps;
DXVA_PicParams_H264 pic_params = { 0, }; 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; 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)); 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)); sizeof (pic_params.FieldOrderCntList));
memcpy (pic_params.FrameNumList, priv->frame_num_list, memcpy (pic_params.FrameNumList, self->frame_num_list,
sizeof (pic_params.FrameNumList)); sizeof (pic_params.FrameNumList));
pic_params.UsedForReferenceFlags = priv->used_for_reference_flags; pic_params.UsedForReferenceFlags = self->used_for_reference_flags;
pic_params.NonExistingFrameFlags = priv->non_existing_frame_flags; pic_params.NonExistingFrameFlags = self->non_existing_frame_flags;
GST_TRACE_OBJECT (self, "Getting picture param decoder buffer"); GST_TRACE_OBJECT (self, "Getting picture param decoder buffer");
@ -1159,39 +1187,133 @@ gst_d3d11_h264_dec_decode_slice (GstH264Decoder * decoder,
return TRUE; return TRUE;
} }
typedef struct
{
guint width;
guint height;
} GstD3D11H264DecResolution;
void void
gst_d3d11_h264_dec_register (GstPlugin * plugin, GstD3D11Device * device, gst_d3d11_h264_dec_register (GstPlugin * plugin, GstD3D11Device * device,
guint rank) GstD3D11Decoder * decoder, guint rank, gboolean legacy)
{ {
GstD3D11Decoder *decoder; GType type;
GstVideoInfo info; gchar *type_name;
gchar *feature_name;
guint index = 0;
guint i;
gboolean ret; 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[] = { static const GUID *supported_profiles[] = {
&GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT, &GST_GUID_D3D11_DECODER_PROFILE_H264_IDCT_FGT,
&GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT, &GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
&GST_GUID_D3D11_DECODER_PROFILE_H264_VLD_FGT &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); ret = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
if (!decoder) { supported_profiles, G_N_ELEMENTS (supported_profiles), &profile);
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);
if (!ret) { if (!ret) {
GST_WARNING_OBJECT (device, "cannot open decoder device"); GST_WARNING_OBJECT (device, "decoder profile unavailable");
return; 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__ #ifndef __GST_D3D11_H264_DEC_H__
#define __GST_D3D11_H264_DEC_H__ #define __GST_D3D11_H264_DEC_H__
#include "gsth264decoder.h"
#include "gsth264picture.h"
#include "gstd3d11decoder.h" #include "gstd3d11decoder.h"
G_BEGIN_DECLS 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, void gst_d3d11_h264_dec_register (GstPlugin * plugin,
GstD3D11Device * device, GstD3D11Device * device,
guint rank); GstD3D11Decoder * decoder,
guint rank,
gboolean legacy);
G_END_DECLS G_END_DECLS

View File

@ -21,6 +21,8 @@
#include <config.h> #include <config.h>
#endif #endif
#include "gsth265decoder.h"
#include "gsth265picture.h"
#include "gstd3d11h265dec.h" #include "gstd3d11h265dec.h"
#include "gstd3d11memory.h" #include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h" #include "gstd3d11bufferpool.h"
@ -40,11 +42,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_h265_dec_debug);
enum enum
{ {
PROP_0, 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 */ /* copied from d3d11.h since mingw header doesn't define them */
DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN, DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN,
0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0); 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 */ /* worst case 16 + 4 margin */
#define NUM_OUTPUT_VIEW 20 #define NUM_OUTPUT_VIEW 20
static GstStaticPadTemplate sink_template = typedef struct _GstD3D11H265Dec
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
{ {
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]; DXVA_PicEntry_HEVC ref_pic_list[15];
INT pic_order_cnt_val_list[15]; INT pic_order_cnt_val_list[15];
UCHAR ref_pic_set_st_curr_before[8]; UCHAR ref_pic_set_st_curr_before[8];
UCHAR ref_pic_set_st_curr_after[8]; UCHAR ref_pic_set_st_curr_after[8];
UCHAR ref_pic_set_lt_curr[8]; UCHAR ref_pic_set_lt_curr[8];
}; } GstD3D11H265Dec;
#define parent_class gst_d3d11_h265_dec_parent_class typedef struct _GstD3D11H265DecClass
G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11H265Dec, {
gst_d3d11_h265_dec, GST_TYPE_H265_DECODER); 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, static void gst_d3d11_h265_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec); guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_d3d11_h265_dec_dispose (GObject * object); 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); GstH265Picture * picture);
static void 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); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstH265DecoderClass *h265decoder_class = GST_H265_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->get_property = gst_d3d11_h265_dec_get_property;
gobject_class->dispose = gst_d3d11_h265_dec_dispose; gobject_class->dispose = gst_d3d11_h265_dec_dispose;
g_object_class_install_property (gobject_class, PROP_ADAPTER, g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter", g_param_spec_uint ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)", "DXGI Adapter index for creating device",
-1, G_MAXINT32, DEFAULT_ADAPTER, 0, G_MAXUINT32, cdata->adapter,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
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 = element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_set_context); GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_set_context);
gst_element_class_set_static_metadata (element_class, long_name = g_strdup_printf ("Direct3D11 H.265 %s Decoder",
"Direct3D11 H.265 Video Decoder", cdata->description);
gst_element_class_set_metadata (element_class, long_name,
"Codec/Decoder/Video/Hardware", "Codec/Decoder/Video/Hardware",
"A Direct3D11 based H.265 video decoder", "A Direct3D11 based H.265 video decoder",
"Seungha Yang <seungha.yang@navercorp.com>"); "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_pad_template (element_class,
gst_element_class_add_static_pad_template (element_class, &src_template); 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->open = GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_h265_dec_close); 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 static void
gst_d3d11_h265_dec_init (GstD3D11H265Dec * self) 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->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 static void
gst_d3d11_h265_dec_get_property (GObject * object, guint prop_id, gst_d3d11_h265_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec) GValue * value, GParamSpec * pspec)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (object); GstD3D11H265DecClass *klass = GST_D3D11_H265_DEC_GET_CLASS (object);
switch (prop_id) { switch (prop_id) {
case PROP_ADAPTER: 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; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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) gst_d3d11_h265_dec_set_context (GstElement * element, GstContext * context)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (element); 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); GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
} }
@ -231,8 +262,9 @@ static gboolean
gst_d3d11_h265_dec_open (GstVideoDecoder * decoder) gst_d3d11_h265_dec_open (GstVideoDecoder * decoder)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (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)) { &self->device)) {
GST_ERROR_OBJECT (self, "Cannot create d3d11device"); GST_ERROR_OBJECT (self, "Cannot create d3d11device");
return FALSE; return FALSE;
@ -543,11 +575,9 @@ gst_d3d11_h265_dec_get_output_view_from_picture (GstD3D11H265Dec * self,
static gint static gint
gst_d3d11_h265_dec_get_ref_index (GstD3D11H265Dec * self, gint view_id) gst_d3d11_h265_dec_get_ref_index (GstD3D11H265Dec * self, gint view_id)
{ {
GstD3D11H265DecPrivate *priv = self->priv;
gint i; gint i;
for (i = 0; i < G_N_ELEMENTS (priv->ref_pic_list); i++) { for (i = 0; i < G_N_ELEMENTS (self->ref_pic_list); i++) {
if (priv->ref_pic_list[i].Index7Bits == view_id) if (self->ref_pic_list[i].Index7Bits == view_id)
return i; return i;
} }
@ -559,7 +589,6 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb) GstH265Picture * picture, GstH265Slice * slice, GstH265Dpb * dpb)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder); GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstD3D11H265DecPrivate *priv = self->priv;
GstD3D11DecoderOutputView *view; GstD3D11DecoderOutputView *view;
gint i, j; gint i, j;
GArray *dpb_array; GArray *dpb_array;
@ -578,21 +607,21 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
} }
for (i = 0; i < 15; i++) { for (i = 0; i < 15; i++) {
priv->ref_pic_list[i].bPicEntry = 0xff; self->ref_pic_list[i].bPicEntry = 0xff;
priv->pic_order_cnt_val_list[i] = 0; self->pic_order_cnt_val_list[i] = 0;
} }
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
priv->ref_pic_set_st_curr_before[i] = 0xff; self->ref_pic_set_st_curr_before[i] = 0xff;
priv->ref_pic_set_st_curr_after[i] = 0xff; self->ref_pic_set_st_curr_after[i] = 0xff;
priv->ref_pic_set_lt_curr[i] = 0xff; self->ref_pic_set_lt_curr[i] = 0xff;
} }
dpb_array = gst_h265_dpb_get_pictures_all (dpb); dpb_array = gst_h265_dpb_get_pictures_all (dpb);
GST_LOG_OBJECT (self, "DPB size %d", dpb_array->len); 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); GstH265Picture *other = g_array_index (dpb_array, GstH265Picture *, i);
GstD3D11DecoderOutputView *other_view; GstD3D11DecoderOutputView *other_view;
gint id = 0xff; gint id = 0xff;
@ -607,12 +636,12 @@ gst_d3d11_h265_dec_start_picture (GstH265Decoder * decoder,
if (other_view) if (other_view)
id = other_view->view_id; id = other_view->view_id;
priv->ref_pic_list[i].Index7Bits = id; self->ref_pic_list[i].Index7Bits = id;
priv->ref_pic_list[i].AssociatedFlag = other->long_term; self->ref_pic_list[i].AssociatedFlag = other->long_term;
priv->pic_order_cnt_val_list[i] = other->pic_order_cnt; 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; GstH265Picture *other = NULL;
gint id = 0xff; 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); 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; GstH265Picture *other = NULL;
gint id = 0xff; 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); 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; GstH265Picture *other = NULL;
gint id = 0xff; 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); 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); g_array_unref (dpb_array);
@ -1184,7 +1213,6 @@ gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder,
GstH265Picture * picture, GstH265Slice * slice) GstH265Picture * picture, GstH265Slice * slice)
{ {
GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder); GstD3D11H265Dec *self = GST_D3D11_H265_DEC (decoder);
GstD3D11H265DecPrivate *priv = self->priv;
GstH265PPS *pps; GstH265PPS *pps;
DXVA_PicParams_HEVC pic_params = { 0, }; DXVA_PicParams_HEVC pic_params = { 0, };
DXVA_Qmatrix_HEVC iq_matrix = { 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.IntraPicFlag = IS_IRAP (slice->nalu.type);
pic_params.CurrPicOrderCntVal = picture->pic_order_cnt; 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)); 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)); 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)); 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)); 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)); sizeof (pic_params.RefPicSetLtCurr));
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
@ -1380,37 +1408,190 @@ gst_d3d11_h265_dec_decode_slice (GstH265Decoder * decoder,
return TRUE; return TRUE;
} }
typedef struct
{
guint width;
guint height;
} GstD3D11H265DecResolution;
void void
gst_d3d11_h265_dec_register (GstPlugin * plugin, GstD3D11Device * device, gst_d3d11_h265_dec_register (GstPlugin * plugin, GstD3D11Device * device,
guint rank) GstD3D11Decoder * decoder, guint rank)
{ {
GstD3D11Decoder *decoder; GType type;
GstVideoInfo info; gchar *type_name;
gboolean ret; gchar *feature_name;
static const GUID *supported_profiles[] = { guint index = 0;
&GST_GUID_D3D11_DECODER_PROFILE_HEVC_VLD_MAIN, 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); have_main10 = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
if (!decoder) { &main_10_guid, 1, &profile);
GST_WARNING_OBJECT (device, "decoder interface unavailable"); 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; return;
} }
/* FIXME: DXVA does not provide API for query supported resolution if (have_main) {
* maybe we need some tries per standard resolution (e.g., HD, FullHD ...) profile = *main_guid;
* to check supported resolution */ format = DXGI_FORMAT_NV12;
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_NV12, 1280, 720); } else {
profile = *main_10_guid;
format = DXGI_FORMAT_P010;
}
ret = gst_d3d11_decoder_open (decoder, GST_D3D11_CODEC_H265, for (i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) {
&info, 1280, 720, NUM_OUTPUT_VIEW, supported_profiles, if (gst_d3d11_decoder_supports_resolution (decoder, &profile,
G_N_ELEMENTS (supported_profiles)); format, resolutions_to_check[i].width,
gst_object_unref (decoder); resolutions_to_check[i].height)) {
max_width = resolutions_to_check[i].width;
max_height = resolutions_to_check[i].height;
if (!ret) { GST_DEBUG_OBJECT (device,
GST_WARNING_OBJECT (device, "cannot open decoder 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; 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__ #ifndef __GST_D3D11_H265_DEC_H__
#define __GST_D3D11_H265_DEC_H__ #define __GST_D3D11_H265_DEC_H__
#include "gsth265decoder.h"
#include "gsth265picture.h"
#include "gstd3d11decoder.h" #include "gstd3d11decoder.h"
G_BEGIN_DECLS 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, void gst_d3d11_h265_dec_register (GstPlugin * plugin,
GstD3D11Device * device, GstD3D11Device * device,
GstD3D11Decoder * decoder,
guint rank); guint rank);
G_END_DECLS G_END_DECLS

View File

@ -52,6 +52,8 @@
#endif #endif
#include "gstd3d11vp9dec.h" #include "gstd3d11vp9dec.h"
#include "gstvp9decoder.h"
#include "gstvp9picture.h"
#include "gstd3d11memory.h" #include "gstd3d11memory.h"
#include "gstd3d11bufferpool.h" #include "gstd3d11bufferpool.h"
#include <string.h> #include <string.h>
@ -70,11 +72,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_vp9_dec_debug);
enum enum
{ {
PROP_0, 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 */ /* copied from d3d11.h since mingw header doesn't define them */
DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0, DEFINE_GUID (GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0,
0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e); 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 */ /* reference list 8 + 4 margin */
#define NUM_OUTPUT_VIEW 12 #define NUM_OUTPUT_VIEW 12
static GstStaticPadTemplate sink_template = typedef struct _GstD3D11Vp9Dec
GST_STATIC_PAD_TEMPLATE (GST_VIDEO_DECODER_SINK_NAME, {
GST_PAD_SINK, GST_PAD_ALWAYS, GstVp9Decoder parent;
GST_STATIC_CAPS ("video/x-vp9")
);
static GstStaticPadTemplate src_template = GstVideoCodecState *output_state;
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 }")));
#define parent_class gst_d3d11_vp9_dec_parent_class GstD3D11Device *device;
G_DEFINE_TYPE (GstD3D11Vp9Dec, gst_d3d11_vp9_dec, GST_TYPE_VP9_DECODER);
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, static void gst_d3d11_vp9_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec); guint prop_id, GValue * value, GParamSpec * pspec);
static void gst_d3d11_vp9_dec_set_context (GstElement * element, 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); GstVp9Picture * picture);
static void 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); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass); GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass); GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstVp9DecoderClass *vp9decoder_class = GST_VP9_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; gobject_class->get_property = gst_d3d11_vp9_dec_get_property;
g_object_class_install_property (gobject_class, PROP_ADAPTER, g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter", g_param_spec_uint ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)", "DXGI Adapter index for creating device",
-1, G_MAXINT32, DEFAULT_ADAPTER, 0, G_MAXUINT32, cdata->adapter,
G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
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 = element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_set_context); GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_set_context);
gst_element_class_set_static_metadata (element_class, long_name = g_strdup_printf ("Direct3D11 VP9 %s Decoder", cdata->description);
"Direct3D11 VP9 Video Decoder", gst_element_class_set_metadata (element_class, long_name,
"Codec/Decoder/Video/Hardware", "Codec/Decoder/Video/Hardware",
"A Direct3D11 based VP9 video decoder", "A Direct3D11 based VP9 video decoder",
"Seungha Yang <seungha.yang@navercorp.com>"); "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_pad_template (element_class,
gst_element_class_add_static_pad_template (element_class, &src_template); 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->open = GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d11_vp9_dec_close); 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 static void
gst_d3d11_vp9_dec_init (GstD3D11Vp9Dec * self) 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 static void
gst_d3d11_vp9_dec_get_property (GObject * object, guint prop_id, gst_d3d11_vp9_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec) GValue * value, GParamSpec * pspec)
{ {
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (object); GstD3D11Vp9DecClass *klass = GST_D3D11_VP9_DEC_GET_CLASS (object);
switch (prop_id) { switch (prop_id) {
case PROP_ADAPTER: 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; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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) gst_d3d11_vp9_dec_set_context (GstElement * element, GstContext * context)
{ {
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (element); 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); GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
} }
@ -236,8 +263,9 @@ static gboolean
gst_d3d11_vp9_dec_open (GstVideoDecoder * decoder) gst_d3d11_vp9_dec_open (GstVideoDecoder * decoder)
{ {
GstD3D11Vp9Dec *self = GST_D3D11_VP9_DEC (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)) { &self->device)) {
GST_ERROR_OBJECT (self, "Cannot create d3d11device"); GST_ERROR_OBJECT (self, "Cannot create d3d11device");
return FALSE; return FALSE;
@ -1139,37 +1167,170 @@ gst_d3d11_vp9_dec_end_picture (GstVp9Decoder * decoder, GstVp9Picture * picture)
return TRUE; return TRUE;
} }
typedef struct
{
guint width;
guint height;
} GstD3D11Vp9DecResolution;
void void
gst_d3d11_vp9_dec_register (GstPlugin * plugin, GstD3D11Device * device, gst_d3d11_vp9_dec_register (GstPlugin * plugin, GstD3D11Device * device,
guint rank) GstD3D11Decoder * decoder, guint rank)
{ {
GstD3D11Decoder *decoder; GType type;
GstVideoInfo info; gchar *type_name;
gboolean ret; gchar *feature_name;
static const GUID *supported_profiles[] = { guint index = 0;
&GST_GUID_D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0, 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); have_profile2 = gst_d3d11_decoder_get_supported_decoder_profile (decoder,
if (!decoder) { &profile2_guid, 1, &profile);
GST_WARNING_OBJECT (device, "decoder interface unavailable"); 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; return;
} }
/* FIXME: DXVA does not provide API for query supported resolution if (have_profile0) {
* maybe we need some tries per standard resolution (e.g., HD, FullHD ...) profile = *profile0_guid;
* to check supported resolution */ format = DXGI_FORMAT_NV12;
gst_video_info_set_format (&info, GST_VIDEO_FORMAT_NV12, 1280, 720); } else {
profile = *profile2_guid;
format = DXGI_FORMAT_P010;
}
ret = gst_d3d11_decoder_open (decoder, GST_D3D11_CODEC_VP9, for (i = 0; i < G_N_ELEMENTS (resolutions_to_check); i++) {
&info, 1280, 720, NUM_OUTPUT_VIEW, supported_profiles, if (gst_d3d11_decoder_supports_resolution (decoder, &profile,
G_N_ELEMENTS (supported_profiles)); format, resolutions_to_check[i].width,
gst_object_unref (decoder); resolutions_to_check[i].height)) {
max_width = resolutions_to_check[i].width;
max_height = resolutions_to_check[i].height;
if (!ret) { GST_DEBUG_OBJECT (device,
GST_WARNING_OBJECT (device, "cannot open decoder 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; 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__ #ifndef __GST_D3D11_VP9_DEC_H__
#define __GST_D3D11_VP9_DEC_H__ #define __GST_D3D11_VP9_DEC_H__
#include "gstvp9decoder.h"
#include "gstvp9picture.h"
#include "gstd3d11decoder.h" #include "gstd3d11decoder.h"
G_BEGIN_DECLS 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, void gst_d3d11_vp9_dec_register (GstPlugin * plugin,
GstD3D11Device * device, GstD3D11Device * device,
GstD3D11Decoder * decoder,
guint rank); guint rank);
G_END_DECLS G_END_DECLS

View File

@ -95,7 +95,8 @@ plugin_init (GstPlugin * plugin)
#ifdef HAVE_DXVA_H #ifdef HAVE_DXVA_H
/* DXVA2 API is availble since Windows 8 */ /* DXVA2 API is availble since Windows 8 */
if (gst_d3d11_is_windows_8_or_greater ()) { 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, GST_DEBUG_CATEGORY_INIT (gst_d3d11_h264_dec_debug,
"d3d11h264dec", 0, "Direct3D11 H.264 Video Decoder"); "d3d11h264dec", 0, "Direct3D11 H.264 Video Decoder");
@ -104,13 +105,34 @@ plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (gst_d3d11_h265_dec_debug, GST_DEBUG_CATEGORY_INIT (gst_d3d11_h265_dec_debug,
"d3d11h265dec", 0, "Direct3D11 H.265 Video Decoder"); "d3d11h265dec", 0, "Direct3D11 H.265 Video Decoder");
device = gst_d3d11_device_new (0); while ((device = gst_d3d11_device_new (i)) != NULL) {
if (device) { GstD3D11Decoder *decoder = NULL;
gst_d3d11_h264_dec_register (plugin, device, GST_RANK_SECONDARY); gboolean legacy;
gst_d3d11_h265_dec_register (plugin, device, GST_RANK_SECONDARY); gboolean hardware;
gst_d3d11_vp9_dec_register (plugin, device, GST_RANK_SECONDARY);
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 #endif