gstreamer/sys/d3d11/gstd3d11device.c
Seungha Yang 5c3879ace6 d3d11videosink: Add new Direct3D11 video render plugin
Direct3D11 was shipped as part of Windows7 and it's obviously
primary graphics API on Windows.

This plugin includes HDR10 rendering if following requirements are satisfied
* IDXGISwapChain4::SetHDRMetaData is available (decleared in dxgi1_5.h)
* Display can support DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 color space
* Upstream provides 10 bitdepth format with smpte-st 2084 static metadata
2019-07-08 08:31:47 +00:00

898 lines
23 KiB
C

/* GStreamer
* Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstd3d11device.h"
#include "gmodule.h"
#ifdef HAVE_D3D11SDKLAYER_H
#include <d3d11sdklayers.h>
#endif
GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
GST_DEBUG_CATEGORY_STATIC (gst_d3d11_device_debug);
#define GST_CAT_DEFAULT gst_d3d11_device_debug
#ifdef HAVE_D3D11SDKLAYER_H
static GModule *sdk_layer = NULL;
#endif
enum
{
PROP_0,
PROP_ADAPTER
};
#define DEFAULT_ADAPTER -1
struct _GstD3D11DevicePrivate
{
gint adapter;
ID3D11Device *device;
ID3D11DeviceContext *device_context;
IDXGIFactory1 *factory;
GstD3D11DXGIFactoryVersion factory_ver;
ID3D11VideoDevice *video_device;
ID3D11VideoContext *video_context;
GMutex lock;
GCond cond;
GThread *thread;
GThread *active_thread;
GMainLoop *loop;
GMainContext *main_context;
#ifdef HAVE_D3D11SDKLAYER_H
ID3D11Debug *debug;
ID3D11InfoQueue *info_queue;
#endif
};
#define gst_d3d11_device_parent_class parent_class
G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Device, gst_d3d11_device, GST_TYPE_OBJECT);
static void gst_d3d11_device_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_d3d11_device_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_d3d11_device_constructed (GObject * object);
static void gst_d3d11_device_dispose (GObject * object);
static void gst_d3d11_device_finalize (GObject * object);
static gpointer gst_d3d11_device_thread_func (gpointer data);
#ifdef HAVE_D3D11SDKLAYER_H
static gboolean
gst_d3d11_device_enable_debug_layer (void)
{
static volatile gsize _init = 0;
if (g_once_init_enter (&_init)) {
sdk_layer = g_module_open ("d3d11sdklayers.dll", G_MODULE_BIND_LAZY);
if (!sdk_layer)
sdk_layer = g_module_open ("d3d11_1sdklayers.dll", G_MODULE_BIND_LAZY);
g_once_init_leave (&_init, 1);
}
return ! !sdk_layer;
}
static gboolean
gst_d3d11_device_get_message (GstD3D11Device * self)
{
GstD3D11DevicePrivate *priv = self->priv;
D3D11_MESSAGE *msg;
SIZE_T msg_len = 0;
HRESULT hr;
UINT64 num_msg, i;
num_msg = ID3D11InfoQueue_GetNumStoredMessages (priv->info_queue);
for (i = 0; i < num_msg; i++) {
hr = ID3D11InfoQueue_GetMessage (priv->info_queue, i, NULL, &msg_len);
if (FAILED (hr) || msg_len == 0) {
return G_SOURCE_CONTINUE;
}
msg = (D3D11_MESSAGE *) g_malloc0 (msg_len);
hr = ID3D11InfoQueue_GetMessage (priv->info_queue, i, msg, &msg_len);
GST_TRACE_OBJECT (self, "D3D11 Message - %s", msg->pDescription);
g_free (msg);
}
ID3D11InfoQueue_ClearStoredMessages (priv->info_queue);
return G_SOURCE_CONTINUE;
}
#endif
static void
gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->set_property = gst_d3d11_device_set_property;
gobject_class->get_property = gst_d3d11_device_get_property;
gobject_class->constructed = gst_d3d11_device_constructed;
gobject_class->dispose = gst_d3d11_device_dispose;
gobject_class->finalize = gst_d3d11_device_finalize;
g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_int ("adapter", "Adapter",
"Adapter index for creating device (-1 for default)",
-1, G_MAXINT32, DEFAULT_ADAPTER,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug,
"d3d11device", 0, "d3d11 device");
GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
}
static void
gst_d3d11_device_init (GstD3D11Device * self)
{
GstD3D11DevicePrivate *priv;
priv = gst_d3d11_device_get_instance_private (self);
priv->adapter = DEFAULT_ADAPTER;
g_mutex_init (&priv->lock);
g_cond_init (&priv->cond);
priv->main_context = g_main_context_new ();
priv->loop = g_main_loop_new (priv->main_context, FALSE);
self->priv = priv;
}
static void
_relase_adapter (IDXGIAdapter1 * adapter)
{
IDXGIAdapter1_Release (adapter);
}
static void
gst_d3d11_device_constructed (GObject * object)
{
GstD3D11Device *self = GST_D3D11_DEVICE (object);
GstD3D11DevicePrivate *priv = self->priv;
IDXGIAdapter1 *adapter = NULL;
GList *adapter_list = NULL;
GList *hw_adapter_list = NULL;
IDXGIFactory1 *factory = NULL;
HRESULT hr;
guint i;
guint num_adapter = 0;
UINT d3d11_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
static const D3D_DRIVER_TYPE driver_types[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_UNKNOWN
};
static const D3D_FEATURE_LEVEL feature_levels[] = {
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3,
D3D_FEATURE_LEVEL_9_2,
D3D_FEATURE_LEVEL_9_1
};
D3D_FEATURE_LEVEL selected_level;
#ifdef HAVE_DXGI_1_5_H
hr = CreateDXGIFactory1 (&IID_IDXGIFactory5, (void **) &factory);
if (FAILED (hr)) {
GST_INFO_OBJECT (self, "IDXGIFactory5 was unavailable");
factory = NULL;
}
priv->factory_ver = GST_D3D11_DXGI_FACTORY_5;
#endif
if (!factory) {
priv->factory_ver = GST_D3D11_DXGI_FACTORY_1;
hr = CreateDXGIFactory1 (&IID_IDXGIFactory1, (void **) &factory);
}
if (FAILED (hr)) {
GST_ERROR_OBJECT (self, "cannot create dxgi factory, hr: 0x%x", (guint) hr);
goto error;
}
while (IDXGIFactory1_EnumAdapters1 (factory, num_adapter,
&adapter) != DXGI_ERROR_NOT_FOUND) {
DXGI_ADAPTER_DESC1 desc;
hr = IDXGIAdapter1_GetDesc1 (adapter, &desc);
if (SUCCEEDED (hr)) {
gchar *vender = NULL;
vender = g_utf16_to_utf8 (desc.Description, -1, NULL, NULL, NULL);
GST_DEBUG_OBJECT (self,
"adapter index %d: D3D11 device vendor-id: 0x%04x, device-id: 0x%04x, "
"Flags: 0x%x, %s",
num_adapter, desc.VendorId, desc.DeviceId, desc.Flags, vender);
g_free (vender);
/* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */
if ((desc.Flags & 0x2) != 0x2) {
hw_adapter_list = g_list_append (hw_adapter_list, adapter);
IDXGIAdapter1_AddRef (adapter);
}
}
adapter_list = g_list_append (adapter_list, adapter);
num_adapter++;
if (priv->adapter >= 0 && priv->adapter < num_adapter)
break;
}
adapter = NULL;
if (priv->adapter >= 0) {
if (priv->adapter >= num_adapter) {
GST_WARNING_OBJECT (self,
"Requested index %d is out of scope for adapter", priv->adapter);
} else {
adapter = (IDXGIAdapter1 *) g_list_nth_data (adapter_list, priv->adapter);
}
} else if (hw_adapter_list) {
adapter = (IDXGIAdapter1 *) g_list_nth_data (hw_adapter_list, 0);
} else if (adapter_list) {
adapter = (IDXGIAdapter1 *) g_list_nth_data (adapter_list, 0);
}
if (adapter)
IDXGIAdapter1_AddRef (adapter);
#ifdef HAVE_D3D11SDKLAYER_H
if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_TRACE) {
/* DirectX SDK should be installed on system for this */
if (gst_d3d11_device_enable_debug_layer ()) {
GST_INFO_OBJECT (self, "sdk layer library was loaded");
d3d11_flags |= D3D11_CREATE_DEVICE_DEBUG;
}
}
#endif
if (adapter) {
hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels),
D3D11_SDK_VERSION, &priv->device, &selected_level,
&priv->device_context);
if (FAILED (hr)) {
/* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
NULL, d3d11_flags, &feature_levels[1],
G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device,
&selected_level, &priv->device_context);
}
if (SUCCEEDED (hr)) {
GST_DEBUG_OBJECT (self, "Selected feature level 0x%x", selected_level);
}
} else {
for (i = 0; i < G_N_ELEMENTS (driver_types); i++) {
hr = D3D11CreateDevice (NULL, driver_types[i], NULL,
d3d11_flags,
feature_levels, G_N_ELEMENTS (feature_levels),
D3D11_SDK_VERSION, &priv->device, &selected_level,
&priv->device_context);
if (FAILED (hr)) {
/* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
hr = D3D11CreateDevice (NULL, driver_types[i], NULL,
d3d11_flags,
&feature_levels[1], G_N_ELEMENTS (feature_levels) - 1,
D3D11_SDK_VERSION, &priv->device, &selected_level,
&priv->device_context);
}
if (SUCCEEDED (hr)) {
GST_DEBUG_OBJECT (self, "Selected driver type 0x%x, feature level 0x%x",
driver_types[i], selected_level);
break;
}
}
}
if (FAILED (hr)) {
GST_ERROR_OBJECT (self, "cannot create d3d11 device, hr: 0x%x", (guint) hr);
goto error;
}
priv->factory = factory;
if (adapter)
IDXGIAdapter1_Release (adapter);
if (adapter_list)
g_list_free_full (adapter_list, (GDestroyNotify) _relase_adapter);
if (hw_adapter_list)
g_list_free_full (hw_adapter_list, (GDestroyNotify) _relase_adapter);
#ifdef HAVE_D3D11SDKLAYER_H
if ((d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == D3D11_CREATE_DEVICE_DEBUG) {
ID3D11Debug *debug;
ID3D11InfoQueue *info_queue;
hr = ID3D11Device_QueryInterface (priv->device,
&IID_ID3D11Debug, (void **) &debug);
if (SUCCEEDED (hr)) {
GST_DEBUG_OBJECT (self, "D3D11Debug interface available");
ID3D11Debug_ReportLiveDeviceObjects (debug, D3D11_RLDO_DETAIL);
priv->debug = debug;
}
hr = ID3D11Device_QueryInterface (priv->device,
&IID_ID3D11InfoQueue, (void **) &info_queue);
if (SUCCEEDED (hr)) {
GSource *source;
GST_DEBUG_OBJECT (self, "D3D11InfoQueue interface available");
priv->info_queue = info_queue;
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) gst_d3d11_device_get_message,
self, NULL);
g_source_attach (source, priv->main_context);
g_source_unref (source);
}
}
#endif
g_mutex_lock (&priv->lock);
priv->thread = g_thread_new ("GstD3D11Device",
(GThreadFunc) gst_d3d11_device_thread_func, self);
while (!g_main_loop_is_running (priv->loop))
g_cond_wait (&priv->cond, &priv->lock);
g_mutex_unlock (&priv->lock);
G_OBJECT_CLASS (parent_class)->constructed (object);
return;
error:
if (factory)
IDXGIFactory1_Release (factory);
if (adapter)
IDXGIAdapter1_Release (adapter);
if (adapter_list)
g_list_free_full (adapter_list, (GDestroyNotify) _relase_adapter);
if (hw_adapter_list)
g_list_free_full (hw_adapter_list, (GDestroyNotify) _relase_adapter);
G_OBJECT_CLASS (parent_class)->constructed (object);
return;
}
static void
gst_d3d11_device_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstD3D11Device *self = GST_D3D11_DEVICE (object);
GstD3D11DevicePrivate *priv = self->priv;
switch (prop_id) {
case PROP_ADAPTER:
priv->adapter = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_d3d11_device_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D11Device *self = GST_D3D11_DEVICE (object);
GstD3D11DevicePrivate *priv = self->priv;
switch (prop_id) {
case PROP_ADAPTER:
g_value_set_int (value, priv->adapter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_d3d11_device_dispose (GObject * object)
{
GstD3D11Device *self = GST_D3D11_DEVICE (object);
GstD3D11DevicePrivate *priv = self->priv;
GST_LOG_OBJECT (self, "dispose");
if (priv->loop) {
g_main_loop_quit (priv->loop);
}
if (priv->thread) {
g_thread_join (priv->thread);
priv->thread = NULL;
}
if (priv->loop) {
g_main_loop_unref (priv->loop);
priv->loop = NULL;
}
if (priv->main_context) {
g_main_context_unref (priv->main_context);
priv->main_context = NULL;
}
#ifdef HAVE_D3D11SDKLAYER_H
if (priv->debug) {
ID3D11Debug_Release (priv->debug);
priv->debug = NULL;
}
if (priv->info_queue) {
ID3D11InfoQueue_ClearStoredMessages (priv->info_queue);
ID3D11InfoQueue_Release (priv->info_queue);
priv->info_queue = NULL;
}
#endif
if (priv->device) {
ID3D11Device_Release (priv->device);
priv->device = NULL;
}
if (priv->device_context) {
ID3D11DeviceContext_Release (priv->device_context);
priv->device_context = NULL;
}
if (priv->video_device) {
ID3D11VideoDevice_Release (priv->video_device);
priv->video_device = NULL;
}
if (priv->video_context) {
ID3D11VideoContext_Release (priv->video_context);
priv->video_context = NULL;
}
if (priv->factory) {
IDXGIFactory1_Release (priv->factory);
priv->factory = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_d3d11_device_finalize (GObject * object)
{
GstD3D11Device *self = GST_D3D11_DEVICE (object);
GstD3D11DevicePrivate *priv = self->priv;
GST_LOG_OBJECT (self, "finalize");
g_mutex_clear (&priv->lock);
g_cond_clear (&priv->cond);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
running_cb (gpointer user_data)
{
GstD3D11Device *self = GST_D3D11_DEVICE (user_data);
GstD3D11DevicePrivate *priv = self->priv;
GST_TRACE_OBJECT (self, "Main loop running now");
g_mutex_lock (&priv->lock);
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->lock);
return G_SOURCE_REMOVE;
}
static gpointer
gst_d3d11_device_thread_func (gpointer data)
{
GstD3D11Device *self = GST_D3D11_DEVICE (data);
GstD3D11DevicePrivate *priv = self->priv;
GSource *source;
GST_DEBUG_OBJECT (self, "Enter loop");
g_main_context_push_thread_default (priv->main_context);
source = g_idle_source_new ();
g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
g_source_attach (source, priv->main_context);
g_source_unref (source);
priv->active_thread = g_thread_self ();
g_main_loop_run (priv->loop);
g_main_context_pop_thread_default (priv->main_context);
GST_DEBUG_OBJECT (self, "Exit loop");
return NULL;
}
/**
* gst_d3d11_device_new:
* @adapter: the index of adapter for creating d3d11 device (-1 for default)
*
* Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter or %NULL
* when failed to create D3D11 device with given adapter index.
*/
GstD3D11Device *
gst_d3d11_device_new (gint adapter)
{
GstD3D11Device *device = NULL;
GstD3D11DevicePrivate *priv;
static volatile gsize _init = 0;
if (g_once_init_enter (&_init)) {
GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug, "d3d11device", 0,
"d3d11 device");
g_once_init_leave (&_init, 1);
}
device = g_object_new (GST_TYPE_D3D11_DEVICE, "adapter", adapter, NULL);
priv = device->priv;
if (!priv->device || !priv->device_context) {
GST_ERROR ("Cannot create d3d11 device");
g_object_unref (device);
device = NULL;
}
return device;
}
/**
* gst_d3d11_device_get_device:
* @device: a #GstD3D11Device
*
* Used for various D3D11 APIs directly.
* Caller must not destroy returned device object.
*
* Returns: (transfer none): the ID3D11Device
*/
ID3D11Device *
gst_d3d11_device_get_device (GstD3D11Device * device)
{
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
return device->priv->device;
}
/**
* gst_d3d11_device_get_device_context:
* @device: a #GstD3D11Device
*
* Used for various D3D11 APIs directly.
* Caller must not destroy returned device object.
*
* Returns: (transfer none): the ID3D11DeviceContext
*/
ID3D11DeviceContext *
gst_d3d11_device_get_device_context (GstD3D11Device * device)
{
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
return device->priv->device_context;
}
GstD3D11DXGIFactoryVersion
gst_d3d11_device_get_chosen_dxgi_factory_version (GstD3D11Device * device)
{
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device),
GST_D3D11_DXGI_FACTORY_UNKNOWN);
return device->priv->factory_ver;
}
typedef struct
{
GstD3D11Device *device;
GstD3D11DeviceThreadFunc func;
gpointer data;
gboolean fired;
} MessageData;
static gboolean
gst_d3d11_device_message_callback (MessageData * msg)
{
GstD3D11Device *self = msg->device;
GstD3D11DevicePrivate *priv = self->priv;
msg->func (self, msg->data);
g_mutex_lock (&priv->lock);
msg->fired = TRUE;
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->lock);
return G_SOURCE_REMOVE;
}
/**
* gst_d3d11_device_thread_add:
* @device: a #GstD3D11Device
* @func: (scope call): a #GstD3D11DeviceThreadFunc
* @data: (closure): user data to call @func with
*
* Execute @func in the D3DDevice thread of @device with @data
*
* MT-safe
*/
void
gst_d3d11_device_thread_add (GstD3D11Device * device,
GstD3D11DeviceThreadFunc func, gpointer data)
{
GstD3D11DevicePrivate *priv;
MessageData msg = { 0, };
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
g_return_if_fail (func != NULL);
priv = device->priv;
if (priv->active_thread == g_thread_self ()) {
func (device, data);
return;
}
msg.device = gst_object_ref (device);
msg.func = func;
msg.data = data;
msg.fired = FALSE;
g_main_context_invoke (priv->main_context,
(GSourceFunc) gst_d3d11_device_message_callback, &msg);
g_mutex_lock (&priv->lock);
while (!msg.fired)
g_cond_wait (&priv->cond, &priv->lock);
g_mutex_unlock (&priv->lock);
gst_object_unref (device);
}
typedef struct
{
IDXGISwapChain *swap_chain;
const DXGI_SWAP_CHAIN_DESC *desc;
} CreateSwapChainData;
static void
gst_d3d11_device_create_swap_chain_internal (GstD3D11Device * device,
CreateSwapChainData * data)
{
GstD3D11DevicePrivate *priv = device->priv;
HRESULT hr;
hr = IDXGIFactory1_CreateSwapChain (priv->factory, (IUnknown *) priv->device,
(DXGI_SWAP_CHAIN_DESC *) data->desc, &data->swap_chain);
if (FAILED (hr)) {
GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
(guint) hr);
data->swap_chain = NULL;
}
}
/**
* gst_d3d11_device_create_swap_chain:
* @device: a #GstD3D11Device
* @desc: a DXGI_SWAP_CHAIN_DESC structure for swapchain
*
* Creat a IDXGISwapChain object. Caller must release returned swap chain object
* via IDXGISwapChain_Release()
*
* Returns: (transfer full) (nullable): a new IDXGISwapChain or %NULL
* when failed to create swap chain with given @desc
*/
IDXGISwapChain *
gst_d3d11_device_create_swap_chain (GstD3D11Device * device,
const DXGI_SWAP_CHAIN_DESC * desc)
{
CreateSwapChainData data = { 0, };
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
data.swap_chain = NULL;
data.desc = desc;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_create_swap_chain_internal, &data);
return data.swap_chain;
}
static void
gst_d3d11_device_release_swap_chain_internal (GstD3D11Device * device,
IDXGISwapChain * swap_chain)
{
IDXGISwapChain_Release (swap_chain);
}
/**
* gst_d3d11_device_release_swap_chain:
* @device: a #GstD3D11Device
* @swap_chain: a IDXGISwapChain
*
* Release a @swap_chain from device thread
*
*/
void
gst_d3d11_device_release_swap_chain (GstD3D11Device * device,
IDXGISwapChain * swap_chain)
{
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
gst_d3d11_device_thread_add (device,
(GstD3D11DeviceThreadFunc) gst_d3d11_device_release_swap_chain_internal,
swap_chain);
}
typedef struct
{
ID3D11Texture2D *texture;
const D3D11_TEXTURE2D_DESC *desc;
const D3D11_SUBRESOURCE_DATA *inital_data;
} CreateTextureData;
static void
gst_d3d11_device_create_texture_internal (GstD3D11Device * device,
CreateTextureData * data)
{
GstD3D11DevicePrivate *priv = device->priv;
HRESULT hr;
hr = ID3D11Device_CreateTexture2D (priv->device, data->desc,
data->inital_data, &data->texture);
if (FAILED (hr)) {
GST_ERROR ("Failed to create staging texture (0x%x)", (guint) hr);
data->texture = NULL;
}
}
ID3D11Texture2D *
gst_d3d11_device_create_texture (GstD3D11Device * device,
const D3D11_TEXTURE2D_DESC * desc,
const D3D11_SUBRESOURCE_DATA * inital_data)
{
CreateTextureData data;
g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
g_return_val_if_fail (desc != NULL, NULL);
data.texture = NULL;
data.desc = desc;
data.inital_data = inital_data;
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_create_texture_internal, &data);
return data.texture;
}
static void
gst_d3d11_device_release_texture_internal (GstD3D11Device * device,
ID3D11Texture2D * texture)
{
ID3D11Texture2D_Release (texture);
}
void
gst_d3d11_device_release_texture (GstD3D11Device * device,
ID3D11Texture2D * texture)
{
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
g_return_if_fail (texture != NULL);
gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
gst_d3d11_device_release_texture_internal, texture);
}
/**
* gst_context_set_d3d11_device:
* @context: a #GstContext
* @device: (transfer none): resulting #GstD3D11Device
*
* Sets @device on @context
*/
void
gst_context_set_d3d11_device (GstContext * context, GstD3D11Device * device)
{
GstStructure *s;
const gchar *context_type;
g_return_if_fail (GST_IS_CONTEXT (context));
g_return_if_fail (GST_IS_D3D11_DEVICE (device));
context_type = gst_context_get_context_type (context);
if (g_strcmp0 (context_type, GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE) != 0)
return;
GST_CAT_LOG (GST_CAT_CONTEXT,
"setting GstD3DDevice(%" GST_PTR_FORMAT ") on context(%" GST_PTR_FORMAT
")", device, context);
s = gst_context_writable_structure (context);
gst_structure_set (s, "device", GST_TYPE_D3D11_DEVICE, device, NULL);
}
/**
* gst_context_get_d3d11_device:
* @context: a #GstContext
* @device: (out) (transfer full): resulting #GstD3D11Device
*
* Returns: Whether @device was in @context
*/
gboolean
gst_context_get_d3d11_device (GstContext * context, GstD3D11Device ** device)
{
const GstStructure *s;
const gchar *context_type;
gboolean ret;
g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (device != NULL, FALSE);
context_type = gst_context_get_context_type (context);
if (g_strcmp0 (context_type, GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE) != 0)
return FALSE;
s = gst_context_get_structure (context);
ret = gst_structure_get (s, "device", GST_TYPE_D3D11_DEVICE, device, NULL);
GST_CAT_LOG (GST_CAT_CONTEXT, "got GstD3DDevice(%p) from context(%p)",
*device, context);
return ret;
}