d3d11: Refactor d3d11 memory and dxgi format usage

* Create staging texture only when the CPU access is requested.
Note that we should avoid the CPU access to d3d11 memory as mush as possible.
Incoming d3d11upload and d3d11download will take this GPU memory upload/download.

* Upload/Download texture memory from/to staging only if it needed, similar to
GstGL PBO implementation.

* Define more dxgi formats for future usage (e.g., color conversion, dxva2 decoder).
Because I420_* formats are not supported formats by dxgi, each plane should
be handled likewise GstGL separately, but NV12/P10 formats might be supported ones.
So we decide the number of d3d11memory per GstBuffer for video memory depending on
OS version and dxgi format. For instance, if NV12 is supported by OS,
only one d3d11memory with DXGI_FORMAT_NV12 texture can be allocated by this commit.
One use case of such texture is DXVA. In case DXVA decoder, it might need to produce decoded data
to one DXGI_FORMAT_NV12 instead of seperate Y and UV planes.
Such behavior will be controlled via configuration of GstD3D11BufferPool and
default configuration is separate resources per plane.
This commit is contained in:
Seungha Yang 2019-11-06 19:37:33 +09:00 committed by GStreamer Merge Bot
parent d4c75f32dd
commit 6c3311a39e
11 changed files with 786 additions and 361 deletions

View file

@ -48,12 +48,13 @@ typedef struct _GstD3D11AllocationParams GstD3D11AllocationParams;
typedef struct _GstD3D11Memory GstD3D11Memory;
typedef struct _GstD3D11Allocator GstD3D11Allocator;
typedef struct _GstD3D11AllocatorClass GstD3D11AllocatorClass;
typedef struct _GstD3D11AllocatorPrivate GstD3D11AllocatorPrivate;
typedef struct _GstD3D11BufferPool GstD3D11BufferPool;
typedef struct _GstD3D11BufferPoolClass GstD3D11BufferPoolClass;
typedef struct _GstD3D11BufferPoolPrivate GstD3D11BufferPoolPrivate;
typedef struct _GstD3D11Format GstD3D11Format;
G_END_DECLS
#endif /* __GST_D3D11_FWD_H__ */

View file

