d3d12: Add H.264 decoder

Adding Direct3D12 h264 decoder

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4161>
This commit is contained in:
Seungha Yang 2023-09-10 23:34:26 +09:00
parent 2c058b3b99
commit 734dd50879
20 changed files with 5618 additions and 0 deletions

View file

@ -6,6 +6,7 @@ subprojects/gst-plugins-bad/gst-libs/gst/va
subprojects/gst-plugins-bad/gst-libs/gst/winrt
subprojects/gst-plugins-bad/sys/amfcodec
subprojects/gst-plugins-bad/sys/d3d11
subprojects/gst-plugins-bad/sys/d3d12
subprojects/gst-plugins-bad/sys/dwrite
subprojects/gst-plugins-bad/sys/mediafoundation
subprojects/gst-plugins-bad/sys/nvcodec

View file

@ -100,6 +100,7 @@ option('curl-ssh2', type : 'feature', value : 'auto', description : 'cURL networ
option('d3dvideosink', type : 'feature', value : 'auto', description : 'Direct3D video sink plugin')
option('d3d11', type : 'feature', value : 'auto', description : 'Direct3D11 plugin')
option('d3d11-wgc', type : 'feature', value : 'auto', description : 'Windows Graphics Capture API support in d3d11 plugin')
option('d3d12', type : 'feature', value : 'auto', description : 'Direct3D12 plugin')
option('dash', type : 'feature', value : 'auto', description : 'DASH demuxer plugin')
option('dc1394', type : 'feature', value : 'auto', description : 'libdc1394 IIDC camera source plugin')
option('decklink', type : 'feature', value : 'auto', description : 'DeckLink audio/video source/sink plugin')

View file

@ -0,0 +1,55 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#ifndef INITGUID
#include <initguid.h>
#endif
#include <d3d12.h>
#include <d3d12video.h>
#include <dxgi1_6.h>
G_BEGIN_DECLS
typedef struct _GstD3D12Device GstD3D12Device;
typedef struct _GstD3D12DeviceClass GstD3D12DeviceClass;
typedef struct _GstD3D12DevicePrivate GstD3D12DevicePrivate;
typedef struct _GstD3D12Fence GstD3D12Fence;
typedef struct _GstD3D12FencePrivate GstD3D12FencePrivate;
typedef struct _GstD3D12Memory GstD3D12Memory;
typedef struct _GstD3D12MemoryPrivate GstD3D12MemoryPrivate;
typedef struct _GstD3D12Allocator GstD3D12Allocator;
typedef struct _GstD3D12AllocatorClass GstD3D12AllocatorClass;
typedef struct _GstD3D12AllocatorPrivate GstD3D12AllocatorPrivate;
typedef struct _GstD3D12PoolAllocator GstD3D12PoolAllocator;
typedef struct _GstD3D12PoolAllocatorClass GstD3D12PoolAllocatorClass;
typedef struct _GstD3D12PoolAllocatorPrivate GstD3D12PoolAllocatorPrivate;
typedef struct _GstD3D12Format GstD3D12Format;
G_END_DECLS

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,167 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/codecs/gstcodecpicture.h>
#include <gst/dxva/gstdxva.h>
#include "gstd3d12_fwd.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D12_DECODER (gst_d3d12_decoder_get_type())
G_DECLARE_FINAL_TYPE (GstD3D12Decoder,
gst_d3d12_decoder, GST, D3D12_DECODER, GstObject);
typedef struct _GstD3D12DecoderClassData GstD3D12DecoderClassData;
struct GstD3D12DecoderSubClassData
{
GstDxvaCodec codec;
gint64 adapter_luid;
guint device_id;
guint vendor_id;
};
#define GST_D3D12_DECODER_DEFINE_TYPE(ModuleObjName,module_obj_name,MODULE,OBJ_NAME,ParentName) \
static GstElementClass *parent_class = NULL; \
typedef struct _##ModuleObjName { \
ParentName parent; \
GstD3D12Device *device; \
GstD3D12Decoder *decoder; \
} ModuleObjName;\
typedef struct _##ModuleObjName##Class { \
ParentName##Class parent_class; \
GstD3D12DecoderSubClassData class_data; \
} ModuleObjName##Class; \
static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return (ModuleObjName *) (ptr); \
} \
static inline ModuleObjName##Class * MODULE##_##OBJ_NAME##_GET_CLASS (gpointer ptr) { \
return G_TYPE_INSTANCE_GET_CLASS ((ptr),G_TYPE_FROM_INSTANCE(ptr),ModuleObjName##Class); \
} \
static void module_obj_name##_get_property (GObject * object, \
guint prop_id, GValue * value, GParamSpec * pspec); \
static void module_obj_name##_set_context (GstElement * element, \
GstContext * context); \
static gboolean module_obj_name##_open (GstVideoDecoder * decoder); \
static gboolean module_obj_name##_close (GstVideoDecoder * decoder); \
static gboolean module_obj_name##_negotiate (GstVideoDecoder * decoder); \
static gboolean module_obj_name##_decide_allocation (GstVideoDecoder * decoder, \
GstQuery * query); \
static gboolean module_obj_name##_sink_query (GstVideoDecoder * decoder, \
GstQuery * query); \
static gboolean module_obj_name##_src_query (GstVideoDecoder * decoder, \
GstQuery * query); \
static GstFlowReturn module_obj_name##_configure (ParentName * decoder, \
GstVideoCodecState * input_state, const GstVideoInfo * info, \
gint crop_x, gint crop_y, \
gint coded_width, gint coded_height, gint max_dpb_size); \
static GstFlowReturn module_obj_name##_new_picture (ParentName * decoder, \
GstCodecPicture * picture); \
static guint8 module_obj_name##_get_picture_id (ParentName * decoder, \
GstCodecPicture * picture); \
static GstFlowReturn module_obj_name##_start_picture (ParentName * decoder, \
GstCodecPicture * picture, guint8 * picture_id); \
static GstFlowReturn module_obj_name##_end_picture (ParentName * decoder, \
GstCodecPicture * picture, GPtrArray * ref_pics, \
const GstDxvaDecodingArgs * args); \
static GstFlowReturn module_obj_name##_output_picture (ParentName * decoder, \
GstVideoCodecFrame * frame, GstCodecPicture * picture, \
GstVideoBufferFlags buffer_flags, \
gint display_width, gint display_height);
#define GST_D3D12_DECODER_DEFINE_TYPE_FULL(ModuleObjName,module_obj_name,MODULE,OBJ_NAME,ParentName) \
GST_D3D12_DECODER_DEFINE_TYPE(ModuleObjName,module_obj_name,MODULE,OBJ_NAME,ParentName); \
static GstFlowReturn module_obj_name##_duplicate_picture (ParentName * decoder, \
GstCodecPicture * src, GstCodecPicture * dst);
GstD3D12Decoder * gst_d3d12_decoder_new (GstD3D12Device * device,
GstDxvaCodec codec);
GstFlowReturn gst_d3d12_decoder_configure (GstD3D12Decoder * decoder,
GstVideoCodecState * input_state,
const GstVideoInfo * info,
gint crop_x,
gint crop_y,
gint coded_width,
gint coded_height,
guint dpb_size);
GstFlowReturn gst_d3d12_decoder_new_picture (GstD3D12Decoder * decoder,
GstVideoDecoder * videodec,
GstCodecPicture * picture);
GstFlowReturn gst_d3d12_decoder_duplicate_picture (GstD3D12Decoder * decoder,
GstCodecPicture * src,
GstCodecPicture * dst);
guint8 gst_d3d12_decoder_get_picture_id (GstD3D12Decoder * decoder,
GstCodecPicture * picture);
GstFlowReturn gst_d3d12_decoder_start_picture (GstD3D12Decoder * decoder,
GstCodecPicture * picture,
guint8 * picture_id);
GstFlowReturn gst_d3d12_decoder_end_picture (GstD3D12Decoder * decoder,
GstCodecPicture * picture,
GPtrArray * ref_pics,
const GstDxvaDecodingArgs * args);
GstFlowReturn gst_d3d12_decoder_output_picture (GstD3D12Decoder * decoder,
GstVideoDecoder * videodec,
GstVideoCodecFrame * frame,
GstCodecPicture * picture,
GstVideoBufferFlags buffer_flags,
gint display_width,
gint display_height);
gboolean gst_d3d12_decoder_negotiate (GstD3D12Decoder * decoder,
GstVideoDecoder * videodec);
gboolean gst_d3d12_decoder_decide_allocation (GstD3D12Decoder * decoder,
GstVideoDecoder * videodec,
GstQuery * query);
/* Utils for element registration */
GstD3D12DecoderClassData * gst_d3d12_decoder_check_feature_support (GstD3D12Device * device,
ID3D12VideoDevice * video_device,
GstDxvaCodec codec);
void gst_d3d12_decoder_class_data_fill_subclass_data (GstD3D12DecoderClassData * data,
GstD3D12DecoderSubClassData * subclass_data);
void gst_d3d12_decoder_proxy_class_init (GstElementClass * klass,
GstD3D12DecoderClassData * data,
const gchar * author);
void gst_d3d12_decoder_proxy_get_property (GObject * object,
guint prop_id,
GValue * value,
GParamSpec * pspec,
GstD3D12DecoderSubClassData * subclass_data);
gboolean gst_d3d12_decoder_proxy_open (GstVideoDecoder * videodec,
GstD3D12DecoderSubClassData * subclass_data,
GstD3D12Device ** device,
GstD3D12Decoder ** decoder);
G_END_DECLS

View file