@ -32,7 +32,9 @@ struct _GstD3D11BufferPoolPrivate
{
GstD3D11Device *device;
GstD3D11Allocator *allocator;
GstCaps *caps;
/* initial buffer used for calculating buffer size */
GstBuffer *initial_buffer;
gboolean add_videometa;
GstD3D11AllocationParams *d3d11_params;
@ -80,9 +82,10 @@ gst_d3d11_buffer_pool_dispose (GObject * object)
if (priv->d3d11_params)
gst_d3d11_allocation_params_free (priv->d3d11_params);
priv->d3d11_params = NULL;
gst_clear_buffer (&priv->initial_buffer);
gst_clear_object (&priv->device);
gst_clear_object (&priv->allocator);
gst_clear_caps (&priv->caps);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@ -90,10 +93,9 @@ gst_d3d11_buffer_pool_dispose (GObject * object)
static const gchar **
gst_d3d11_buffer_pool_get_options (GstBufferPool * pool)
{
static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META,
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT,
NULL
};
/* NOTE: d3d11 memory does not support alignment */
static const gchar *options[] = { GST_BUFFER_POOL_OPTION_VIDEO_META, NULL };
return options;
}
@ -105,11 +107,8 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
GstVideoInfo info;
GstCaps *caps = NULL;
guint min_buffers, max_buffers;
guint max_align, n;
GstAllocator *allocator = NULL;
GstAllocationParams alloc_params;
gboolean ret = TRUE;
D3D11_TEXTURE2D_DESC *desc;
if (!gst_buffer_pool_config_get_params (config, &caps, NULL, &min_buffers,
&max_buffers))
@ -125,17 +124,14 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height,
caps);
if (!gst_buffer_pool_config_get_allocator (config, &allocator, &alloc_params))
if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
goto wrong_config;
gst_caps_replace (&priv->caps, caps);
if (priv->allocator)
gst_object_unref (priv->allocator);
gst_clear_buffer (&priv->initial_buffer);
gst_clear_object (&priv->allocator);
if (allocator) {
if (!GST_IS_D3D11_ALLOCATOR (allocator)) {
gst_object_unref (allocator);
goto wrong_allocator;
} else {
priv->allocator = gst_object_ref (allocator);
@ -152,59 +148,50 @@ gst_d3d11_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
gst_d3d11_allocation_params_free (priv->d3d11_params);
priv->d3d11_params =
gst_buffer_pool_config_get_d3d11_allocation_params (config);
if (!priv->d3d11_params)
priv->d3d11_params = gst_d3d11_allocation_params_new (&alloc_params,
&info, NULL);
if (!priv->d3d11_params) {
/* allocate memory with resource format by default */
priv->d3d11_params = gst_d3d11_allocation_params_new (&info,
GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT);
}
#ifndef GST_DISABLE_GST_DEBUG
{
D3D11_TEXTURE2D_DESC *desc;
gint i;
desc = priv->d3d11_params->desc;
desc = &priv->d3d11_params->desc;
GST_LOG_OBJECT (self, "Direct3D11 Allocation params");
for (i = 0; GST_VIDEO_MAX_PLANES; i++) {
if (desc[i].Format == DXGI_FORMAT_UNKNOWN)
break;
GST_LOG_OBJECT (self, "\t[plane %d] %dx%d, DXGI format %d",
i, desc[i].Width, desc[i].Height, desc[i].Format);
GST_LOG_OBJECT (self, "\t[plane %d] MipLevel %d, ArraySize %d",
i, desc[i].MipLevels, desc[i].ArraySize);
GST_LOG_OBJECT (self,
"\t[plane %d] SampleDesc.Count %d, SampleDesc.Quality %d",
i, desc[i].SampleDesc.Count, desc[i].SampleDesc.Quality);
GST_LOG_OBJECT (self, "\t[plane %d] Usage %d", i, desc[i].Usage);
GST_LOG_OBJECT (self,
"\t[plane %d] BindFlags 0x%x", i, desc[i].BindFlags);
GST_LOG_OBJECT (self,
"\t[plane %d] CPUAccessFlags 0x%x", i, desc[i].CPUAccessFlags);
GST_LOG_OBJECT (self,
"\t[plane %d] MiscFlags 0x%x", i, desc[i].MiscFlags);
}
}
#endif
GST_LOG_OBJECT (self, "Direct3D11 Allocation params");
GST_LOG_OBJECT (self, "\t%dx%d, DXGI format %d",
desc->Width, desc->Height, desc->Format);
GST_LOG_OBJECT (self, "\tMipLevel %d, ArraySize %d",
desc->MipLevels, desc->ArraySize);
GST_LOG_OBJECT (self, "\tSampleDesc.Count %d, SampleDesc.Quality %d",
desc->SampleDesc.Count, desc->SampleDesc.Quality);
GST_LOG_OBJECT (self, "\tUsage %d", desc->Usage);
GST_LOG_OBJECT (self, "\tBindFlags 0x%x", desc->BindFlags);
GST_LOG_OBJECT (self, "\tCPUAccessFlags 0x%x", desc->CPUAccessFlags);
GST_LOG_OBJECT (self, "\tMiscFlags 0x%x", desc->MiscFlags);
gst_d3d11_buffer_pool_alloc (pool, &priv->initial_buffer, NULL);
max_align = alloc_params.align;
if (gst_buffer_pool_config_has_option (config,
GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
priv->add_videometa = TRUE;
gst_buffer_pool_config_get_video_alignment (config,
&priv->d3d11_params->align);
for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n)
max_align |= priv->d3d11_params->align.stride_align[n];
for (n = 0; n < GST_VIDEO_MAX_PLANES; ++n)
priv->d3d11_params->align.stride_align[n] = max_align;
gst_video_info_align (&priv->d3d11_params->info,
&priv->d3d11_params->align);
gst_buffer_pool_config_set_video_alignment (config,
&priv->d3d11_params->align);
if (!priv->initial_buffer) {
GST_ERROR_OBJECT (pool, "Could not create initial buffer");
return FALSE;
}
if (alloc_params.align < max_align) {
GST_WARNING_OBJECT (pool, "allocation params alignment %u is smaller "
"than the max specified video stride alignment %u, fixing",
(guint) alloc_params.align, max_align);
alloc_params.align = priv->d3d11_params->parent.align = max_align;
gst_buffer_pool_config_set_allocator (config, allocator, &alloc_params);
gst_allocation_params_copy (&alloc_params);
}
self->buffer_size = gst_buffer_get_size (priv->initial_buffer);
gst_buffer_pool_config_set_params (config,
caps, GST_VIDEO_INFO_SIZE (&priv->d3d11_params->info), min_buffers,
max_buffers);
caps, self->buffer_size, min_buffers, max_buffers);
return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config) && ret;
@ -240,34 +227,71 @@ gst_d3d11_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
GstD3D11BufferPoolPrivate *priv = self->priv;
GstMemory *mem;
GstBuffer *buf;
GstVideoInfo *info = &priv->d3d11_params->info;
GstD3D11AllocationParams *d3d11_params = priv->d3d11_params;
GstVideoInfo *info = &d3d11_params->info;
gint n_texture = 0;
gint i;
gsize offset[GST_VIDEO_MAX_PLANES] = { 0, };
mem = gst_d3d11_allocator_alloc (priv->allocator, priv->d3d11_params);
/* consume pre-allocated buffer if any */
if (G_UNLIKELY (priv->initial_buffer)) {
*buffer = priv->initial_buffer;
priv->initial_buffer = NULL;
if (!mem) {
GST_ERROR_OBJECT (self, "cannot create texture memory");
return GST_FLOW_ERROR;
return GST_FLOW_OK;
}
buf = gst_buffer_new ();
gst_buffer_append_memory (buf, mem);
if ((d3d11_params->flags & GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) ==
GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) {
for (n_texture = 0; n_texture < GST_VIDEO_INFO_N_PLANES (info); n_texture++) {
d3d11_params->plane = n_texture;
mem = gst_d3d11_allocator_alloc (priv->allocator, d3d11_params);
if (!mem)
goto error;
gst_buffer_append_memory (buf, mem);
}
} else {
d3d11_params->plane = 0;
mem = gst_d3d11_allocator_alloc (priv->allocator, priv->d3d11_params);
n_texture++;
if (!mem)
goto error;
gst_buffer_append_memory (buf, mem);
}
/* calculate offset */
for (i = 0; i < n_texture && i < GST_VIDEO_MAX_PLANES - 1; i++) {
offset[i + 1] = offset[i] +
d3d11_params->stride[i] * GST_VIDEO_INFO_COMP_HEIGHT (info, i);
}
if (priv->add_videometa) {
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
GST_DEBUG_OBJECT (self, "adding GstVideoMeta");
gst_buffer_add_video_meta_full (buf, GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
dmem->offset, dmem->stride);
offset, d3d11_params->stride);
}
*buffer = buf;
return GST_FLOW_OK;
error:
gst_buffer_unref (buf);
GST_ERROR_OBJECT (self, "cannot create texture memory");
return GST_FLOW_ERROR;
}
GstD3D11BufferPool *
GstBufferPool *
gst_d3d11_buffer_pool_new (GstD3D11Device * device)
{
GstD3D11BufferPool *pool;
@ -281,7 +305,7 @@ gst_d3d11_buffer_pool_new (GstD3D11Device * device)
pool->priv->device = gst_object_ref (device);
pool->priv->allocator = alloc;
return pool;
return GST_BUFFER_POOL_CAST (pool);
}
GstD3D11AllocationParams *

View file

@ -39,6 +39,9 @@ struct _GstD3D11BufferPool
{
GstBufferPool parent;
/* re-calculated buffer size based on d3d11 pitch and stride */
guint buffer_size;
/*< private >*/
GstD3D11BufferPoolPrivate *priv;
@ -55,7 +58,7 @@ struct _GstD3D11BufferPoolClass
GType gst_d3d11_buffer_pool_get_type (void);
GstD3D11BufferPool * gst_d3d11_buffer_pool_new (GstD3D11Device *device);
GstBufferPool * gst_d3d11_buffer_pool_new (GstD3D11Device *device);
GstD3D11AllocationParams * gst_buffer_pool_config_get_d3d11_allocation_params (GstStructure * config);

307
sys/d3d11/gstd3d11format.c Normal file
View file

@ -0,0 +1,307 @@
/* GStreamer
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstd3d11format.h"
#include "gstd3d11utils.h"
#include "gstd3d11device.h"
#ifndef GST_DISABLE_GST_DEBUG
#define GST_CAT_DEFAULT ensure_debug_category()
static GstDebugCategory *
ensure_debug_category (void)
{
static gsize cat_gonce = 0;
if (g_once_init_enter (&cat_gonce)) {
gsize cat_done;
cat_done = (gsize) _gst_debug_category_new ("d3d11format", 0,
"Direct3D11 Format");
g_once_init_leave (&cat_gonce, cat_done);
}
return (GstDebugCategory *) cat_gonce;
}
#else
#define ensure_debug_category() /* NOOP */
#endif /* GST_DISABLE_GST_DEBUG */
/* Following formats were introduced since Windows 8
* DXGI_FORMAT_AYUV
* DXGI_FORMAT_NV12
* DXGI_FORMAT_P010
* ...
*/
static const GstD3D11Format legacy_d3d11_formats[] = {
/* RGB formats */
{GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM,
{DXGI_FORMAT_B8G8R8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM,
{DXGI_FORMAT_R10G10B10A2_UNORM,}},
/* YUV packed */
{GST_VIDEO_FORMAT_VUYA, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
/* YUV semi-planner */
{GST_VIDEO_FORMAT_NV12, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM}},
{GST_VIDEO_FORMAT_P010_10LE, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM}},
/* YUV planner */
{GST_VIDEO_FORMAT_I420, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM}},
{GST_VIDEO_FORMAT_I420_10LE, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM}},
/* LAST */
{GST_VIDEO_FORMAT_UNKNOWN,},
};
static const GstD3D11Format d3d11_formats[] = {
/* RGB formats */
{GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM,
{DXGI_FORMAT_B8G8R8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
{GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM,
{DXGI_FORMAT_R10G10B10A2_UNORM,}},
/* YUV packed */
{GST_VIDEO_FORMAT_VUYA, DXGI_FORMAT_AYUV,
{DXGI_FORMAT_R8G8B8A8_UNORM,}},
/* YUV semi-planner */
{GST_VIDEO_FORMAT_NV12, DXGI_FORMAT_NV12,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8G8_UNORM}},
{GST_VIDEO_FORMAT_P010_10LE, DXGI_FORMAT_P010,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16G16_UNORM}},
/* YUV planner */
{GST_VIDEO_FORMAT_I420, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UNORM}},
{GST_VIDEO_FORMAT_I420_10LE, DXGI_FORMAT_UNKNOWN,
{DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UNORM}},
/* LAST */
{GST_VIDEO_FORMAT_UNKNOWN,},
};
static GstD3D11Format *
get_supported_d3d11_formats (void)
{
static gsize format_once = 0;
static GstD3D11Format *supported_d3d11_formats = NULL;
if (g_once_init_enter (&format_once)) {
if (gst_d3d11_is_windows_8_or_greater ())
supported_d3d11_formats = (GstD3D11Format *) d3d11_formats;
else
supported_d3d11_formats = (GstD3D11Format *) legacy_d3d11_formats;
g_once_init_leave (&format_once, 1);
}
return supported_d3d11_formats;
}
GstVideoFormat
gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format)
{
gint i;
GstD3D11Format *format_list;
if (format == DXGI_FORMAT_UNKNOWN)
return GST_VIDEO_FORMAT_UNKNOWN;
format_list = get_supported_d3d11_formats ();
for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) {
if (format_list[i].dxgi_format == format)
return format_list[i].format;
}
return GST_VIDEO_FORMAT_UNKNOWN;
}
guint
gst_d3d11_dxgi_format_n_planes (DXGI_FORMAT format)
{
switch (format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_AYUV:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16G16_UNORM:
return 1;
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
return 2;
default:
break;
}
return 0;
}
gboolean
gst_d3d11_dxgi_format_get_size (DXGI_FORMAT format, guint width, guint height,
guint pitch, gsize offset[GST_VIDEO_MAX_PLANES],
gint stride[GST_VIDEO_MAX_PLANES], gsize * size)
{
g_return_val_if_fail (format != DXGI_FORMAT_UNKNOWN, FALSE);
switch (format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_AYUV:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16G16_UNORM:
offset[0] = 0;
stride[0] = pitch;
*size = pitch * height;
break;
case DXGI_FORMAT_NV12:
case DXGI_FORMAT_P010:
offset[0] = 0;
stride[0] = pitch;
offset[1] = offset[0] + stride[0] * height;
stride[1] = pitch;
*size = offset[1] + stride[1] * GST_ROUND_UP_2 (height / 2);
break;
default:
return FALSE;
}
GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT
" (dxgi format:%d, %dx%d, Pitch %d)",
*size, format, width, height, pitch);
return TRUE;
}
const GstD3D11Format *
gst_d3d11_format_from_gst (GstVideoFormat format)
{
gint i;
GstD3D11Format *format_list;
format_list = get_supported_d3d11_formats ();
for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) {
if (format_list[i].format == format)
return &format_list[i];
}
return NULL;
}
typedef struct
{
GstCaps *caps;
D3D11_FORMAT_SUPPORT flags;
} SupportCapsData;
static void
gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
SupportCapsData * data)
{
ID3D11Device *d3d11_device;
HRESULT hr;
gint i;
GValue v_list = G_VALUE_INIT;
GstCaps *supported_caps;
GstD3D11Format *format_list;
d3d11_device = gst_d3d11_device_get_device_handle (device);
g_value_init (&v_list, GST_TYPE_LIST);
format_list = get_supported_d3d11_formats ();
for (i = 0; format_list[i].format != GST_VIDEO_FORMAT_UNKNOWN; i++) {
UINT format_support = 0;
GstVideoFormat format;
if (format_list[i].dxgi_format == DXGI_FORMAT_UNKNOWN)
continue;
format = format_list[i].format;
hr = ID3D11Device_CheckFormatSupport (d3d11_device,
format_list[i].dxgi_format, &format_support);
if (SUCCEEDED (hr) && ((format_support & data->flags) == data->flags)) {
GValue v_str = G_VALUE_INIT;
g_value_init (&v_str, G_TYPE_STRING);
GST_LOG_OBJECT (device, "d3d11 device can support %s with flags 0x%x",
gst_video_format_to_string (format), data->flags);
g_value_set_string (&v_str, gst_video_format_to_string (format));
gst_value_list_append_and_take_value (&v_list, &v_str);
}
}
supported_caps = gst_caps_new_simple ("video/x-raw",
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
gst_caps_set_value (supported_caps, "format", &v_list);
g_value_unset (&v_list);
data->caps = supported_caps;
}
/**
* gst_d3d11_device_get_supported_caps:
* @device: a #GstD3DDevice
* @flags: D3D11_FORMAT_SUPPORT flags
*
* Check supported format with given flags
*
* Returns: a #GstCaps representing supported format
*/
GstCaps *
gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags)
{
SupportCapsData data;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
data.caps = NULL;
data.flags = flags;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_get_supported_caps_internal, &data);
return data.caps;
}