@ -0,0 +1,802 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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 "gstd3d12device.h"
#include "gstd3d12utils.h"
#include "gstd3d12format.h"
#include <wrl.h>
#include <vector>
#include <string.h>
#include <mutex>
#include <atomic>
#include <string>
#include <locale>
#include <codecvt>
#include <algorithm>
#ifdef HAVE_D3D12_SDKLAYERS_H
#include <d3d12sdklayers.h>
#endif
GST_DEBUG_CATEGORY_STATIC (gst_d3d12_device_debug);
GST_DEBUG_CATEGORY_STATIC (gst_d3d12_sdk_debug);
#define GST_CAT_DEFAULT gst_d3d12_device_debug
#define MAKE_FORMAT_MAP_YUV(g,d,r0,r1,r2,r3) \
{ GST_VIDEO_FORMAT_ ##g, DXGI_FORMAT_ ##d, \
{ DXGI_FORMAT_ ##r0, DXGI_FORMAT_ ##r1, DXGI_FORMAT_ ##r2, DXGI_FORMAT_ ##r3 }, \
{ DXGI_FORMAT_ ##r0, DXGI_FORMAT_ ##r1, DXGI_FORMAT_ ##r2, DXGI_FORMAT_ ##r3 }, \
(D3D12_FORMAT_SUPPORT1) (D3D12_FORMAT_SUPPORT1_TEXTURE2D | \
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE | D3D12_FORMAT_SUPPORT1_RENDER_TARGET) }
#define MAKE_FORMAT_MAP_YUV_FULL(g,d,r0,r1,r2,r3,f) \
{ GST_VIDEO_FORMAT_ ##g, DXGI_FORMAT_ ##d, \
{ DXGI_FORMAT_ ##r0, DXGI_FORMAT_ ##r1, DXGI_FORMAT_ ##r2, DXGI_FORMAT_ ##r3 }, \
{ DXGI_FORMAT_ ##r0, DXGI_FORMAT_ ##r1, DXGI_FORMAT_ ##r2, DXGI_FORMAT_ ##r3 }, \
(D3D12_FORMAT_SUPPORT1) (f) }
#define MAKE_FORMAT_MAP_RGB(g,d) \
{ GST_VIDEO_FORMAT_ ##g, DXGI_FORMAT_ ##d, \
{ DXGI_FORMAT_ ##d, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, \
{ DXGI_FORMAT_ ##d, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN }, \
(D3D12_FORMAT_SUPPORT1) (D3D12_FORMAT_SUPPORT1_TEXTURE2D | \
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE | D3D12_FORMAT_SUPPORT1_RENDER_TARGET) }
#define MAKE_FORMAT_MAP_RGBP(g,d,a) \
{ GST_VIDEO_FORMAT_ ##g, DXGI_FORMAT_UNKNOWN, \
{ DXGI_FORMAT_ ##d, DXGI_FORMAT_ ##d, DXGI_FORMAT_ ##d, DXGI_FORMAT_ ##a }, \
{ DXGI_FORMAT_ ##d, DXGI_FORMAT_ ##d, DXGI_FORMAT_ ##d, DXGI_FORMAT_ ##a }, \
(D3D12_FORMAT_SUPPORT1) (D3D12_FORMAT_SUPPORT1_TEXTURE2D | \
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE | D3D12_FORMAT_SUPPORT1_RENDER_TARGET) }
static const GstD3D12Format _gst_d3d12_default_format_map[] = {
MAKE_FORMAT_MAP_RGB (BGRA, B8G8R8A8_UNORM),
MAKE_FORMAT_MAP_RGB (RGBA, R8G8B8A8_UNORM),
MAKE_FORMAT_MAP_RGB (BGRx, B8G8R8A8_UNORM),
MAKE_FORMAT_MAP_RGB (RGBx, R8G8B8A8_UNORM),
MAKE_FORMAT_MAP_RGB (RGB10A2_LE, R10G10B10A2_UNORM),
MAKE_FORMAT_MAP_RGB (RGBA64_LE, R16G16B16A16_UNORM),
MAKE_FORMAT_MAP_YUV (AYUV, UNKNOWN, R8G8B8A8_UNORM, UNKNOWN, UNKNOWN,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (AYUV64, UNKNOWN, R16G16B16A16_UNORM, UNKNOWN, UNKNOWN,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (VUYA, AYUV, R8G8B8A8_UNORM, UNKNOWN, UNKNOWN, UNKNOWN),
MAKE_FORMAT_MAP_YUV (NV12, NV12, R8_UNORM, R8G8_UNORM, UNKNOWN, UNKNOWN),
MAKE_FORMAT_MAP_YUV (NV21, UNKNOWN, R8_UNORM, R8G8_UNORM, UNKNOWN, UNKNOWN),
MAKE_FORMAT_MAP_YUV (P010_10LE, P010, R16_UNORM, R16G16_UNORM, UNKNOWN,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (P012_LE, P016, R16_UNORM, R16G16_UNORM, UNKNOWN,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (P016_LE, P016, R16_UNORM, R16G16_UNORM, UNKNOWN,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (I420, UNKNOWN, R8_UNORM, R8_UNORM, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_YUV (YV12, UNKNOWN, R8_UNORM, R8_UNORM, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_YUV (I420_10LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (I420_12LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (Y42B, UNKNOWN, R8_UNORM, R8_UNORM, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_YUV (I422_10LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (I422_12LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (Y444, UNKNOWN, R8_UNORM, R8_UNORM, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_YUV (Y444_10LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (Y444_12LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
MAKE_FORMAT_MAP_YUV (Y444_16LE, UNKNOWN, R16_UNORM, R16_UNORM, R16_UNORM,
UNKNOWN),
/* GRAY */
/* NOTE: To support conversion by using video processor,
* mark DXGI_FORMAT_{R8,R16}_UNORM formats as known dxgi_format.
* Otherwise, d3d12 elements will not try to use video processor for
* those formats */
MAKE_FORMAT_MAP_RGB (GRAY8, R8_UNORM),
MAKE_FORMAT_MAP_RGB (GRAY16_LE, R16_UNORM),
MAKE_FORMAT_MAP_YUV_FULL (Y410, Y410, R10G10B10A2_UNORM, UNKNOWN, UNKNOWN,
UNKNOWN,
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE),
MAKE_FORMAT_MAP_YUV_FULL (YUY2, YUY2, R8G8B8A8_UNORM, UNKNOWN, UNKNOWN,
UNKNOWN,
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE),
MAKE_FORMAT_MAP_RGBP (RGBP, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_RGBP (BGRP, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_RGBP (GBR, R8_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_RGBP (GBR_10LE, R16_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_RGBP (GBR_12LE, R16_UNORM, UNKNOWN),
MAKE_FORMAT_MAP_RGBP (GBRA, R8_UNORM, R8_UNORM),
MAKE_FORMAT_MAP_RGBP (GBRA_10LE, R16_UNORM, R16_UNORM),
MAKE_FORMAT_MAP_RGBP (GBRA_12LE, R16_UNORM, R16_UNORM),
};
#undef MAKE_FORMAT_MAP_YUV
#undef MAKE_FORMAT_MAP_YUV_FULL
#undef MAKE_FORMAT_MAP_RGB
#define GST_D3D12_N_FORMATS G_N_ELEMENTS(_gst_d3d12_default_format_map)
enum
{
PROP_0,
PROP_ADAPTER_INDEX,
PROP_ADAPTER_LUID,
PROP_DEVICE_ID,
PROP_VENDOR_ID,
PROP_HARDWARE,
PROP_DESCRIPTION,
};
/* d3d12 devices are singtones per adapter. Keep track of live objects and
* reuse already created object if possible */
/* *INDENT-OFF* */
std::mutex device_list_lock_;
std::vector<GstD3D12Device*> live_devices_;
using namespace Microsoft::WRL;
struct _GstD3D12DevicePrivate
{
ComPtr<ID3D12Device> device;
ComPtr<IDXGIAdapter1> adapter;
ComPtr<IDXGIFactory2> factory;
std::vector < GstD3D12Format> formats;
std::mutex lock;
std::recursive_mutex extern_lock;
std::atomic<guint64> fence_value;
#ifdef HAVE_D3D12_SDKLAYERS_H
ComPtr<ID3D12InfoQueue> info_queue;
#endif
guint adapter_index = 0;
guint device_id = 0;
guint vendor_id = 0;
std::string description;
gint64 adapter_luid = 0;
};
/* *INDENT-ON* */
#ifdef HAVE_D3D12_SDKLAYERS_H
static gboolean
gst_d3d12_device_enable_debug (void)
{
static gboolean enabled = FALSE;
GST_D3D12_CALL_ONCE_BEGIN {
GST_DEBUG_CATEGORY_INIT (gst_d3d12_device_debug,
"d3d12device", 0, "d3d12 device object");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_sdk_debug,
"d3d12debuglayer", 0, "d3d12 SDK layer debug");
/* Enables debug layer only if it's requested, otherwise
* already configured d3d12 devices (e.g., owned by application)
* will be invalidated by ID3D12Debug::EnableDebugLayer() */
if (!g_getenv ("GST_ENABLE_D3D12_DEBUG"))
return;
HRESULT hr;
ComPtr < ID3D12Debug > d3d12_debug;
hr = D3D12GetDebugInterface (IID_PPV_ARGS (&d3d12_debug));
if (FAILED (hr))
return;
d3d12_debug->EnableDebugLayer ();
enabled = TRUE;
GST_INFO ("D3D12 debug layer is enabled");
ComPtr < ID3D12Debug5 > d3d12_debug5;
hr = d3d12_debug.As (&d3d12_debug5);
if (SUCCEEDED (hr))
d3d12_debug5->SetEnableAutoName (TRUE);
ComPtr < ID3D12Debug1 > d3d12_debug1;
hr = d3d12_debug.As (&d3d12_debug1);
if (FAILED (hr))
return;
d3d12_debug1->SetEnableSynchronizedCommandQueueValidation (TRUE);
GST_INFO ("Enabled synchronized command queue validation");
if (!g_getenv ("GST_ENABLE_D3D12_DEBUG_GPU_VALIDATION"))
return;
d3d12_debug1->SetEnableGPUBasedValidation (TRUE);
GST_INFO ("Enabled GPU based validation");
}
GST_D3D12_CALL_ONCE_END;
return enabled;
}
#endif
#define gst_d3d12_device_parent_class parent_class
G_DEFINE_TYPE (GstD3D12Device, gst_d3d12_device, GST_TYPE_OBJECT);
static void gst_d3d12_device_finalize (GObject * object);
static void gst_d3d12_device_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_d3d12_device_setup_format_table (GstD3D12Device * self);
static void
gst_d3d12_device_class_init (GstD3D12DeviceClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GParamFlags readable_flags =
(GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
gobject_class->finalize = gst_d3d12_device_finalize;
gobject_class->get_property = gst_d3d12_device_get_property;
g_object_class_install_property (gobject_class, PROP_ADAPTER_INDEX,
g_param_spec_uint ("adapter-index", "Adapter Index",
"DXGI Adapter index for creating device",
0, G_MAXUINT32, 0, readable_flags));
g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
g_param_spec_int64 ("adapter-luid", "Adapter LUID",
"DXGI Adapter LUID (Locally Unique Identifier) of created device",
0, G_MAXINT64, 0, readable_flags));
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, readable_flags));
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, readable_flags));
g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
g_param_spec_string ("description", "Description",
"Human readable device description", nullptr, readable_flags));
}
static void
gst_d3d12_device_init (GstD3D12Device * self)
{
self->priv = new GstD3D12DevicePrivate ();
}
static void
gst_d3d12_device_finalize (GObject * object)
{
GstD3D12Device *self = GST_D3D12_DEVICE (object);
GST_DEBUG_OBJECT (self, "Finalize");
delete self->priv;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gst_d3d12_device_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D12Device *self = GST_D3D12_DEVICE (object);
GstD3D12DevicePrivate *priv = self->priv;
switch (prop_id) {
case PROP_ADAPTER_INDEX:
g_value_set_uint (value, priv->adapter_index);
break;
case PROP_ADAPTER_LUID:
g_value_set_int64 (value, priv->adapter_luid);
break;
case PROP_DEVICE_ID:
g_value_set_uint (value, priv->device_id);
break;
case PROP_VENDOR_ID:
g_value_set_uint (value, priv->vendor_id);
break;
case PROP_DESCRIPTION:
g_value_set_string (value, priv->description.c_str ());
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
check_format_support (GstD3D12Device * self, DXGI_FORMAT format,
guint flags, D3D12_FEATURE_DATA_FORMAT_SUPPORT * support)
{
ID3D12Device *device = self->priv->device.Get ();
HRESULT hr;
support->Format = format;
hr = device->CheckFeatureSupport (D3D12_FEATURE_FORMAT_SUPPORT, support,
sizeof (D3D12_FEATURE_DATA_FORMAT_SUPPORT));
if (FAILED (hr)) {
GST_INFO_OBJECT (self,
"Failed to check feature support for DXGI format %d", format);
return FALSE;
}
if (((guint) support->Support1 & flags) != flags) {
GST_INFO_OBJECT (self,
"DXGI format %d supports1 flag 0x%x, required 0x%x", format,
support->Support1, flags);
return FALSE;
}
return TRUE;
}
static void
gst_d3d12_device_setup_format_table (GstD3D12Device * self)
{
GstD3D12DevicePrivate *priv = self->priv;
for (guint i = 0; i < G_N_ELEMENTS (_gst_d3d12_default_format_map); i++) {
const GstD3D12Format *iter = &_gst_d3d12_default_format_map[i];
GstD3D12Format format;
D3D12_FEATURE_DATA_FORMAT_SUPPORT support[GST_VIDEO_MAX_PLANES];
memset (support, 0, sizeof (support));
switch (iter->format) {
/* RGB/GRAY */
case GST_VIDEO_FORMAT_BGRA:
case GST_VIDEO_FORMAT_BGRx:
case GST_VIDEO_FORMAT_RGBA:
case GST_VIDEO_FORMAT_RGBx:
case GST_VIDEO_FORMAT_RGB10A2_LE:
case GST_VIDEO_FORMAT_RGBA64_LE:
case GST_VIDEO_FORMAT_GRAY8:
case GST_VIDEO_FORMAT_GRAY16_LE:
if (!check_format_support (self, iter->dxgi_format,
iter->format_support1[0], &support[0])) {
continue;
}
break;
/* YUV DXGI native formats */
case GST_VIDEO_FORMAT_VUYA:
case GST_VIDEO_FORMAT_Y410:
case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_P010_10LE:
case GST_VIDEO_FORMAT_P012_LE:
case GST_VIDEO_FORMAT_P016_LE:
case GST_VIDEO_FORMAT_YUY2:
if (!check_format_support (self, iter->dxgi_format,
iter->format_support1[0], &support[0])) {
continue;
}
break;
/* non-DXGI native formats */
case GST_VIDEO_FORMAT_NV21:
case GST_VIDEO_FORMAT_I420:
case GST_VIDEO_FORMAT_YV12:
case GST_VIDEO_FORMAT_I420_10LE:
case GST_VIDEO_FORMAT_I420_12LE:
case GST_VIDEO_FORMAT_Y42B:
case GST_VIDEO_FORMAT_I422_10LE:
case GST_VIDEO_FORMAT_I422_12LE:
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y444_10LE:
case GST_VIDEO_FORMAT_Y444_12LE:
case GST_VIDEO_FORMAT_Y444_16LE:
case GST_VIDEO_FORMAT_AYUV:
case GST_VIDEO_FORMAT_AYUV64:
/* RGB planar formats */
case GST_VIDEO_FORMAT_RGBP:
case GST_VIDEO_FORMAT_BGRP:
case GST_VIDEO_FORMAT_GBR:
case GST_VIDEO_FORMAT_GBR_10LE:
case GST_VIDEO_FORMAT_GBR_12LE:
case GST_VIDEO_FORMAT_GBRA:
case GST_VIDEO_FORMAT_GBRA_10LE:
case GST_VIDEO_FORMAT_GBRA_12LE:
{
bool supported = true;
for (guint j = 0; j < GST_VIDEO_MAX_PLANES; j++) {
if (iter->resource_format[j] == DXGI_FORMAT_UNKNOWN)
break;
if (!check_format_support (self, iter->resource_format[j],
iter->format_support1[0], &support[j])) {
supported = false;
break;
}
}
if (!supported) {
GST_INFO_OBJECT (self, "%s is not supported",
gst_video_format_to_string (iter->format));
continue;
}
break;
}
default:
g_assert_not_reached ();
return;
}
format = *iter;
for (guint j = 0; j < GST_VIDEO_MAX_PLANES; j++) {
format.format_support1[j] = support[j].Support1;
format.format_support2[j] = support[j].Support2;
}
priv->formats.push_back (format);
}
}
static void
gst_d3d12_device_weak_ref_notify (gpointer data, GstD3D12Device * device)
{
std::lock_guard < std::mutex > lk (device_list_lock_);
auto it = std::find (live_devices_.begin (), live_devices_.end (), device);
if (it != live_devices_.end ())
live_devices_.erase (it);
else
GST_WARNING ("Could not find %p from list", device);
}
typedef enum
{
GST_D3D12_DEVICE_CONSTRUCT_FOR_INDEX,
GST_D3D12_DEVICE_CONSTRUCT_FOR_LUID,
} GstD3D12DeviceConstructType;
typedef struct
{
union
{
guint index;
gint64 luid;
} data;
GstD3D12DeviceConstructType type;
} GstD3D12DeviceConstructData;
static HRESULT
gst_d3d12_device_find_adapter (const GstD3D12DeviceConstructData * data,
IDXGIFactory2 * factory, guint * index, IDXGIAdapter1 ** rst)
{
HRESULT hr;
UINT factory_flags = 0;
#ifdef HAVE_D3D12_SDKLAYERS_H
if (gst_d3d12_device_enable_debug ())
factory_flags |= DXGI_CREATE_FACTORY_DEBUG;
#endif
hr = CreateDXGIFactory2 (factory_flags, IID_PPV_ARGS (&factory));
if (FAILED (hr)) {
GST_WARNING ("cannot create dxgi factory, hr: 0x%x", (guint) hr);
return hr;
}
switch (data->type) {
case GST_D3D12_DEVICE_CONSTRUCT_FOR_INDEX:{
ComPtr < IDXGIAdapter1 > adapter;
hr = factory->EnumAdapters1 (data->data.index, &adapter);
if (FAILED (hr))
return hr;
*index = data->data.index;
*rst = adapter.Detach ();
return S_OK;
}
case GST_D3D12_DEVICE_CONSTRUCT_FOR_LUID:
for (UINT i = 0;; i++) {
ComPtr < IDXGIAdapter1 > adapter;
DXGI_ADAPTER_DESC1 desc;
hr = factory->EnumAdapters1 (i, &adapter);
if (FAILED (hr))
return hr;
hr = adapter->GetDesc1 (&desc);
if (FAILED (hr))
return hr;
if (gst_d3d12_luid_to_int64 (&desc.AdapterLuid) != data->data.luid) {
continue;
}
*index = i;
*rst = adapter.Detach ();
return S_OK;
}
default:
g_assert_not_reached ();
break;
}
return E_FAIL;
}
static GstD3D12Device *
gst_d3d12_device_new_internal (const GstD3D12DeviceConstructData * data)
{
ComPtr < IDXGIFactory2 > factory;
ComPtr < IDXGIAdapter1 > adapter;
ComPtr < ID3D12Device > device;
HRESULT hr;
UINT factory_flags = 0;
guint index = 0;
#ifdef HAVE_D3D12_SDKLAYERS_H
if (gst_d3d12_device_enable_debug ())
factory_flags |= DXGI_CREATE_FACTORY_DEBUG;
#endif
hr = CreateDXGIFactory2 (factory_flags, IID_PPV_ARGS (&factory));
if (FAILED (hr)) {
GST_WARNING ("Could create dxgi factory, hr: 0x%x", (guint) hr);
return nullptr;
}
hr = gst_d3d12_device_find_adapter (data, factory.Get (), &index, &adapter);
if (FAILED (hr)) {
GST_WARNING ("Could not find adapter, hr: 0x%x", (guint) hr);
return nullptr;
}
DXGI_ADAPTER_DESC1 desc;
hr = adapter->GetDesc1 (&desc);
if (FAILED (hr)) {
GST_WARNING ("Could not get adapter desc, hr: 0x%x", (guint) hr);
return nullptr;
}
hr = D3D12CreateDevice (adapter.Get (), D3D_FEATURE_LEVEL_12_0,
IID_PPV_ARGS (&device));
if (FAILED (hr)) {
GST_WARNING ("Could not create device, hr: 0x%x", (guint) hr);
return nullptr;
}
GstD3D12Device *self = (GstD3D12Device *)
g_object_new (GST_TYPE_D3D12_DEVICE, nullptr);
GstD3D12DevicePrivate *priv = self->priv;
priv->factory = factory;
priv->adapter = adapter;
priv->device = device;
priv->adapter_luid = gst_d3d12_luid_to_int64 (&desc.AdapterLuid);
priv->vendor_id = desc.VendorId;
priv->device_id = desc.DeviceId;
std::wstring_convert < std::codecvt_utf8 < wchar_t >, wchar_t >converter;
priv->description = converter.to_bytes (desc.Description);
GST_INFO_OBJECT (self,
"adapter index %d: D3D12 device vendor-id: 0x%04x, device-id: 0x%04x, "
"Flags: 0x%x, adapter-luid: %" G_GINT64_FORMAT ", %s",
priv->adapter_index, desc.VendorId, desc.DeviceId, desc.Flags,
priv->adapter_luid, priv->description.c_str ());
gst_d3d12_device_setup_format_table (self);
#ifdef HAVE_D3D12_SDKLAYERS_H
if (gst_d3d12_device_enable_debug ()) {
ComPtr < ID3D12InfoQueue > info_queue;
device.As (&info_queue);
priv->info_queue = info_queue;
}
#endif
return self;
}
GstD3D12Device *
gst_d3d12_device_new (guint adapter_index)
{
GstD3D12Device *self = nullptr;
std::lock_guard < std::mutex > lk (device_list_lock_);
/* *INDENT-OFF* */
for (auto iter: live_devices_) {
if (iter->priv->adapter_index == adapter_index) {
self = (GstD3D12Device *) gst_object_ref (iter);
break;
}
}
/* *INDENT-ON* */
if (!self) {
GstD3D12DeviceConstructData data;
data.data.index = adapter_index;
data.type = GST_D3D12_DEVICE_CONSTRUCT_FOR_INDEX;
self = gst_d3d12_device_new_internal (&data);
if (!self) {
GST_INFO ("Could not create device for index %d", adapter_index);
return nullptr;
}
gst_object_ref_sink (self);
g_object_weak_ref (G_OBJECT (self),
(GWeakNotify) gst_d3d12_device_weak_ref_notify, nullptr);
live_devices_.push_back (self);
}
return self;
}
GstD3D12Device *
gst_d3d12_device_new_for_adapter_luid (gint64 adapter_luid)
{
GstD3D12Device *self = nullptr;
std::lock_guard < std::mutex > lk (device_list_lock_);
/* *INDENT-OFF* */
for (auto iter: live_devices_) {
if (iter->priv->adapter_luid == adapter_luid) {
self = (GstD3D12Device *) gst_object_ref (iter);
break;
}
}
/* *INDENT-ON* */
if (!self) {
GstD3D12DeviceConstructData data;
data.data.luid = adapter_luid;
data.type = GST_D3D12_DEVICE_CONSTRUCT_FOR_LUID;
self = gst_d3d12_device_new_internal (&data);
if (!self) {
GST_INFO ("Could not create device for LUID %" G_GINT64_FORMAT,
adapter_luid);
return nullptr;
}
gst_object_ref_sink (self);
g_object_weak_ref (G_OBJECT (self),
(GWeakNotify) gst_d3d12_device_weak_ref_notify, nullptr);
live_devices_.push_back (self);
}
return self;
}
ID3D12Device *
gst_d3d12_device_get_device_handle (GstD3D12Device * device)
{
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
return device->priv->device.Get ();
}
IDXGIAdapter1 *
gst_d3d12_device_get_adapter_handle (GstD3D12Device * device)
{
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
return device->priv->adapter.Get ();
}
IDXGIFactory2 *
gst_d3d12_device_get_factory_handle (GstD3D12Device * device)
{
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
return device->priv->factory.Get ();
}
gboolean
gst_d3d12_device_get_device_format (GstD3D12Device * device,
GstVideoFormat format, GstD3D12Format * device_format)
{
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), FALSE);
g_return_val_if_fail (device_format != nullptr, FALSE);
/* *INDENT-OFF* */
for (const auto &iter : device->priv->formats) {
if (iter.format == format) {
*device_format = iter;
return TRUE;
}
}
/* *INDENT-ON* */
return FALSE;
}
static inline GstDebugLevel
d3d12_message_severity_to_gst (D3D12_MESSAGE_SEVERITY level)
{
switch (level) {
case D3D12_MESSAGE_SEVERITY_CORRUPTION:
case D3D12_MESSAGE_SEVERITY_ERROR:
return GST_LEVEL_ERROR;
case D3D12_MESSAGE_SEVERITY_WARNING:
return GST_LEVEL_WARNING;
case D3D12_MESSAGE_SEVERITY_INFO:
return GST_LEVEL_INFO;
case D3D12_MESSAGE_SEVERITY_MESSAGE:
return GST_LEVEL_DEBUG;
default:
break;
}
return GST_LEVEL_LOG;
}
#ifdef HAVE_D3D12_SDKLAYERS_H
void
gst_d3d12_device_d3d12_debug (GstD3D12Device * device, const gchar * file,
const gchar * function, gint line)
{
g_return_if_fail (GST_IS_D3D12_DEVICE (device));
if (!device->priv->info_queue)
return;
GstD3D12DevicePrivate *priv = device->priv;
std::lock_guard < std::recursive_mutex > lk (priv->extern_lock);
ID3D12InfoQueue *info_queue = priv->info_queue.Get ();
UINT64 num_msg = info_queue->GetNumStoredMessages ();
for (guint64 i = 0; i < num_msg; i++) {
HRESULT hr;
SIZE_T msg_len;
D3D12_MESSAGE *msg;
GstDebugLevel msg_level;
GstDebugLevel selected_level;
hr = info_queue->GetMessage (i, nullptr, &msg_len);
if (FAILED (hr) || msg_len == 0)
continue;
msg = (D3D12_MESSAGE *) g_malloc0 (msg_len);
hr = info_queue->GetMessage (i, msg, &msg_len);
if (FAILED (hr) || msg_len == 0) {
g_free (msg);
continue;
}
msg_level = d3d12_message_severity_to_gst (msg->Severity);
if (msg->Category == D3D12_MESSAGE_CATEGORY_STATE_CREATION &&
msg_level > GST_LEVEL_ERROR) {
/* Do not warn for live object, since there would be live object
* when ReportLiveDeviceObjects was called */
selected_level = GST_LEVEL_INFO;
} else {
selected_level = msg_level;
}
gst_debug_log (gst_d3d12_sdk_debug, selected_level, file, function, line,
G_OBJECT (device), "D3D12InfoQueue: %s", msg->pDescription);
g_free (msg);
}
info_queue->ClearStoredMessages ();
}
#else
void
gst_d3d12_device_d3d12_debug (GstD3D12Device * device, const gchar * file,
const gchar * function, gint line)
{
}
#endif

View file

@ -0,0 +1,77 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstd3d12_fwd.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D12_DEVICE (gst_d3d12_device_get_type())
#define GST_D3D12_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_D3D12_DEVICE,GstD3D12Device))
#define GST_D3D12_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_D3D12_DEVICE,GstD3D12DeviceClass))
#define GST_D3D12_DEVICE_GET_CLASS(obj) (GST_D3D12_DEVICE_CLASS(G_OBJECT_GET_CLASS(obj)))
#define GST_IS_D3D12_DEVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_D3D12_DEVICE))
#define GST_IS_D3D12_DEVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_D3D12_DEVICE))
#define GST_D3D12_DEVICE_CAST(obj) ((GstD3D12Device*)(obj))
#define GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE "gst.d3d12.device.handle"
struct _GstD3D12Device
{
GstObject parent;
/*< private >*/
GstD3D12DevicePrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstD3D12DeviceClass
{
GstObjectClass parent_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType gst_d3d12_device_get_type (void);
GstD3D12Device * gst_d3d12_device_new (guint adapter_index);
GstD3D12Device * gst_d3d12_device_new_for_adapter_luid (gint64 adapter_luid);
ID3D12Device * gst_d3d12_device_get_device_handle (GstD3D12Device * device);
IDXGIAdapter1 * gst_d3d12_device_get_adapter_handle (GstD3D12Device * device);
IDXGIFactory2 * gst_d3d12_device_get_factory_handle (GstD3D12Device * device);
gboolean gst_d3d12_device_get_device_format (GstD3D12Device * device,
GstVideoFormat format,
GstD3D12Format * device_format);
void gst_d3d12_device_d3d12_debug (GstD3D12Device * device,
const gchar * file,
const gchar * function,
gint line);
G_END_DECLS

View file

@ -0,0 +1,173 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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 "gstd3d12fence.h"
#include "gstd3d12device.h"
#include "gstd3d12utils.h"
#include <wrl.h>
#include <mutex>
GST_DEBUG_CATEGORY_EXTERN (gst_d3d12_fence_debug);
#define GST_CAT_DEFAULT gst_d3d12_fence_debug
GST_DEFINE_MINI_OBJECT_TYPE (GstD3D12Fence, gst_d3d12_fence);
/* *INDENT-OFF* */
using namespace Microsoft::WRL;
struct _GstD3D12FencePrivate
{
_GstD3D12FencePrivate()
{
event_handle = CreateEventEx (nullptr, nullptr, 0, EVENT_ALL_ACCESS);
}
~_GstD3D12FencePrivate()
{
CloseHandle (event_handle);
}
ComPtr<ID3D12Fence> fence;
HANDLE event_handle;
std::mutex lock;
guint64 value = 0;
gboolean can_wait = FALSE;
};
/* *INDENT-ON* */
static void
gst_d3d12_fence_free (GstD3D12Fence * self)
{
if (!self)
return;
GST_TRACE ("Freeing fence %p", self);
gst_clear_object (&self->device);
delete self->priv;
g_free (self);
}
GstD3D12Fence *
gst_d3d12_fence_new (GstD3D12Device * device)
{
GstD3D12Fence *self;
GstD3D12FencePrivate *priv;
ID3D12Device *device_handle;
HRESULT hr;
ComPtr < ID3D12Fence > fence;
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
device_handle = gst_d3d12_device_get_device_handle (device);
hr = device_handle->CreateFence (0,
D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS (&fence));
if (!gst_d3d12_result (hr, device)) {
GST_ERROR_OBJECT (device, "Failed to create fence, hr: 0x%x", hr);
return nullptr;
}
priv = new GstD3D12FencePrivate ();
priv->fence = fence;
self = g_new0 (GstD3D12Fence, 1);
GST_TRACE_OBJECT (device, "Creating fence %p", self);
self->device = (GstD3D12Device *) gst_object_ref (device);
self->priv = priv;
gst_mini_object_init (GST_MINI_OBJECT_CAST (self), 0, GST_TYPE_D3D12_FENCE,
nullptr, nullptr, (GstMiniObjectFreeFunction) gst_d3d12_fence_free);
return self;
}
gboolean
gst_d3d12_fence_set_event_on_completion_value (GstD3D12Fence * fence,
guint64 value)
{
GstD3D12FencePrivate *priv;
HRESULT hr;
g_return_val_if_fail (fence != nullptr, FALSE);
priv = fence->priv;
std::lock_guard < std::mutex > lk (priv->lock);
hr = priv->fence->SetEventOnCompletion (value, priv->event_handle);
if (!gst_d3d12_result (hr, fence->device)) {
GST_ERROR_OBJECT (fence->device, "Failed to set completion event");
return FALSE;
}
priv->value = value;
priv->can_wait = TRUE;
return TRUE;
}
ID3D12Fence *
gst_d3d12_fence_get_handle (GstD3D12Fence * fence)
{
g_return_val_if_fail (fence != nullptr, nullptr);
return fence->priv->fence.Get ();
}
void
gst_d3d12_fence_wait_for (GstD3D12Fence * fence, guint timeout_ms)
{
g_return_if_fail (fence != nullptr);
GstD3D12FencePrivate *priv = fence->priv;
std::lock_guard < std::mutex > lk (priv->lock);
if (!priv->can_wait)
return;
GST_TRACE ("Waiting for fence to be signalled with value %" G_GUINT64_FORMAT,
priv->value);
WaitForSingleObjectEx (priv->event_handle, timeout_ms, FALSE);
GST_TRACE ("Signalled with value %" G_GUINT64_FORMAT, priv->value);
priv->can_wait = FALSE;
}
void
gst_d3d12_fence_wait (GstD3D12Fence * fence)
{
gst_d3d12_fence_wait_for (fence, INFINITE);
}
GstD3D12Fence *
gst_d3d12_fence_ref (GstD3D12Fence * fence)
{
return (GstD3D12Fence *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (fence));
}
void
gst_d3d12_fence_unref (GstD3D12Fence * fence)
{
gst_mini_object_unref (GST_MINI_OBJECT_CAST (fence));
}

View file

@ -0,0 +1,60 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#include "gstd3d12_fwd.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D12_FENCE (gst_d3d12_fence_get_type())
#define GST_D3D12_FENCE_CAST(f) ((GstD3D12Fence *)f)
struct _GstD3D12Fence
{
GstMiniObject parent;
GstD3D12Device *device;
/*< private >*/
GstD3D12FencePrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
GType gst_d3d12_fence_get_type (void);
GstD3D12Fence * gst_d3d12_fence_new (GstD3D12Device * device);
ID3D12Fence * gst_d3d12_fence_get_handle (GstD3D12Fence * fence);
gboolean gst_d3d12_fence_set_event_on_completion_value (GstD3D12Fence * fence,
guint64 value);
void gst_d3d12_fence_wait_for (GstD3D12Fence * fence,
guint timeout_ms);
void gst_d3d12_fence_wait (GstD3D12Fence * fence);
GstD3D12Fence * gst_d3d12_fence_ref (GstD3D12Fence * fence);
void gst_d3d12_fence_unref (GstD3D12Fence * fence);
G_END_DECLS

View file

@ -0,0 +1,127 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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 "gstd3d12format.h"
#include "gstd3d12utils.h"
#include "gstd3d12device.h"
#include <string.h>
GST_DEBUG_CATEGORY_EXTERN (gst_d3d12_format_debug);
#define GST_CAT_DEFAULT gst_d3d12_format_debug
guint
gst_d3d12_get_format_plane_count (GstD3D12Device * device, DXGI_FORMAT format)
{
ID3D12Device *device_handle;
HRESULT hr;
D3D12_FEATURE_DATA_FORMAT_INFO format_info = { format, 0 };
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), 0);
device_handle = gst_d3d12_device_get_device_handle (device);
hr = device_handle->CheckFeatureSupport (D3D12_FEATURE_FORMAT_INFO,
&format_info, sizeof (D3D12_FEATURE_DATA_FORMAT_INFO));
if (!gst_d3d12_result (hr, device))
return 0;
return format_info.PlaneCount;
}
GstVideoFormat
gst_d3d12_dxgi_format_to_gst (DXGI_FORMAT format)
{
switch (format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
return GST_VIDEO_FORMAT_BGRA;
case DXGI_FORMAT_R8G8B8A8_UNORM:
return GST_VIDEO_FORMAT_RGBA;
case DXGI_FORMAT_R10G10B10A2_UNORM:
return GST_VIDEO_FORMAT_RGB10A2_LE;
case DXGI_FORMAT_AYUV:
return GST_VIDEO_FORMAT_VUYA;
case DXGI_FORMAT_YUY2:
return GST_VIDEO_FORMAT_YUY2;
case DXGI_FORMAT_Y210:
return GST_VIDEO_FORMAT_Y210;
case DXGI_FORMAT_Y410:
return GST_VIDEO_FORMAT_Y410;
case DXGI_FORMAT_NV12:
return GST_VIDEO_FORMAT_NV12;
case DXGI_FORMAT_P010:
return GST_VIDEO_FORMAT_P010_10LE;
case DXGI_FORMAT_P016:
return GST_VIDEO_FORMAT_P016_LE;
default:
break;
}
return GST_VIDEO_FORMAT_UNKNOWN;
}
gboolean
gst_d3d12_dxgi_format_to_resource_formats (DXGI_FORMAT format,
DXGI_FORMAT resource_format[GST_VIDEO_MAX_PLANES])
{
g_return_val_if_fail (resource_format != nullptr, FALSE);
for (guint i = 0; i < GST_VIDEO_MAX_PLANES; i++)
resource_format[i] = DXGI_FORMAT_UNKNOWN;
switch (format) {
case DXGI_FORMAT_B8G8R8A8_UNORM:
case DXGI_FORMAT_R8G8B8A8_UNORM:
case DXGI_FORMAT_R10G10B10A2_UNORM:
case DXGI_FORMAT_R8_UNORM:
case DXGI_FORMAT_R8G8_UNORM:
case DXGI_FORMAT_R16_UNORM:
case DXGI_FORMAT_R16G16_UNORM:
case DXGI_FORMAT_G8R8_G8B8_UNORM:
case DXGI_FORMAT_R8G8_B8G8_UNORM:
case DXGI_FORMAT_R16G16B16A16_UNORM:
resource_format[0] = format;
break;
case DXGI_FORMAT_AYUV:
case DXGI_FORMAT_YUY2:
resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case DXGI_FORMAT_NV12:
resource_format[0] = DXGI_FORMAT_R8_UNORM;
resource_format[1] = DXGI_FORMAT_R8G8_UNORM;
break;
case DXGI_FORMAT_P010:
case DXGI_FORMAT_P016:
resource_format[0] = DXGI_FORMAT_R16_UNORM;
resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
break;
case DXGI_FORMAT_Y210:
resource_format[0] = DXGI_FORMAT_R16G16B16A16_UNORM;
break;
case DXGI_FORMAT_Y410:
resource_format[0] = DXGI_FORMAT_R10G10B10A2_UNORM;
break;
default:
return FALSE;
}
return TRUE;
}

View file

@ -0,0 +1,72 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstd3d12_fwd.h"
G_BEGIN_DECLS
#define GST_D3D12_COMMON_FORMATS \
"NV12, P010_10LE, P016_LE "
#define GST_D3D12_SINK_FORMATS \
"{ " GST_D3D12_COMMON_FORMATS " }"
#define GST_D3D12_SRC_FORMATS \
"{ " GST_D3D12_COMMON_FORMATS " }"
#define GST_D3D12_FORMATS_ALL \
"{ " GST_D3D12_COMMON_FORMATS " }"
struct _GstD3D12Format
{
GstVideoFormat format;
/* direct mapping to dxgi format if applicable */
DXGI_FORMAT dxgi_format;
/* formats for texture processing */
DXGI_FORMAT resource_format[GST_VIDEO_MAX_PLANES];
/* extra format used for unordered access view (unused) */
DXGI_FORMAT uav_format[GST_VIDEO_MAX_PLANES];
/* D3D12_FORMAT_SUPPORT1 flags */
guint format_support1[GST_VIDEO_MAX_PLANES];
/* D3D12_FORMAT_SUPPORT2 flags (unused) */
guint format_support2[GST_VIDEO_MAX_PLANES];
/*< private >*/
guint padding[GST_PADDING_LARGE];
};
guint gst_d3d12_get_format_plane_count (GstD3D12Device * device,
DXGI_FORMAT format);
GstVideoFormat gst_d3d12_dxgi_format_to_gst (DXGI_FORMAT format);
gboolean gst_d3d12_dxgi_format_to_resource_formats (DXGI_FORMAT format,
DXGI_FORMAT resource_format[GST_VIDEO_MAX_PLANES]);
G_END_DECLS

View file

@ -0,0 +1,327 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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 02120-1301, USA.
*/
/**
* SECTION:element-d3d12h264dec
* @title: d3d12h264dec
*
* A Direct3D12 based H.264 video decoder
*
* ## Example launch line
* ```
* gst-launch-1.0 filesrc location=/path/to/h264/file ! parsebin ! d3d12h264dec ! videoconvert ! autovideosink
* ```
*
* Since: 1.24
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gstd3d12h264dec.h"
#include "gstd3d12device.h"
#include "gstd3d12utils.h"
#include <gst/dxva/gstdxvah264decoder.h>
GST_DEBUG_CATEGORY_STATIC (gst_d3d12_h264_dec_debug);
#define GST_CAT_DEFAULT gst_d3d12_h264_dec_debug
GST_D3D12_DECODER_DEFINE_TYPE_FULL (GstD3D12H264Dec, gst_d3d12_h264_dec,
GST, D3D12_H264_DEC, GstDxvaH264Decoder);
static void
gst_d3d12_h264_dec_class_init (GstD3D12H264DecClass * klass, gpointer data)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoDecoderClass *decoder_class = GST_VIDEO_DECODER_CLASS (klass);
GstDxvaH264DecoderClass *dxva_class = GST_DXVA_H264_DECODER_CLASS (klass);
GstD3D12DecoderClassData *cdata = (GstD3D12DecoderClassData *) data;
gobject_class->get_property = gst_d3d12_h264_dec_get_property;
element_class->set_context =
GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_set_context);
parent_class = (GstElementClass *) g_type_class_peek_parent (klass);
gst_d3d12_decoder_class_data_fill_subclass_data (cdata, &klass->class_data);
gst_d3d12_decoder_proxy_class_init (element_class, cdata,
"Seungha Yang <seungha@centricualr.com>");
decoder_class->open = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_open);
decoder_class->close = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_close);
decoder_class->negotiate = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_negotiate);
decoder_class->decide_allocation =
GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_decide_allocation);
decoder_class->sink_query = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_sink_query);
decoder_class->src_query = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_src_query);
dxva_class->configure = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_configure);
dxva_class->new_picture = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_new_picture);
dxva_class->duplicate_picture =
GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_duplicate_picture);
dxva_class->get_picture_id =
GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_get_picture_id);
dxva_class->start_picture =
GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_start_picture);
dxva_class->end_picture = GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_end_picture);
dxva_class->output_picture =
GST_DEBUG_FUNCPTR (gst_d3d12_h264_dec_output_picture);
}
static void
gst_d3d12_h264_dec_init (GstD3D12H264Dec * self)
{
}
static void
gst_d3d12_h264_dec_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstD3D12H264DecClass *klass = GST_D3D12_H264_DEC_GET_CLASS (object);
GstD3D12DecoderSubClassData *cdata = &klass->class_data;
gst_d3d12_decoder_proxy_get_property (object, prop_id, value, pspec, cdata);
}
static void
gst_d3d12_h264_dec_set_context (GstElement * element, GstContext * context)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (element);
GstD3D12H264DecClass *klass = GST_D3D12_H264_DEC_GET_CLASS (self);
GstD3D12DecoderSubClassData *cdata = &klass->class_data;
gst_d3d12_handle_set_context_for_adapter_luid (element,
context, cdata->adapter_luid, &self->device);
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static gboolean
gst_d3d12_h264_dec_open (GstVideoDecoder * decoder)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
GstD3D12H264DecClass *klass = GST_D3D12_H264_DEC_GET_CLASS (self);
GstD3D12DecoderSubClassData *cdata = &klass->class_data;
return gst_d3d12_decoder_proxy_open (decoder, cdata, &self->device,
&self->decoder);
}
static gboolean
gst_d3d12_h264_dec_close (GstVideoDecoder * decoder)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
gst_clear_object (&self->decoder);
gst_clear_object (&self->device);
return TRUE;
}
static gboolean
gst_d3d12_h264_dec_negotiate (GstVideoDecoder * decoder)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
if (!gst_d3d12_decoder_negotiate (self->decoder, decoder))
return FALSE;
return GST_VIDEO_DECODER_CLASS (parent_class)->negotiate (decoder);
}
static gboolean
gst_d3d12_h264_dec_decide_allocation (GstVideoDecoder * decoder,
GstQuery * query)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
if (!gst_d3d12_decoder_decide_allocation (self->decoder, decoder, query)) {
return FALSE;
}
return GST_VIDEO_DECODER_CLASS (parent_class)->decide_allocation
(decoder, query);
}
static gboolean
gst_d3d12_h264_dec_sink_query (GstVideoDecoder * decoder, GstQuery * query)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
if (gst_d3d12_handle_context_query (GST_ELEMENT (decoder),
query, self->device)) {
return TRUE;
}
break;
default:
break;
}
return GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (decoder, query);
}
static gboolean
gst_d3d12_h264_dec_src_query (GstVideoDecoder * decoder, GstQuery * query)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_CONTEXT:
if (gst_d3d12_handle_context_query (GST_ELEMENT (decoder),
query, self->device)) {
return TRUE;
}
break;
default:
break;
}
return GST_VIDEO_DECODER_CLASS (parent_class)->src_query (decoder, query);
}
static GstFlowReturn
gst_d3d12_h264_dec_configure (GstDxvaH264Decoder * decoder,
GstVideoCodecState * input_state, const GstVideoInfo * info,
gint crop_x, gint crop_y, gint coded_width, gint coded_height,
gint max_dpb_size)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_configure (self->decoder, input_state, info,
crop_x, crop_y, coded_width, coded_height, max_dpb_size);
}
static GstFlowReturn
gst_d3d12_h264_dec_new_picture (GstDxvaH264Decoder * decoder,
GstCodecPicture * picture)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_new_picture (self->decoder,
GST_VIDEO_DECODER (decoder), picture);
}
static GstFlowReturn
gst_d3d12_h264_dec_duplicate_picture (GstDxvaH264Decoder * decoder,
GstCodecPicture * src, GstCodecPicture * dst)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_duplicate_picture (self->decoder, src, dst);
}
static guint8
gst_d3d12_h264_dec_get_picture_id (GstDxvaH264Decoder * decoder,
GstCodecPicture * picture)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_get_picture_id (self->decoder, picture);
}
static GstFlowReturn
gst_d3d12_h264_dec_start_picture (GstDxvaH264Decoder * decoder,
GstCodecPicture * picture, guint8 * picture_id)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_start_picture (self->decoder, picture, picture_id);
}
static GstFlowReturn
gst_d3d12_h264_dec_end_picture (GstDxvaH264Decoder * decoder,
GstCodecPicture * picture, GPtrArray * ref_pics,
const GstDxvaDecodingArgs * args)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_end_picture (self->decoder, picture, ref_pics, args);
}
static GstFlowReturn
gst_d3d12_h264_dec_output_picture (GstDxvaH264Decoder * decoder,
GstVideoCodecFrame * frame, GstCodecPicture * picture,
GstVideoBufferFlags buffer_flags, gint display_width, gint display_height)
{
GstD3D12H264Dec *self = GST_D3D12_H264_DEC (decoder);
return gst_d3d12_decoder_output_picture (self->decoder,
GST_VIDEO_DECODER (decoder), frame, picture,
buffer_flags, display_width, display_height);
}
void
gst_d3d12_h264_dec_register (GstPlugin * plugin, GstD3D12Device * device,
ID3D12VideoDevice * video_device, guint rank)
{
GType type;
gchar *type_name;
gchar *feature_name;
guint index = 0;
GTypeInfo type_info = {
sizeof (GstD3D12H264DecClass),
nullptr,
nullptr,
(GClassInitFunc) gst_d3d12_h264_dec_class_init,
nullptr,
nullptr,
sizeof (GstD3D12H264Dec),
0,
(GInstanceInitFunc) gst_d3d12_h264_dec_init,
};
GST_DEBUG_CATEGORY_INIT (gst_d3d12_h264_dec_debug, "d3d12h264dec", 0,
"d3d12h264dec");
type_info.class_data =
gst_d3d12_decoder_check_feature_support (device, video_device,
GST_DXVA_CODEC_H264);
if (!type_info.class_data)
return;
type_name = g_strdup ("GstD3D12H264Dec");
feature_name = g_strdup ("d3d12h264dec");
while (g_type_from_name (type_name)) {
index++;
g_free (type_name);
g_free (feature_name);
type_name = g_strdup_printf ("GstD3D12H264Device%dDec", index);
feature_name = g_strdup_printf ("d3d12h264device%ddec", index);
}
type = g_type_register_static (GST_TYPE_DXVA_H264_DECODER,
type_name, &type_info, (GTypeFlags) 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

@ -0,0 +1,32 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include "gstd3d12decoder.h"
G_BEGIN_DECLS
void gst_d3d12_h264_dec_register (GstPlugin * plugin,
GstD3D12Device * device,
ID3D12VideoDevice * video_device,
guint rank);
G_END_DECLS

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,190 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#include <gst/video/video.h>
#include "gstd3d12_fwd.h"
G_BEGIN_DECLS
#define GST_TYPE_D3D12_ALLOCATION_PARAMS (gst_d3d12_allocation_params_get_type())
#define GST_TYPE_D3D12_MEMORY (gst_d3d12_memory_get_type())
#define GST_D3D12_MEMORY_CAST(obj) ((GstD3D12Memory *)obj)
#define GST_TYPE_D3D12_ALLOCATOR (gst_d3d12_allocator_get_type())
#define GST_D3D12_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_D3D12_ALLOCATOR, GstD3D12Allocator))
#define GST_D3D12_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_D3D12_ALLOCATOR, GstD3D12AllocatorClass))
#define GST_IS_D3D12_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_D3D12_ALLOCATOR))
#define GST_IS_D3D12_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_D3D12_ALLOCATOR))
#define GST_D3D12_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_D3D12_ALLOCATOR, GstD3D12AllocatorClass))
#define GST_D3D12_ALLOCATOR_CAST(obj) ((GstD3D12Allocator *)obj)
#define GST_TYPE_D3D12_POOL_ALLOCATOR (gst_d3d12_pool_allocator_get_type())
#define GST_D3D12_POOL_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_D3D12_POOL_ALLOCATOR, GstD3D12PoolAllocator))
#define GST_D3D12_POOL_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_D3D12_POOL_ALLOCATOR, GstD3D12PoolAllocatorClass))
#define GST_IS_D3D12_POOL_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_D3D12_POOL_ALLOCATOR))
#define GST_IS_D3D12_POOL_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_D3D12_POOL_ALLOCATOR))
#define GST_D3D12_POOL_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_D3D12_POOL_ALLOCATOR, GstD3D12PoolAllocatorClass))
#define GST_D3D12_POOL_ALLOCATOR_CAST(obj) ((GstD3D12PoolAllocator *)obj)
/**
* GST_D3D12_MEMORY_NAME:
*
* The name of the Direct3D12 memory
*/
#define GST_D3D12_MEMORY_NAME "D3D12Memory"
/**
* GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY:
*
* Name of the caps feature for indicating the use of #GstD3D12Memory
*/
#define GST_CAPS_FEATURE_MEMORY_D3D12_MEMORY "memory:D3D12Memory"
/**
* GST_MAP_D3D12:
*
* Flag indicating that we should map the D3D12 resource instead of to system memory.
*/
#define GST_MAP_D3D12 (GST_MAP_FLAG_LAST << 1)
struct _GstD3D12Memory
{
GstMemory mem;
/*< public >*/
GstD3D12Device *device;
/*< private >*/
GstD3D12MemoryPrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
GType gst_d3d12_memory_get_type (void);
void gst_d3d12_memory_init_once (void);
gboolean gst_is_d3d12_memory (GstMemory * mem);
ID3D12Resource * gst_d3d12_memory_get_resource_handle (GstD3D12Memory * mem);
gboolean gst_d3d12_memory_get_state (GstD3D12Memory * mem,
D3D12_RESOURCE_STATES * state);
gboolean gst_d3d12_memory_set_state (GstD3D12Memory * mem,
D3D12_RESOURCE_STATES state);
gboolean gst_d3d12_memory_get_subresource_index (GstD3D12Memory * mem,
guint plane,
guint * index);
gboolean gst_d3d12_memory_get_plane_count (GstD3D12Memory * mem,
guint * count);
gboolean gst_d3d12_memory_get_plane_size (GstD3D12Memory * mem,
guint plane,
gint * width,
gint * height,
gint * stride,
gsize * offset);
guint gst_d3d12_memory_get_shader_resource_view_size (GstD3D12Memory * mem);
gboolean gst_d3d12_memory_get_shader_resource_view (GstD3D12Memory * mem,
guint index,
D3D12_CPU_DESCRIPTOR_HANDLE * srv);
guint gst_d3d12_memory_get_render_target_view_size (GstD3D12Memory * mem);
gboolean gst_d3d12_memory_get_render_target_view (GstD3D12Memory * mem,
guint index,
D3D12_CPU_DESCRIPTOR_HANDLE * rtv);
struct _GstD3D12Allocator
{
GstAllocator allocator;
/*< private >*/
GstD3D12AllocatorPrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstD3D12AllocatorClass
{
GstAllocatorClass allocator_class;
gboolean (*set_actvie) (GstD3D12Allocator * allocator,
gboolean active);
/*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE];
};
GType gst_d3d12_allocator_get_type (void);
GstMemory * gst_d3d12_allocator_alloc (GstD3D12Allocator * allocator,
GstD3D12Device * device,
const D3D12_HEAP_PROPERTIES * heap_props,
D3D12_HEAP_FLAGS heap_flags,
const D3D12_RESOURCE_DESC * desc,
D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE * optimized_clear_value);
gboolean gst_d3d12_allocator_set_active (GstD3D12Allocator * allocator,
gboolean active);
struct _GstD3D12PoolAllocator
{
GstD3D12Allocator allocator;
/*< public >*/
GstD3D12Device *device;
/*< private >*/
GstD3D12PoolAllocatorPrivate *priv;
gpointer _gst_reserved[GST_PADDING];
};
struct _GstD3D12PoolAllocatorClass
{
GstD3D12AllocatorClass allocator_class;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType gst_d3d12_pool_allocator_get_type (void);
GstD3D12PoolAllocator * gst_d3d12_pool_allocator_new (GstD3D12Device * device,
const D3D12_HEAP_PROPERTIES * heap_props,
D3D12_HEAP_FLAGS heap_flags,
const D3D12_RESOURCE_DESC * desc,
D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE * optimized_clear_value);
GstFlowReturn gst_d3d12_pool_allocator_acquire_memory (GstD3D12PoolAllocator * allocator,
GstMemory ** memory);
G_END_DECLS

View file

@ -0,0 +1,442 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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 "gstd3d12utils.h"
#include "gstd3d12device.h"
#include <mutex>
/* *INDENT-OFF* */
static std::recursive_mutex context_lock_;
/* *INDENT-ON* */
GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
GST_DEBUG_CATEGORY_EXTERN (gst_d3d12_utils_debug);
#define GST_CAT_DEFAULT gst_d3d12_utils_debug
static void
init_context_debug (void)
{
GST_D3D12_CALL_ONCE_BEGIN {
GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
} GST_D3D12_CALL_ONCE_END;
}
gboolean
gst_d3d12_handle_set_context (GstElement * element, GstContext * context,
gint adapter_index, GstD3D12Device ** device)
{
const gchar *context_type;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (device != nullptr, FALSE);
init_context_debug ();
if (!context)
return FALSE;
context_type = gst_context_get_context_type (context);
if (g_strcmp0 (context_type, GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE) == 0) {
const GstStructure *str;
GstD3D12Device *other_device = nullptr;
guint other_adapter = 0;
/* If we had device already, will not replace it */
if (*device)
return TRUE;
str = gst_context_get_structure (context);
if (gst_structure_get (str, "device", GST_TYPE_D3D12_DEVICE,
&other_device, "adapter-index", G_TYPE_UINT, &other_adapter,
nullptr)) {
if (adapter_index == -1 || (guint) adapter_index == other_adapter) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT,
element, "Found D3D12 device context");
*device = other_device;
return TRUE;
}
gst_object_unref (other_device);
}
}
return FALSE;
}
gboolean
gst_d3d12_handle_set_context_for_adapter_luid (GstElement * element,
GstContext * context, gint64 adapter_luid, GstD3D12Device ** device)
{
const gchar *context_type;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (device != nullptr, FALSE);
init_context_debug ();
if (!context)
return FALSE;
context_type = gst_context_get_context_type (context);
if (g_strcmp0 (context_type, GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE) == 0) {
const GstStructure *str;
GstD3D12Device *other_device = nullptr;
gint64 other_adapter = 0;
/* If we had device already, will not replace it */
if (*device)
return TRUE;
str = gst_context_get_structure (context);
if (gst_structure_get (str, "device", GST_TYPE_D3D12_DEVICE,
&other_device, "adapter-luid", G_TYPE_INT64, &other_adapter,
nullptr)) {
if (adapter_luid == other_adapter) {
GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT,
element, "Found D3D12 device context");
*device = other_device;
return TRUE;
}
gst_object_unref (other_device);
}
}
return FALSE;
}
static void
context_set_d3d12_device (GstContext * context, GstD3D12Device * device)
{
GstStructure *s;
guint adapter_index = 0;
guint device_id = 0;
guint vendor_id = 0;
gchar *desc = nullptr;
gint64 adapter_luid = 0;
g_return_if_fail (context != nullptr);
g_object_get (G_OBJECT (device), "adapter-index", &adapter_index,
"device-id", &device_id, "vendor-id", &vendor_id, "description", &desc,
"adapter-luid", &adapter_luid, nullptr);
GST_CAT_LOG (GST_CAT_CONTEXT,
"setting GstD3D12Device(%" GST_PTR_FORMAT
") with adapter index %d on context(%" GST_PTR_FORMAT ")",
device, adapter_index, context);
s = gst_context_writable_structure (context);
gst_structure_set (s, "device", GST_TYPE_D3D12_DEVICE, device,
"adapter-index", G_TYPE_UINT, adapter_index,
"adapter-luid", G_TYPE_INT64, adapter_luid,
"device-id", G_TYPE_UINT, device_id,
"vendor-id", G_TYPE_UINT, vendor_id,
"description", G_TYPE_STRING, GST_STR_NULL (desc), nullptr);
g_free (desc);
}
gboolean
gst_d3d12_handle_context_query (GstElement * element, GstQuery * query,
GstD3D12Device * device)
{
const gchar *context_type;
GstContext *context, *old_context;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (GST_IS_QUERY (query), FALSE);
init_context_debug ();
GST_LOG_OBJECT (element, "handle context query %" GST_PTR_FORMAT, query);
if (!device)
return FALSE;
gst_query_parse_context_type (query, &context_type);
if (g_strcmp0 (context_type, GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE) != 0)
return FALSE;
gst_query_parse_context (query, &old_context);
if (old_context)
context = gst_context_copy (old_context);
else
context = gst_context_new (GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE, TRUE);
context_set_d3d12_device (context, device);
gst_query_set_context (query, context);
gst_context_unref (context);
GST_DEBUG_OBJECT (element, "successfully set %" GST_PTR_FORMAT
" on %" GST_PTR_FORMAT, device, query);
return TRUE;
}
static gboolean
pad_query (const GValue * item, GValue * value, gpointer user_data)
{
GstPad *pad = (GstPad *) g_value_get_object (item);
GstQuery *query = (GstQuery *) user_data;
gboolean res;
res = gst_pad_peer_query (pad, query);
if (res) {
g_value_set_boolean (value, TRUE);
return FALSE;
}
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "pad peer query failed");
return TRUE;
}
static gboolean
run_query (GstElement * element, GstQuery * query, GstPadDirection direction)
{
GstIterator *it;
GstIteratorFoldFunction func = pad_query;
GValue res = G_VALUE_INIT;
g_value_init (&res, G_TYPE_BOOLEAN);
g_value_set_boolean (&res, FALSE);
/* Ask neighbor */
if (direction == GST_PAD_SRC)
it = gst_element_iterate_src_pads (element);
else
it = gst_element_iterate_sink_pads (element);
while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
gst_iterator_resync (it);
gst_iterator_free (it);
return g_value_get_boolean (&res);
}
static void
run_d3d12_context_query (GstElement * element, GstD3D12Device ** device)
{
GstQuery *query;
GstContext *ctxt = nullptr;
query = gst_query_new_context (GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE);
if (run_query (element, query, GST_PAD_SRC)) {
gst_query_parse_context (query, &ctxt);
if (ctxt) {
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%" GST_PTR_FORMAT ") in downstream query", ctxt);
gst_element_set_context (element, ctxt);
}
}
if (*device == nullptr && run_query (element, query, GST_PAD_SINK)) {
gst_query_parse_context (query, &ctxt);
if (ctxt) {
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"found context (%" GST_PTR_FORMAT ") in upstream query", ctxt);
gst_element_set_context (element, ctxt);
}
}
if (*device == nullptr) {
GstMessage *msg;
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting need context message");
msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE);
gst_element_post_message (element, msg);
}
gst_query_unref (query);
}
gboolean
gst_d3d12_ensure_element_data (GstElement * element, gint adapter_index,
GstD3D12Device ** device)
{
guint target_adapter = 0;
std::lock_guard < std::recursive_mutex > lk (context_lock_);
g_return_val_if_fail (element != nullptr, FALSE);
g_return_val_if_fail (device != nullptr, FALSE);
init_context_debug ();
if (*device) {
GST_LOG_OBJECT (element, "already have a device %" GST_PTR_FORMAT, *device);
return TRUE;
}
run_d3d12_context_query (element, device);
if (*device)
return TRUE;
if (adapter_index > 0)
target_adapter = adapter_index;
*device = gst_d3d12_device_new (target_adapter);
if (*device == nullptr) {
GST_ERROR_OBJECT (element,
"Couldn't create new device with adapter index %d", target_adapter);
return FALSE;
} else {
GstContext *context;
GstMessage *msg;
/* Propagate new D3D12 device context */
context = gst_context_new (GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE, TRUE);
context_set_d3d12_device (context, *device);
gst_element_set_context (element, context);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting have context (%p) message with D3D12 device context (%p)",
context, *device);
msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
gst_element_post_message (GST_ELEMENT_CAST (element), msg);
}
return TRUE;
}
gboolean
gst_d3d12_ensure_element_data_for_adapter_luid (GstElement * element,
gint64 adapter_luid, GstD3D12Device ** device)
{
std::lock_guard < std::recursive_mutex > lk (context_lock_);
g_return_val_if_fail (element != nullptr, FALSE);
g_return_val_if_fail (device != nullptr, FALSE);
init_context_debug ();
if (*device) {
GST_LOG_OBJECT (element, "already have a device %" GST_PTR_FORMAT, *device);
return TRUE;
}
run_d3d12_context_query (element, device);
if (*device)
return TRUE;
*device = gst_d3d12_device_new_for_adapter_luid (adapter_luid);
if (*device == nullptr) {
GST_ERROR_OBJECT (element,
"Couldn't create new device with adapter luid %" G_GINT64_FORMAT,
adapter_luid);
return FALSE;
} else {
GstContext *context;
GstMessage *msg;
/* Propagate new D3D12 device context */
context = gst_context_new (GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE, TRUE);
context_set_d3d12_device (context, *device);
gst_element_set_context (element, context);
GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
"posting have context (%p) message with D3D12 device context (%p)",
context, *device);
msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
gst_element_post_message (GST_ELEMENT_CAST (element), msg);
}
return TRUE;
}
gint64
gst_d3d12_luid_to_int64 (const LUID * luid)
{
LARGE_INTEGER val;
g_return_val_if_fail (luid != nullptr, 0);
val.LowPart = luid->LowPart;
val.HighPart = luid->HighPart;
return val.QuadPart;
}
GstContext *
gst_d3d12_context_new (GstD3D12Device * device)
{
GstContext *context;
g_return_val_if_fail (GST_IS_D3D12_DEVICE (device), nullptr);
context = gst_context_new (GST_D3D12_DEVICE_HANDLE_CONTEXT_TYPE, TRUE);
context_set_d3d12_device (context, device);
return context;
}
gboolean
_gst_d3d12_result (HRESULT hr, GstD3D12Device * device, GstDebugCategory * cat,
const gchar * file, const gchar * function, gint line, GstDebugLevel level)
{
#ifndef GST_DISABLE_GST_DEBUG
gboolean ret = TRUE;
if (device)
gst_d3d12_device_d3d12_debug (device, file, function, line);
if (FAILED (hr)) {
gchar *error_text = nullptr;
error_text = g_win32_error_message ((guint) hr);
/* g_win32_error_message() doesn't cover all HERESULT return code,
* so it could be empty string, or nullptr if there was an error
* in g_utf16_to_utf8() */
gst_debug_log (cat, level, file, function, line,
nullptr, "D3D12 call failed: 0x%x, %s", (guint) hr,
GST_STR_NULL (error_text));
g_free (error_text);
ret = FALSE;
}
return ret;
#else
return SUCCEEDED (hr);
#endif
}
guint
gst_d3d12_calculate_subresource (guint mip_slice, guint array_slice,
guint plane_slice, guint mip_level, guint array_size)
{
return mip_slice + array_slice * mip_level +
plane_slice * mip_level * array_size;
}

View file

@ -0,0 +1,217 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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.
*/
#pragma once
#include <gst/gst.h>
#include "gstd3d12_fwd.h"
#include "gstd3d12device.h"
G_BEGIN_DECLS
gboolean gst_d3d12_handle_set_context (GstElement * element,
GstContext * context,
gint adapter_index,
GstD3D12Device ** device);
gboolean gst_d3d12_handle_set_context_for_adapter_luid (GstElement * element,
GstContext * context,
gint64 adapter_luid,
GstD3D12Device ** device);
gboolean gst_d3d12_handle_context_query (GstElement * element,
GstQuery * query,
GstD3D12Device * device);
gboolean gst_d3d12_ensure_element_data (GstElement * element,
gint adapter_index,
GstD3D12Device ** device);
gboolean gst_d3d12_ensure_element_data_for_adapter_luid (GstElement * element,
gint64 adapter_luid,
GstD3D12Device ** device);
gint64 gst_d3d12_luid_to_int64 (const LUID * luid);
GstContext * gst_d3d12_context_new (GstD3D12Device * device);
gboolean _gst_d3d12_result (HRESULT hr,
GstD3D12Device * device,
GstDebugCategory * cat,
const gchar * file,
const gchar * function,
gint line,
GstDebugLevel level);
/**
* gst_d3d12_result:
* @result: HRESULT D3D12 API return code
* @device: (nullable): Associated #GstD3D12Device
*
* Returns: %TRUE if D3D12 API call result is SUCCESS
*/
#define gst_d3d12_result(result,device) \
_gst_d3d12_result (result, device, GST_CAT_DEFAULT, __FILE__, GST_FUNCTION, __LINE__, GST_LEVEL_ERROR)
guint gst_d3d12_calculate_subresource (guint mip_slice,
guint array_slice,
guint plane_slice,
guint mip_level,
guint array_size);
#define GST_D3D12_CLEAR_COM(obj) G_STMT_START { \
if (obj) { \
(obj)->Release (); \
(obj) = NULL; \
} \
} G_STMT_END
G_END_DECLS
struct CD3D12_HEAP_PROPERTIES : public D3D12_HEAP_PROPERTIES
{
CD3D12_HEAP_PROPERTIES (
D3D12_HEAP_TYPE type,
D3D12_CPU_PAGE_PROPERTY cpu_page_property = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
D3D12_MEMORY_POOL memory_pool_preference = D3D12_MEMORY_POOL_UNKNOWN,
UINT creation_node_mask = 1,
UINT visible_node_mask = 1)
{
Type = type;
CPUPageProperty = cpu_page_property;
MemoryPoolPreference = memory_pool_preference;
CreationNodeMask = creation_node_mask;
VisibleNodeMask = visible_node_mask;
}
};
struct CD3D12_RESOURCE_DESC : public D3D12_RESOURCE_DESC
{
CD3D12_RESOURCE_DESC(
D3D12_RESOURCE_DIMENSION dimension,
UINT64 alignment,
UINT64 width,
UINT height,
UINT16 depth_or_array_size,
UINT16 mip_levels,
DXGI_FORMAT format,
UINT sample_count,
UINT sample_quality,
D3D12_TEXTURE_LAYOUT layout,
D3D12_RESOURCE_FLAGS flags)
{
Dimension = dimension;
Alignment = alignment;
Width = width;
Height = height;
DepthOrArraySize = depth_or_array_size;
MipLevels = mip_levels;
Format = format;
SampleDesc.Count = sample_count;
SampleDesc.Quality = sample_quality;
Layout = layout;
Flags = flags;
}
static inline CD3D12_RESOURCE_DESC Buffer (
UINT64 width,
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
UINT64 alignment = 0)
{
return CD3D12_RESOURCE_DESC (D3D12_RESOURCE_DIMENSION_BUFFER, alignment,
width, 1, 1, 1, DXGI_FORMAT_UNKNOWN, 1, 0,
D3D12_TEXTURE_LAYOUT_ROW_MAJOR, flags);
}
static inline CD3D12_RESOURCE_DESC Tex2D (
DXGI_FORMAT format,
UINT64 width,
UINT height,
UINT16 array_size = 1,
UINT16 mip_levels = 0,
UINT sample_count = 1,
UINT sample_quality = 0,
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
D3D12_TEXTURE_LAYOUT layout = D3D12_TEXTURE_LAYOUT_UNKNOWN,
UINT64 alignment = 0)
{
return CD3D12_RESOURCE_DESC(D3D12_RESOURCE_DIMENSION_TEXTURE2D, alignment,
width, height, array_size, mip_levels, format, sample_count,
sample_quality, layout, flags);
}
};
struct CD3D12_RESOURCE_BARRIER : public D3D12_RESOURCE_BARRIER
{
static inline CD3D12_RESOURCE_BARRIER Transition (
ID3D12Resource * resource,
D3D12_RESOURCE_STATES before,
D3D12_RESOURCE_STATES after,
UINT subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
D3D12_RESOURCE_BARRIER_FLAGS flags = D3D12_RESOURCE_BARRIER_FLAG_NONE)
{
CD3D12_RESOURCE_BARRIER result;
D3D12_RESOURCE_BARRIER &barrier = result;
result.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
result.Flags = flags;
barrier.Transition.pResource = resource;
barrier.Transition.StateBefore = before;
barrier.Transition.StateAfter = after;
barrier.Transition.Subresource = subresource;
return result;
}
};
struct CD3D12_TEXTURE_COPY_LOCATION : public D3D12_TEXTURE_COPY_LOCATION
{
CD3D12_TEXTURE_COPY_LOCATION (ID3D12Resource * resource)
{
pResource = resource;
Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
PlacedFootprint = {};
}
CD3D12_TEXTURE_COPY_LOCATION (
ID3D12Resource * resource,
D3D12_PLACED_SUBRESOURCE_FOOTPRINT const & foot_print)
{
pResource = resource;
Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
PlacedFootprint = foot_print;
}
CD3D12_TEXTURE_COPY_LOCATION (
ID3D12Resource * resource,
UINT subresource)
{
pResource = resource;
Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
PlacedFootprint = {};
SubresourceIndex = subresource;
}
};
#include <mutex>
#define GST_D3D12_CALL_ONCE_BEGIN \
static std::once_flag __once_flag; \
std::call_once (__once_flag, [&]()
#define GST_D3D12_CALL_ONCE_END )

View file

@ -0,0 +1,75 @@
d3d12_sources = [
'gstd3d12decoder.cpp',
'gstd3d12device.cpp',
'gstd3d12fence.cpp',
'gstd3d12format.cpp',
'gstd3d12h264dec.cpp',
'gstd3d12memory.cpp',
'gstd3d12utils.cpp',
'plugin.cpp',
]
extra_args = ['-DGST_USE_UNSTABLE_API']
extra_dep = []
d3d12_option = get_option('d3d12')
if host_system != 'windows' or d3d12_option.disabled()
subdir_done()
endif
d3d12_lib = cc.find_library('d3d12', required : d3d12_option)
dxgi_lib = cc.find_library('dxgi', required : d3d12_option)
if not gstdxva_dep.found() or not d3d12_lib.found() or not dxgi_lib.found()
if d3d12_option.enabled()
error('The d3d12 was enabled explicitly, but required GstD3D11 dependencies were not found.')
endif
subdir_done()
endif
d3d12_headers = [
'd3d12.h',
'd3d12video.h',
'dxgi1_6.h',
'wrl.h',
]
have_d3d12_headers = true
foreach h: d3d12_headers
if not cc.has_header(h)
have_d3d12_headers = false
endif
endforeach
if not have_d3d12_headers
if d3d12_option.enabled()
error('The d3d12 plugin was enabled explicitly, but required dependencies were not found.')
endif
subdir_done()
endif
if cc.has_header('d3d12sdklayers.h')
extra_dep += ['-DHAVE_D3D12_SDKLAYERS_H']
endif
# MinGW 32bits compiler seems to be complaining about redundant-decls
# when ComPtr is in use. Let's just disable the warning
if cc.get_id() != 'msvc'
extra_mingw_args = cc.get_supported_arguments([
'-Wno-redundant-decls',
])
extra_args += extra_mingw_args
endif
gstd3d12 = library('gstd3d12',
d3d12_sources,
c_args : gst_plugins_bad_args + extra_args,
cpp_args: gst_plugins_bad_args + extra_args,
include_directories : [configinc],
dependencies : [gstbase_dep, gstvideo_dep, gstcodecs_dep,
gstdxva_dep, d3d12_lib, dxgi_lib],
install : true,
install_dir : plugins_install_dir,
)
plugins += [gstd3d12]

View file

@ -0,0 +1,94 @@
/* GStreamer
* Copyright (C) 2023 Seungha Yang <seungha@centricular.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 <gst/gst.h>
#include "gstd3d12device.h"
#include "gstd3d12h264dec.h"
#include <wrl.h>
/* *INDENT-OFF* */
using namespace Microsoft::WRL;
/* *INDENT-ON* */
GST_DEBUG_CATEGORY (gst_d3d12_debug);
GST_DEBUG_CATEGORY (gst_d3d12_allocator_debug);
GST_DEBUG_CATEGORY (gst_d3d12_command_list_debug);
GST_DEBUG_CATEGORY (gst_d3d12_decoder_debug);
GST_DEBUG_CATEGORY (gst_d3d12_fence_debug);
GST_DEBUG_CATEGORY (gst_d3d12_format_debug);
GST_DEBUG_CATEGORY (gst_d3d12_utils_debug);
#define GST_CAT_DEFAULT gst_d3d12_debug
static gboolean
plugin_init (GstPlugin * plugin)
{
GST_DEBUG_CATEGORY_INIT (gst_d3d12_debug, "d3d12", 0, "d3d12");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_allocator_debug, "d3d12allocator", 0,
"d3d12allocator");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_command_list_debug, "d3d12commandlist", 0,
"d3d12commandlist");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_decoder_debug, "d3d12decoder", 0,
"d3d12decoder");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_fence_debug, "d3d12fence", 0,
"d3d12fence");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_format_debug, "d3d12format", 0,
"d3d12format");
GST_DEBUG_CATEGORY_INIT (gst_d3d12_utils_debug,
"d3d12utils", 0, "d3d12utils");
/* Enumerate devices to register decoders per device and to get the highest
* feature level */
/* AMD seems to be supporting up to 12 cards, and 8 for NVIDIA */
for (guint i = 0; i < 12; i++) {
GstD3D12Device *device = nullptr;
ID3D12Device *device_handle;
ComPtr < ID3D12VideoDevice > video_device;
HRESULT hr;
device = gst_d3d12_device_new (i);
if (!device)
break;
device_handle = gst_d3d12_device_get_device_handle (device);
hr = device_handle->QueryInterface (IID_PPV_ARGS (&video_device));
if (FAILED (hr)) {
gst_object_unref (device);
continue;
}
gst_d3d12_h264_dec_register (plugin, device, video_device.Get (),
GST_RANK_NONE);
gst_object_unref (device);
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
d3d12,
"Direct3D12 plugin",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -4,6 +4,7 @@ subdir('applemedia')
subdir('asio')
subdir('bluez')
subdir('d3d11')
subdir('d3d12')
subdir('d3dvideosink')
subdir('decklink')
subdir('directsound')