View file

@ -0,0 +1,63 @@
/* GStreamer
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef __GST_D3D11_FORMAT_H__
#define __GST_D3D11_FORMAT_H__
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstd3d11_fwd.h"
#define GST_D3D11_FORMATS \
"{ BGRA, RGBA, RGB10A2, RGB10A2_LE, VUYA, NV12, P010_10LE, I420, I420_10LE }"
G_BEGIN_DECLS
struct _GstD3D11Format
{
GstVideoFormat format;
/* direct mapping to dxgi format if applicable */
DXGI_FORMAT dxgi_format;
/* formats for texture processing */
DXGI_FORMAT resource_format[GST_VIDEO_MAX_COMPONENTS];
};
GstVideoFormat gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format);
guint gst_d3d11_dxgi_format_n_planes (DXGI_FORMAT format);
gboolean gst_d3d11_dxgi_format_get_size (DXGI_FORMAT format,
guint width,
guint height,
guint pitch,
gsize offset[GST_VIDEO_MAX_PLANES],
gint stride[GST_VIDEO_MAX_PLANES],
gsize *size);
const GstD3D11Format * gst_d3d11_format_from_gst (GstVideoFormat format);
GstCaps * gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags);
G_END_DECLS
#endif /* __GST_D3D11_FORMAT_H__ */

View file

@ -30,33 +30,72 @@ GST_DEBUG_CATEGORY_STATIC (gst_d3d11_allocator_debug);
#define GST_CAT_DEFAULT gst_d3d11_allocator_debug
GstD3D11AllocationParams *
gst_d3d11_allocation_params_new (GstAllocationParams * alloc_params,
GstVideoInfo * info, GstVideoAlignment * align)
gst_d3d11_allocation_params_new (GstVideoInfo * info,
GstD3D11AllocationFlags flags)
{
GstD3D11AllocationParams *ret;
const GstD3D11Format *d3d11_format;
gint i;
g_return_val_if_fail (alloc_params != NULL, NULL);
g_return_val_if_fail (info != NULL, NULL);
d3d11_format = gst_d3d11_format_from_gst (GST_VIDEO_INFO_FORMAT (info));
if (!d3d11_format) {
GST_WARNING ("Couldn't get d3d11 format");
return NULL;
}
ret = g_new0 (GstD3D11AllocationParams, 1);
memcpy (&ret->info, info, sizeof (GstVideoInfo));
if (align) {
ret->align = *align;
ret->info = *info;
ret->d3d11_format = d3d11_format;
/* Usage Flag
* https://docs.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_usage
*
* +----------------------------------------------------------+
* | Resource Usage | Default | Dynamic | Immutable | Staging |
* +----------------+---------+---------+-----------+---------+
* | GPU-Read | Yes | Yes | Yes | Yes |
* | GPU-Write | Yes | | | Yes |
* | CPU-Read | | | | Yes |
* | CPU-Write | | Yes | | Yes |
* +----------------------------------------------------------+
*/
/* If corresponding dxgi format is undefined, use resource format instead */
if (d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN ||
(flags & GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) ==
GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT) {
flags |= GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT;
for (i = 0; i < GST_VIDEO_INFO_N_PLANES (info); i++) {
g_assert (d3d11_format->resource_format[i] != DXGI_FORMAT_UNKNOWN);
ret->desc[i].Width = GST_VIDEO_INFO_COMP_WIDTH (info, i);
ret->desc[i].Height = GST_VIDEO_INFO_COMP_HEIGHT (info, i);
ret->desc[i].MipLevels = 1;
ret->desc[i].ArraySize = 1;
ret->desc[i].Format = d3d11_format->resource_format[i];
ret->desc[i].SampleDesc.Count = 1;
ret->desc[i].SampleDesc.Quality = 0;
ret->desc[i].Usage = D3D11_USAGE_DEFAULT;
/* User must set proper BindFlags and MiscFlags manually */
}
} else {
gst_video_alignment_reset (&ret->align);
g_assert (d3d11_format->dxgi_format != DXGI_FORMAT_UNKNOWN);
ret->desc[0].Width = GST_VIDEO_INFO_WIDTH (info);
ret->desc[0].Height = GST_VIDEO_INFO_HEIGHT (info);
ret->desc[0].MipLevels = 1;
ret->desc[0].ArraySize = 1;
ret->desc[0].Format = d3d11_format->dxgi_format;
ret->desc[0].SampleDesc.Count = 1;
ret->desc[0].SampleDesc.Quality = 0;
ret->desc[0].Usage = D3D11_USAGE_DEFAULT;
}
ret->desc.Width = GST_VIDEO_INFO_WIDTH (info);
ret->desc.Height = GST_VIDEO_INFO_HEIGHT (info);
ret->desc.MipLevels = 1;
ret->desc.ArraySize = 1;
ret->desc.Format =
gst_d3d11_dxgi_format_from_gst (GST_VIDEO_INFO_FORMAT (info));
ret->desc.SampleDesc.Count = 1;
ret->desc.SampleDesc.Quality = 0;
ret->desc.Usage = D3D11_USAGE_DEFAULT;
/* User must set proper BindFlags and MiscFlags manually */
ret->flags = flags;
return ret;
}
@ -88,7 +127,7 @@ G_DEFINE_BOXED_TYPE (GstD3D11AllocationParams, gst_d3d11_allocation_params,
G_DEFINE_TYPE (GstD3D11Allocator, gst_d3d11_allocator, GST_TYPE_ALLOCATOR);
static inline D3D11_MAP
_gst_map_flags_to_d3d11 (GstMapFlags flags)
gst_map_flags_to_d3d11 (GstMapFlags flags)
{
if ((flags & GST_MAP_READWRITE) == GST_MAP_READWRITE)
return D3D11_MAP_READ_WRITE;
@ -103,7 +142,7 @@ _gst_map_flags_to_d3d11 (GstMapFlags flags)
}
static ID3D11Texture2D *
_create_staging_texture (GstD3D11Device * device,
create_staging_texture (GstD3D11Device * device,
const D3D11_TEXTURE2D_DESC * ref)
{
D3D11_TEXTURE2D_DESC desc = { 0, };
@ -120,18 +159,33 @@ _create_staging_texture (GstD3D11Device * device,
return gst_d3d11_device_create_texture (device, &desc, NULL);
}
typedef struct
{
ID3D11Resource *dst;
ID3D11Resource *src;
} D3D11CopyTextureData;
static void
copy_texture (GstD3D11Device * device, D3D11CopyTextureData * data)
{
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
data->dst, 0, 0, 0, 0, data->src, 0, NULL);
}
typedef struct
{
GstD3D11Memory *mem;
D3D11_MAP map_flag;
D3D11_MAP map_type;
gboolean ret;
} D3D11MapData;
static void
_map_cpu_access_data (GstD3D11Device * device, gpointer data)
map_cpu_access_data (GstD3D11Device * device, D3D11MapData * map_data)
{
D3D11MapData *map_data = (D3D11MapData *) data;
GstD3D11Memory *dmem = map_data->mem;
HRESULT hr;
ID3D11Resource *texture = (ID3D11Resource *) dmem->texture;
@ -139,14 +193,17 @@ _map_cpu_access_data (GstD3D11Device * device, gpointer data)
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
ID3D11DeviceContext_CopySubresourceRegion (device_context,
staging, 0, 0, 0, 0, texture, 0, NULL);
if (GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD)) {
ID3D11DeviceContext_CopySubresourceRegion (device_context,
staging, 0, 0, 0, 0, texture, 0, NULL);
}
hr = ID3D11DeviceContext_Map (device_context,
staging, 0, map_data->map_flag, 0, &dmem->map);
staging, 0, map_data->map_type, 0, &dmem->map);
if (FAILED (hr)) {
GST_ERROR ("Failed to map staging texture (0x%x)", (guint) hr);
GST_ERROR_OBJECT (GST_MEMORY_CAST (dmem)->allocator,
"Failed to map staging texture (0x%x)", (guint) hr);
map_data->ret = FALSE;
}
@ -158,64 +215,111 @@ gst_d3d11_memory_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11)
g_mutex_lock (&dmem->lock);
if ((flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
if (dmem->staging &&
GST_MEMORY_FLAG_IS_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD)) {
D3D11CopyTextureData data;
data.dst = (ID3D11Resource *) dmem->texture;
data.src = (ID3D11Resource *) dmem->staging;
gst_d3d11_device_thread_add (dmem->device,
(GstD3D11DeviceThreadFunc) copy_texture, &data);
}
GST_MEMORY_FLAG_UNSET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE)
GST_MINI_OBJECT_FLAG_SET (dmem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
g_assert (dmem->texture != NULL);
g_mutex_unlock (&dmem->lock);
return dmem->texture;
}
if (dmem->cpu_map_count == 0) {
D3D11MapData map_data;
GstD3D11Device *device = GST_D3D11_ALLOCATOR (mem->allocator)->device;
/* Allocate staging texture for CPU access */
if (!dmem->staging) {
dmem->staging = create_staging_texture (dmem->device, &dmem->desc);
if (!dmem->staging) {
GST_ERROR_OBJECT (mem->allocator, "Couldn't create staging texture");
g_mutex_unlock (&dmem->lock);
return NULL;
}
/* first memory, always need download to staging */
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
}
map_data.mem = dmem;
map_data.map_flag = _gst_map_flags_to_d3d11 (flags);
map_data.map_type = gst_map_flags_to_d3d11 (flags);
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
_map_cpu_access_data, &map_data);
gst_d3d11_device_thread_add (dmem->device, (GstD3D11DeviceThreadFunc)
map_cpu_access_data, &map_data);
if (!map_data.ret) {
GST_ERROR_OBJECT (mem->allocator, "Couldn't map staging texture");
g_mutex_unlock (&dmem->lock);
if (!map_data.ret)
return NULL;
}
}
if ((flags & GST_MAP_WRITE) == GST_MAP_WRITE)
dmem->need_upload = TRUE;
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
GST_MEMORY_FLAG_UNSET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
dmem->cpu_map_count++;
g_mutex_unlock (&dmem->lock);
return dmem->map.pData;
}
static void
_unmap_cpu_access_data (GstD3D11Device * device, gpointer data)
unmap_cpu_access_data (GstD3D11Device * device, gpointer data)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) data;
ID3D11Resource *texture = (ID3D11Resource *) dmem->texture;
ID3D11Resource *staging = (ID3D11Resource *) dmem->staging;
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
ID3D11DeviceContext_Unmap (device_context, staging, 0);
if (dmem->need_upload) {
ID3D11DeviceContext_CopySubresourceRegion (device_context, texture,
0, 0, 0, 0, staging, 0, NULL);
}
dmem->need_upload = FALSE;
}
static void
gst_d3d11_memory_unmap_full (GstMemory * mem, GstMapInfo * info)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
GstD3D11Device *device = GST_D3D11_ALLOCATOR (mem->allocator)->device;
if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11)
g_mutex_lock (&dmem->lock);
if ((info->flags & GST_MAP_D3D11) == GST_MAP_D3D11) {
if ((info->flags & GST_MAP_WRITE) == GST_MAP_WRITE)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
g_mutex_unlock (&dmem->lock);
return;
}
if ((info->flags & GST_MAP_WRITE))
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD);
dmem->cpu_map_count--;
if (dmem->cpu_map_count > 0)
if (dmem->cpu_map_count > 0) {
g_mutex_unlock (&dmem->lock);
return;
}
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
_unmap_cpu_access_data, dmem);
gst_d3d11_device_thread_add (dmem->device, (GstD3D11DeviceThreadFunc)
unmap_cpu_access_data, dmem);
g_mutex_unlock (&dmem->lock);
}
static GstMemory *
@ -232,19 +336,30 @@ gst_d3d11_allocator_dummy_alloc (GstAllocator * allocator, gsize size,
g_return_val_if_reached (NULL);
}
static void
release_texture (GstD3D11Device * device, GstD3D11Memory * mem)
{
if (mem->texture)
ID3D11Texture2D_Release (mem->texture);
if (mem->staging)
ID3D11Texture2D_Release (mem->staging);
}
static void
gst_d3d11_allocator_free (GstAllocator * allocator, GstMemory * mem)
{
GstD3D11Memory *dmem = (GstD3D11Memory *) mem;
GstD3D11Device *device = GST_D3D11_ALLOCATOR (allocator)->device;
GstD3D11Device *device = dmem->device;
if (dmem->texture)
gst_d3d11_device_release_texture (device, dmem->texture);
if (dmem->texture || dmem->staging)
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) release_texture, dmem);
if (dmem->staging)
gst_d3d11_device_release_texture (device, dmem->staging);
gst_object_unref (device);
g_mutex_clear (&dmem->lock);
g_slice_free (GstD3D11Memory, dmem);
g_free (dmem);
}
static void
@ -299,38 +414,40 @@ gst_d3d11_allocator_new (GstD3D11Device * device)
return allocator;
}
typedef struct _CalculateSizeData
typedef struct
{
ID3D11Texture2D *staging;
GstVideoInfo *info;
gsize offset[GST_VIDEO_MAX_PLANES];
ID3D11Resource *staging;
D3D11_TEXTURE2D_DESC *desc;
gint stride[GST_VIDEO_MAX_PLANES];
gsize size;
gboolean ret;
} CalculateSizeData;
} CalSizeData;
static void
_calculate_buffer_size (GstD3D11Device * device, CalculateSizeData * data)
calculate_mem_size (GstD3D11Device * device, CalSizeData * data)
{
HRESULT hr;
D3D11_MAPPED_SUBRESOURCE map;
gsize offset[GST_VIDEO_MAX_PLANES];
ID3D11DeviceContext *device_context =
gst_d3d11_device_get_device_context_handle (device);
hr = ID3D11DeviceContext_Map (device_context,
(ID3D11Resource *) data->staging, 0, GST_MAP_READWRITE, 0, &map);
data->staging, 0, D3D11_MAP_READ, 0, &map);
if (FAILED (hr)) {
GST_ERROR ("Failed to map staging texture (0x%x)", (guint) hr);
GST_ERROR_OBJECT (device,
"Failed to map staging texture (0x%x)", (guint) hr);
data->ret = FALSE;
return;
}
ID3D11DeviceContext_Unmap (device_context, (ID3D11Resource *) data->staging,
0);
data->ret = gst_d3d11_dxgi_format_get_size (data->desc->Format,
data->desc->Width, data->desc->Height, map.RowPitch,
offset, data->stride, &data->size);
data->ret = gst_d3d11_calculate_buffer_size (data->info,
map.RowPitch, data->offset, data->stride, &data->size);
ID3D11DeviceContext_Unmap (device_context, data->staging, 0);
}
GstMemory *
@ -339,68 +456,81 @@ gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator,
{
GstD3D11Memory *mem;
GstD3D11Device *device;
GstAllocationParams *alloc_params;
gsize size, maxsize;
ID3D11Texture2D *texture = NULL;
ID3D11Texture2D *staging = NULL;
CalculateSizeData data;
gint i;
D3D11_TEXTURE2D_DESC *desc;
gsize *size;
gboolean is_first = FALSE;
g_return_val_if_fail (GST_IS_D3D11_ALLOCATOR (allocator), NULL);
g_return_val_if_fail (params != NULL, NULL);
device = allocator->device;
desc = &params->desc[params->plane];
size = &params->size[params->plane];
texture = gst_d3d11_device_create_texture (device, &params->desc, NULL);
if (*size == 0)
is_first = TRUE;
texture = gst_d3d11_device_create_texture (device, desc, NULL);
if (!texture) {
GST_ERROR_OBJECT (allocator, "Couldn't create texture");
goto error;
}
staging = _create_staging_texture (device, &params->desc);
if (!staging) {
GST_ERROR_OBJECT (allocator, "Couldn't create staging texture");
goto error;
/* per plane, allocated staging texture to calculate actual size,
* stride, and offset */
if (is_first) {
CalSizeData data;
gint num_plane;
gint i;
staging = create_staging_texture (device, desc);
if (!staging) {
GST_ERROR_OBJECT (allocator, "Couldn't create staging texture");
goto error;
}
data.staging = (ID3D11Resource *) staging;
data.desc = desc;
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) calculate_mem_size, &data);
num_plane = gst_d3d11_dxgi_format_n_planes (desc->Format);
for (i = 0; i < num_plane; i++) {
params->stride[params->plane + i] = data.stride[i];
}
*size = data.size;
}
/* try map staging texture to get actual stride and size */
memset (&data, 0, sizeof (CalculateSizeData));
data.staging = staging;
data.info = &params->info;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
_calculate_buffer_size, &data);
if (!data.ret) {
GST_ERROR_OBJECT (allocator, "Couldn't calculate stride");
goto error;
}
alloc_params = (GstAllocationParams *) params;
maxsize = size = data.size;
maxsize += alloc_params->prefix + alloc_params->padding;
mem = g_slice_new0 (GstD3D11Memory);
mem = g_new0 (GstD3D11Memory, 1);
gst_memory_init (GST_MEMORY_CAST (mem),
alloc_params->flags, GST_ALLOCATOR_CAST (allocator), NULL, maxsize,
alloc_params->align, 0, size);
0, GST_ALLOCATOR_CAST (allocator), NULL, *size, 0, 0, *size);
mem->desc = params->desc;
g_mutex_init (&mem->lock);
mem->info = params->info;
mem->plane = params->plane;
mem->desc = *desc;
mem->texture = texture;
mem->staging = staging;
mem->device = gst_object_ref (device);
for (i = 0; i < GST_VIDEO_MAX_PLANES; i++) {
mem->offset[i] = data.offset[i];
mem->stride[i] = data.stride[i];
}
if (staging)
GST_MINI_OBJECT_FLAG_SET (mem, GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD);
return GST_MEMORY_CAST (mem);
error:
if (texture)
gst_d3d11_device_release_texture (device, texture);
if (staging)
gst_d3d11_device_release_texture (device, staging);
gst_d3d11_device_release_texture (device, texture);
return NULL;
}

View file

@ -25,6 +25,7 @@
#include <gst/video/video.h>
#include "gstd3d11_fwd.h"
#include "gstd3d11format.h"
G_BEGIN_DECLS
@ -52,35 +53,70 @@ G_BEGIN_DECLS
*/
#define GST_MAP_D3D11 (GST_MAP_FLAG_LAST << 1)
/**
* GstD3D11AllocationFlags:
* GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT: Allocate texture with resource format
* per planes instead of the direct use of DXGI format
*/
typedef enum
{
GST_D3D11_ALLOCATION_FLAG_USE_RESOURCE_FORMAT = (1 << 0),
} GstD3D11AllocationFlags;
/**
* GstD3D11MemoryTransfer:
* @GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD: the texture needs downloading
* to the staging texture memory
* @GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD: the staging texture needs uploading
* to the texture
*/
typedef enum
{
GST_D3D11_MEMORY_TRANSFER_NEED_DOWNLOAD = (GST_MEMORY_FLAG_LAST << 0),
GST_D3D11_MEMORY_TRANSFER_NEED_UPLOAD = (GST_MEMORY_FLAG_LAST << 1)
} GstD3D11MemoryTransfer;
struct _GstD3D11AllocationParams
{
/* Texture description per plane */
D3D11_TEXTURE2D_DESC desc[GST_VIDEO_MAX_PLANES];
GstVideoInfo info;
const GstD3D11Format *d3d11_format;
/* size and stride of staging texture, set by allocator */
gint stride[GST_VIDEO_MAX_PLANES];
gsize size[GST_VIDEO_MAX_PLANES];
/* Current target plane for allocation */
guint plane;
GstD3D11AllocationFlags flags;
/*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE];
};
struct _GstD3D11Memory
{
GstMemory mem;
GstMapFlags map_flags;
gint cpu_map_count;
/*< public > */
GstD3D11Device *device;
ID3D11Texture2D *texture;
ID3D11Texture2D *staging;
GstVideoInfo info;
guint plane;
D3D11_TEXTURE2D_DESC desc;
D3D11_MAPPED_SUBRESOURCE map;
gboolean need_upload;
gsize offset[GST_VIDEO_MAX_PLANES];
gint stride[GST_VIDEO_MAX_PLANES];
};
struct _GstD3D11AllocationParams
{
GstAllocationParams parent;
D3D11_TEXTURE2D_DESC desc;
GstVideoInfo info;
GstVideoAlignment align;
/*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE];
GMutex lock;
gint cpu_map_count;
};
struct _GstD3D11Allocator
@ -103,9 +139,8 @@ struct _GstD3D11AllocatorClass
GType gst_d3d11_allocation_params_get_type (void);
GstD3D11AllocationParams * gst_d3d11_allocation_params_new (GstAllocationParams * alloc_params,
GstVideoInfo * info,
GstVideoAlignment * align);
GstD3D11AllocationParams * gst_d3d11_allocation_params_new (GstVideoInfo * info,
GstD3D11AllocationFlags flags);
GstD3D11AllocationParams * gst_d3d11_allocation_params_copy (GstD3D11AllocationParams * src);
@ -120,7 +155,6 @@ GstMemory * gst_d3d11_allocator_alloc (GstD3D11Allocator * allocator
gboolean gst_is_d3d11_memory (GstMemory * mem);
G_END_DECLS
#endif /* __GST_D3D11_MEMORY_H__ */

View file

@ -24,6 +24,9 @@
#include "gstd3d11utils.h"
#include "gstd3d11device.h"
#include <windows.h>
#include <versionhelpers.h>
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_utils_debug);
GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
@ -54,157 +57,6 @@ _init_context_debug (void)
#define GST_CAT_DEFAULT _init_d3d11_utils_debug()
static const struct
{
GstVideoFormat gst_format;
DXGI_FORMAT dxgi_format;
} gst_dxgi_format_map[] = {
/* TODO: add more formats */
{
GST_VIDEO_FORMAT_BGRA, DXGI_FORMAT_B8G8R8A8_UNORM}, {
GST_VIDEO_FORMAT_RGBA, DXGI_FORMAT_R8G8B8A8_UNORM}, {
GST_VIDEO_FORMAT_RGB10A2_LE, DXGI_FORMAT_R10G10B10A2_UNORM}
};
GstVideoFormat
gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (gst_dxgi_format_map); i++) {
if (gst_dxgi_format_map[i].dxgi_format == format)
return gst_dxgi_format_map[i].gst_format;
}
return GST_VIDEO_FORMAT_UNKNOWN;
}
DXGI_FORMAT
gst_d3d11_dxgi_format_from_gst (GstVideoFormat format)
{
gint i;
for (i = 0; i < G_N_ELEMENTS (gst_dxgi_format_map); i++) {
if (gst_dxgi_format_map[i].gst_format == format)
return gst_dxgi_format_map[i].dxgi_format;
}
return DXGI_FORMAT_UNKNOWN;
}
typedef struct
{
GstCaps *caps;
D3D11_FORMAT_SUPPORT flags;
} SupportCapsData;
static void
gst_d3d11_device_get_supported_caps_internal (GstD3D11Device * device,
SupportCapsData * data)
{
ID3D11Device *d3d11_device;
HRESULT hr;
gint i;
GValue v_list = G_VALUE_INIT;
GstCaps *supported_caps;
d3d11_device = gst_d3d11_device_get_device_handle (device);
g_value_init (&v_list, GST_TYPE_LIST);
for (i = 0; i < G_N_ELEMENTS (gst_dxgi_format_map); i++) {
UINT format_support = 0;
GstVideoFormat format = gst_dxgi_format_map[i].gst_format;
hr = ID3D11Device_CheckFormatSupport (d3d11_device,
gst_dxgi_format_map[i].dxgi_format, &format_support);
if (SUCCEEDED (hr) && ((format_support & data->flags) == data->flags)) {
GValue v_str = G_VALUE_INIT;
g_value_init (&v_str, G_TYPE_STRING);
GST_LOG_OBJECT (device, "d3d11 device can support %s with flags 0x%x",
gst_video_format_to_string (format), data->flags);
g_value_set_string (&v_str, gst_video_format_to_string (format));
gst_value_list_append_and_take_value (&v_list, &v_str);
}
}
supported_caps = gst_caps_new_simple ("video/x-raw",
"width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
"framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
gst_caps_set_value (supported_caps, "format", &v_list);
g_value_unset (&v_list);
data->caps = supported_caps;
}
/**
* gst_d3d11_device_get_supported_caps:
* @device: a #GstD3DDevice
* @flags: D3D11_FORMAT_SUPPORT flags
*
* Check supported format with given flags
*
* Returns: a #GstCaps representing supported format
*/
GstCaps *
gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags)
{
SupportCapsData data;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
_init_d3d11_utils_debug ();
_init_context_debug ();
data.caps = NULL;
data.flags = flags;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_get_supported_caps_internal, &data);
return data.caps;
}
gboolean
gst_d3d11_calculate_buffer_size (GstVideoInfo * info, guint pitch,
gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES],
gsize * size)
{
g_return_val_if_fail (info != NULL, FALSE);
_init_d3d11_utils_debug ();
_init_context_debug ();
switch (GST_VIDEO_INFO_FORMAT (info)) {
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGB10A2_LE:
offset[0] = 0;
stride[0] = pitch;
*size = pitch * GST_VIDEO_INFO_HEIGHT (info);
break;
case GST_VIDEO_FORMAT_NV12:
offset[0] = 0;
stride[0] = pitch;
offset[1] = offset[0] + stride[0] * GST_VIDEO_INFO_COMP_HEIGHT (info, 0);
stride[1] = pitch;
*size = offset[1] + stride[1] * GST_VIDEO_INFO_COMP_HEIGHT (info, 1);
break;
default:
return FALSE;
}
GST_LOG ("Calculated buffer size: %" G_GSIZE_FORMAT
" (%s %dx%d, Pitch %d)", *size,
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)),
GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), pitch);
return TRUE;
}
/**
* gst_d3d11_handle_set_context:
* @element: a #GstElement
@ -487,3 +339,19 @@ gst_d3d11_ensure_element_data (GstElement * element, gint adapter,
return TRUE;
}
gboolean
gst_d3d11_is_windows_8_or_greater (void)
{
static gsize version_once = 0;
static gboolean ret = FALSE;
if (g_once_init_enter (&version_once)) {
if (IsWindows8OrGreater ())
ret = TRUE;
g_once_init_leave (&version_once, 1);
}
return ret;
}

View file

@ -27,19 +27,6 @@
G_BEGIN_DECLS
GstVideoFormat gst_d3d11_dxgi_format_to_gst (DXGI_FORMAT format);
DXGI_FORMAT gst_d3d11_dxgi_format_from_gst (GstVideoFormat format);
GstCaps * gst_d3d11_device_get_supported_caps (GstD3D11Device * device,
D3D11_FORMAT_SUPPORT flags);
gboolean gst_d3d11_calculate_buffer_size (GstVideoInfo * info,
guint pitch,
gsize offset[GST_VIDEO_MAX_PLANES],
gint stride[GST_VIDEO_MAX_PLANES],
gsize *size);
gboolean gst_d3d11_handle_set_context (GstElement * element,
GstContext * context,
gint adapter,
@ -53,6 +40,8 @@ gboolean gst_d3d11_ensure_element_data (GstElement * element,
gint adapter,
GstD3D11Device ** device);
gboolean gst_d3d11_is_windows_8_or_greater (void);
G_END_DECLS
#endif /* __GST_D3D11_UTILS_H__ */

View file

@ -246,6 +246,7 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
D3D11_TEXTURE2D_DESC desc = { 0, };
ID3D11Texture2D *staging;
GError *error = NULL;
const GstD3D11Format *d3d11_format = NULL;
GST_DEBUG_OBJECT (self, "set caps %" GST_PTR_FORMAT, caps);
@ -263,6 +264,11 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
if (!gst_video_info_from_caps (&self->info, caps))
goto invalid_format;
d3d11_format =
gst_d3d11_format_from_gst (GST_VIDEO_INFO_FORMAT (&self->info));
if (!d3d11_format || d3d11_format->dxgi_format == DXGI_FORMAT_UNKNOWN)
goto invalid_format;
video_width = GST_VIDEO_INFO_WIDTH (&self->info);
video_height = GST_VIDEO_INFO_HEIGHT (&self->info);
video_par_n = GST_VIDEO_INFO_PAR_N (&self->info);
@ -316,8 +322,7 @@ gst_d3d11_video_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
if (GST_VIDEO_SINK_WIDTH (self) <= 0 || GST_VIDEO_SINK_HEIGHT (self) <= 0)
goto no_display_size;
self->dxgi_format =
gst_d3d11_dxgi_format_from_gst (GST_VIDEO_INFO_FORMAT (&self->info));
self->dxgi_format = d3d11_format->dxgi_format;
if (!self->window_id)
gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (self));
@ -523,7 +528,7 @@ gst_d3d11_video_sink_propose_allocation (GstBaseSink * sink, GstQuery * query)
if (need_pool) {
GST_DEBUG_OBJECT (self, "create new pool");
pool = (GstBufferPool *) gst_d3d11_buffer_pool_new (self->device);
pool = gst_d3d11_buffer_pool_new (self->device);
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, caps, size, 2,
DXGI_MAX_SWAP_CHAIN_BUFFERS);

View file

@ -6,6 +6,7 @@ d3d11_sources = [
'gstd3d11videosink.c',
'gstd3d11window.c',
'plugin.c',
'gstd3d11format.c',
]
have_d3d11 = false