Commit 84db4b68 authored by Seungha Yang's avatar Seungha Yang 🐑 Committed by GStreamer Marge Bot
Browse files

mfvideoenc: Add support for Direct3D11 texture

Initial support for d3d11 texture so that encoder can copy
upstream d3d11 texture into encoder's own texture pool without
downloading memory.

This implementation requires MFTEnum2() API for creating
MFT (Media Foundation Transform) object for specific GPU but
the API is Windows 10 desktop only. So UWP is not target
of this change.
See also https://docs.microsoft.com/en-us/windows/win32/api/mfapi/nf-mfapi-mftenum2

Note that, for MF plugin to be able to support old OS versions
without breakage, this commit will load MFTEnum2() symbol
by using g_module_open()

Summary of required system environment:
- Needs Windows 10 (probably at least RS 1 update)
- GPU should support ExtendedNV12SharedTextureSupported feature
- Desktop application only (UWP is not supported yet)

Part-of: <!1903>
parent 86c009e7
......@@ -35,12 +35,18 @@
#include "config.h"
#endif
#include "gstmfconfig.h"
#include <gst/gst.h>
#include <gst/pbutils/pbutils.h>
#include "gstmfvideoenc.h"
#include "gstmfh264enc.h"
#include <wrl.h>
#if GST_MF_HAVE_D3D11
#include <gst/d3d11/gstd3d11.h>
#endif
using namespace Microsoft::WRL;
GST_DEBUG_CATEGORY (gst_mf_h264_enc_debug);
......@@ -154,6 +160,8 @@ enum
PROP_QP_P,
PROP_QP_B,
PROP_REF,
PROP_D3D11_AWARE,
PROP_ADAPTER,
};
#define DEFAULT_BITRATE (2 * 1024)
......@@ -456,6 +464,21 @@ gst_mf_h264_enc_class_init (GstMFH264EncClass * klass, gpointer data)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
}
g_object_class_install_property (gobject_class, PROP_D3D11_AWARE,
g_param_spec_boolean ("d3d11-aware", "D3D11 Aware",
"Whether device can support Direct3D11 interop",
device_caps->d3d11_aware,
(GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
if (device_caps->d3d11_aware) {
g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_uint ("adapter", "Adapter",
"DXGI Adapter index for creating device",
0, G_MAXUINT32, device_caps->adapter,
(GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
}
long_name = g_strdup_printf ("Media Foundation %s", cdata->device_name);
classification = g_strdup_printf ("Codec/Encoder/Video%s",
(cdata->enum_flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE ?
......@@ -519,6 +542,7 @@ gst_mf_h264_enc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstMFH264Enc *self = (GstMFH264Enc *) (object);
GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (object);
switch (prop_id) {
case PROP_BITRATE:
......@@ -587,6 +611,12 @@ gst_mf_h264_enc_get_property (GObject * object, guint prop_id,
case PROP_REF:
g_value_set_uint (value, self->max_num_ref);
break;
case PROP_D3D11_AWARE:
g_value_set_boolean (value, klass->device_caps.d3d11_aware);
break;
case PROP_ADAPTER:
g_value_set_uint (value, klass->device_caps.adapter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -984,7 +1014,8 @@ gst_mf_h264_enc_set_src_caps (GstMFVideoEnc * mfenc,
}
void
gst_mf_h264_enc_plugin_init (GstPlugin * plugin, guint rank)
gst_mf_h264_enc_plugin_init (GstPlugin * plugin, guint rank,
GList * d3d11_device)
{
GTypeInfo type_info = {
sizeof (GstMFH264EncClass),
......@@ -1001,5 +1032,5 @@ gst_mf_h264_enc_plugin_init (GstPlugin * plugin, guint rank)
GST_DEBUG_CATEGORY_INIT (gst_mf_h264_enc_debug, "mfh264enc", 0, "mfh264enc");
gst_mf_video_enc_register (plugin, rank, &subtype, &type_info);
gst_mf_video_enc_register (plugin, rank, &subtype, &type_info, d3d11_device);
}
......@@ -26,7 +26,8 @@
G_BEGIN_DECLS
void gst_mf_h264_enc_plugin_init (GstPlugin * plugin,
guint rank);
guint rank,
GList * d3d11_device);
G_END_DECLS
......
......@@ -115,6 +115,8 @@ enum
PROP_QP_P,
PROP_QP_B,
PROP_REF,
PROP_D3D11_AWARE,
PROP_ADAPTER,
};
#define DEFAULT_BITRATE (2 * 1024)
......@@ -353,6 +355,21 @@ gst_mf_h265_enc_class_init (GstMFH265EncClass * klass, gpointer data)
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
}
g_object_class_install_property (gobject_class, PROP_D3D11_AWARE,
g_param_spec_boolean ("d3d11-aware", "D3D11 Aware",
"Whether device can support Direct3D11 interop",
device_caps->d3d11_aware,
(GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
if (device_caps->d3d11_aware) {
g_object_class_install_property (gobject_class, PROP_ADAPTER,
g_param_spec_uint ("adapter", "Adapter",
"DXGI Adapter index for creating device",
0, G_MAXUINT32, device_caps->adapter,
(GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE |
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
}
long_name = g_strdup_printf ("Media Foundation %s", cdata->device_name);
classification = g_strdup_printf ("Codec/Encoder/Video%s",
(cdata->enum_flags & MFT_ENUM_FLAG_HARDWARE) == MFT_ENUM_FLAG_HARDWARE ?
......@@ -411,6 +428,7 @@ gst_mf_h265_enc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstMFH265Enc *self = (GstMFH265Enc *) (object);
GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (object);
switch (prop_id) {
case PROP_BITRATE:
......@@ -464,6 +482,12 @@ gst_mf_h265_enc_get_property (GObject * object, guint prop_id,
case PROP_REF:
g_value_set_uint (value, self->max_num_ref);
break;
case PROP_D3D11_AWARE:
g_value_set_boolean (value, klass->device_caps.d3d11_aware);
break;
case PROP_ADAPTER:
g_value_set_uint (value, klass->device_caps.adapter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -753,7 +777,8 @@ gst_mf_h265_enc_set_src_caps (GstMFVideoEnc * mfenc,
}
void
gst_mf_h265_enc_plugin_init (GstPlugin * plugin, guint rank)
gst_mf_h265_enc_plugin_init (GstPlugin * plugin, guint rank,
GList * d3d11_device)
{
GTypeInfo type_info = {
sizeof (GstMFH265EncClass),
......@@ -770,5 +795,5 @@ gst_mf_h265_enc_plugin_init (GstPlugin * plugin, guint rank)
GST_DEBUG_CATEGORY_INIT (gst_mf_h265_enc_debug, "mfh265enc", 0, "mfh265enc");
gst_mf_video_enc_register (plugin, rank, &subtype, &type_info);
gst_mf_video_enc_register (plugin, rank, &subtype, &type_info, d3d11_device);
}
\ No newline at end of file
......@@ -26,7 +26,8 @@
G_BEGIN_DECLS
void gst_mf_h265_enc_plugin_init (GstPlugin * plugin,
guint rank);
guint rank,
GList * d3d11_device);
G_END_DECLS
......
......@@ -22,7 +22,10 @@
#include "config.h"
#endif
#include "gstmfconfig.h"
#include <gst/gst.h>
#include <gmodule.h>
#include "gstmftransform.h"
#include "gstmfutils.h"
#include <string.h>
......@@ -37,6 +40,43 @@ GST_DEBUG_CATEGORY_EXTERN (gst_mf_transform_debug);
G_END_DECLS
static GModule *mf_plat_module = NULL;
typedef HRESULT (__stdcall *pMFTEnum2) (GUID guidCategory,
UINT32 Flags,
const MFT_REGISTER_TYPE_INFO * pInputType,
const MFT_REGISTER_TYPE_INFO * pOutputType,
IMFAttributes * pAttributes,
IMFActivate *** pppMFTActivate,
UINT32 * pnumMFTActivate);
static pMFTEnum2 GstMFTEnum2Func = NULL;
gboolean
gst_mf_transform_load_library (void)
{
#if GST_MF_HAVE_D3D11
static volatile gsize _init = 0;
if (g_once_init_enter (&_init)) {
mf_plat_module = g_module_open ("mfplat.dll", G_MODULE_BIND_LAZY);
if (mf_plat_module) {
if (!g_module_symbol (mf_plat_module, "MFTEnum2",
(gpointer *) & GstMFTEnum2Func)) {
GST_WARNING ("Cannot load MFTEnum2 symbol");
g_module_close (mf_plat_module);
mf_plat_module = NULL;
GstMFTEnum2Func = NULL;
} else {
GST_INFO ("MFTEnum2 symbol is available");
}
}
g_once_init_leave (&_init, 1);
}
#endif
return ! !GstMFTEnum2Func;
}
typedef HRESULT (*GstMFTransformAsyncCallbackOnEvent) (MediaEventType event,
GstObject * client);
......@@ -221,6 +261,7 @@ enum
PROP_DEVICE_NAME,
PROP_HARDWARE,
PROP_ENUM_PARAMS,
PROP_D3D11_AWARE,
};
struct _GstMFTransform
......@@ -232,6 +273,7 @@ struct _GstMFTransform
gchar *device_name;
gboolean hardware;
gboolean d3d11_aware;
IMFActivate *activate;
IMFTransform *transform;
......@@ -299,6 +341,10 @@ gst_mf_transform_class_init (GstMFTransformClass * klass)
"GstMFTransformEnumParams for MFTEnumEx",
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)));
g_object_class_install_property (gobject_class, PROP_D3D11_AWARE,
g_param_spec_boolean ("d3d11-aware", "D3D11 Aware",
"Whether Direct3D11 supports Direct3D11", FALSE,
(GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
}
static void
......@@ -382,6 +428,9 @@ gst_mf_transform_get_property (GObject * object, guint prop_id,
case PROP_HARDWARE:
g_value_set_boolean (value, self->hardware);
break;
case PROP_D3D11_AWARE:
g_value_set_boolean (value, self->d3d11_aware);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -404,6 +453,7 @@ gst_mf_transform_set_property (GObject * object, guint prop_id,
self->enum_params.category = params->category;
self->enum_params.enum_flags = params->enum_flags;
self->enum_params.device_index = params->device_index;
self->enum_params.adapter_luid = params->adapter_luid;
if (params->input_typeinfo) {
self->enum_params.input_typeinfo = g_new0 (MFT_REGISTER_TYPE_INFO, 1);
memcpy (self->enum_params.input_typeinfo, params->input_typeinfo,
......@@ -438,7 +488,7 @@ gst_mf_transform_main_loop_running_cb (GstMFTransform * self)
static gpointer
gst_mf_transform_thread_func (GstMFTransform * self)
{
HRESULT hr;
HRESULT hr = S_OK;
IMFActivate **devices = NULL;
UINT32 num_devices, i;
LPWSTR name = NULL;
......@@ -454,9 +504,43 @@ gst_mf_transform_thread_func (GstMFTransform * self)
g_source_attach (source, self->context);
g_source_unref (source);
hr = MFTEnumEx (self->enum_params.category, self->enum_params.enum_flags,
self->enum_params.input_typeinfo, self->enum_params.output_typeinfo,
&devices, &num_devices);
/* NOTE: MFTEnum2 is desktop only and requires Windows 10 */
#if GST_MF_HAVE_D3D11
if (GstMFTEnum2Func && self->enum_params.adapter_luid &&
(self->enum_params.enum_flags & MFT_ENUM_FLAG_HARDWARE) != 0) {
ComPtr<IMFAttributes> attr;
LUID luid;
hr = MFCreateAttributes (&attr, 1);
if (!gst_mf_result (hr)) {
GST_ERROR_OBJECT (self, "Couldn't create IMFAttributes");
goto run_loop;
}
GST_INFO_OBJECT (self,
"Enumerating MFT for adapter-luid %" G_GINT64_FORMAT,
self->enum_params.adapter_luid);
luid.LowPart = (DWORD) (self->enum_params.adapter_luid & 0xffffffff);
luid.HighPart = (LONG) (self->enum_params.adapter_luid >> 32);
hr = attr->SetBlob (GST_GUID_MFT_ENUM_ADAPTER_LUID, (BYTE *) &luid,
sizeof (LUID));
if (!gst_mf_result (hr)) {
GST_ERROR_OBJECT (self, "Couldn't set MFT_ENUM_ADAPTER_LUID");
goto run_loop;
}
hr = GstMFTEnum2Func (self->enum_params.category,
self->enum_params.enum_flags, self->enum_params.input_typeinfo,
self->enum_params.output_typeinfo, attr.Get (), &devices, &num_devices);
} else
#endif
{
hr = MFTEnumEx (self->enum_params.category, self->enum_params.enum_flags,
self->enum_params.input_typeinfo, self->enum_params.output_typeinfo,
&devices, &num_devices);
}
if (!gst_mf_result (hr)) {
GST_WARNING_OBJECT (self, "MFTEnumEx failure");
......@@ -833,6 +917,7 @@ gst_mf_transform_open_internal (GstMFTransformOpenData * data)
if (object->hardware) {
ComPtr<IMFAttributes> attr;
UINT32 supports_d3d11 = 0;
hr = object->transform->GetAttributes (attr.GetAddressOf ());
if (!gst_mf_result (hr)) {
......@@ -846,6 +931,12 @@ gst_mf_transform_open_internal (GstMFTransformOpenData * data)
goto done;
}
hr = attr->GetUINT32 (GST_GUID_MF_SA_D3D11_AWARE, &supports_d3d11);
if (gst_mf_result (hr) && supports_d3d11 != 0) {
GST_DEBUG_OBJECT (object, "MFT supports direct3d11");
object->d3d11_aware = TRUE;
}
/* Create our IMFAsyncCallback object so that listen METransformNeedInput
* and METransformHaveOutput events. The event callback will be called from
* Media Foundation's worker queue thread */
......@@ -909,6 +1000,29 @@ gst_mf_transform_open (GstMFTransform * object)
return data.ret;
}
gboolean
gst_mf_transform_set_device_manager (GstMFTransform * object,
IMFDXGIDeviceManager * manager)
{
HRESULT hr;
g_return_val_if_fail (GST_IS_MF_TRANSFORM (object), FALSE);
if (!object->transform) {
GST_ERROR_OBJECT (object, "IMFTransform is not configured yet");
return FALSE;
}
hr = object->transform->ProcessMessage (MFT_MESSAGE_SET_D3D_MANAGER,
(ULONG_PTR) manager);
if (!gst_mf_result (hr)) {
GST_ERROR_OBJECT (object, "Couldn't set device manager");
return FALSE;
}
return TRUE;
}
void
gst_mf_transform_set_new_sample_callback (GstMFTransform * object,
GstMFTransformNewSampleCallback callback, gpointer user_data)
......
......@@ -34,6 +34,26 @@ G_DECLARE_FINAL_TYPE (GstMFTransform, gst_mf_transform,
#define GST_MF_TRANSFORM_FLOW_NEED_DATA GST_FLOW_CUSTOM_SUCCESS
/* NOTE: This GUID is defined in mfapi.h header but it's available only for
* at least Windows 10 RS1. So defining the GUID here again so that
* make use even if build target (e.g., WINVER) wasn't for Windows 10 */
DEFINE_GUID(GST_GUID_MFT_ENUM_ADAPTER_LUID,
0x1d39518c, 0xe220, 0x4da8, 0xa0, 0x7f, 0xba, 0x17, 0x25, 0x52, 0xd6, 0xb1);
/* below GUIDs are defined in mftransform.h for Windows 8 or greater
* FIXME: remove below defines when we bump minimum supported OS version to
* Windows 10 */
DEFINE_GUID(GST_GUID_MF_SA_D3D11_AWARE,
0x206b4fc8, 0xfcf9, 0x4c51, 0xaf, 0xe3, 0x97, 0x64, 0x36, 0x9e, 0x33, 0xa0);
DEFINE_GUID(GST_GUID_MF_SA_BUFFERS_PER_SAMPLE,
0x873c5171, 0x1e3d, 0x4e25, 0x98, 0x8d, 0xb4, 0x33, 0xce, 0x04, 0x19, 0x83);
DEFINE_GUID(GST_GUID_MF_SA_D3D11_USAGE,
0xe85fe442, 0x2ca3, 0x486e, 0xa9, 0xc7, 0x10, 0x9d, 0xda, 0x60, 0x98, 0x80);
DEFINE_GUID(GST_GUID_MF_SA_D3D11_SHARED_WITHOUT_MUTEX,
0x39dbd44d, 0x2e44, 0x4931, 0xa4, 0xc8, 0x35, 0x2d, 0x3d, 0xc4, 0x21, 0x15);
DEFINE_GUID(GST_GUID_MF_SA_D3D11_BINDFLAGS,
0xeacf97ad, 0x065c, 0x4408, 0xbe, 0xe3, 0xfd, 0xcb, 0xfd, 0x12, 0x8b, 0xe2);
typedef struct _GstMFTransformEnumParams
{
GUID category;
......@@ -42,16 +62,22 @@ typedef struct _GstMFTransformEnumParams
MFT_REGISTER_TYPE_INFO *output_typeinfo;
guint device_index;
gint64 adapter_luid;
} GstMFTransformEnumParams;
typedef HRESULT (*GstMFTransformNewSampleCallback) (GstMFTransform * object,
IMFSample * sample,
gpointer user_data);
gboolean gst_mf_transform_load_library (void);
GstMFTransform * gst_mf_transform_new (GstMFTransformEnumParams * params);
gboolean gst_mf_transform_open (GstMFTransform * object);
gboolean gst_mf_transform_set_device_manager (GstMFTransform * object,
IMFDXGIDeviceManager * manager);
void gst_mf_transform_set_new_sample_callback (GstMFTransform * object,
GstMFTransformNewSampleCallback callback,
gpointer user_data);
......
......@@ -41,6 +41,9 @@ G_END_DECLS
G_DEFINE_ABSTRACT_TYPE (GstMFVideoEnc, gst_mf_video_enc,
GST_TYPE_VIDEO_ENCODER);
static void gst_mf_video_enc_dispose (GObject * object);
static void gst_mf_video_enc_set_context (GstElement * element,
GstContext * context);
static gboolean gst_mf_video_enc_open (GstVideoEncoder * enc);
static gboolean gst_mf_video_enc_close (GstVideoEncoder * enc);
static gboolean gst_mf_video_enc_set_format (GstVideoEncoder * enc,
......@@ -49,6 +52,12 @@ static GstFlowReturn gst_mf_video_enc_handle_frame (GstVideoEncoder * enc,
GstVideoCodecFrame * frame);
static GstFlowReturn gst_mf_video_enc_finish (GstVideoEncoder * enc);
static gboolean gst_mf_video_enc_flush (GstVideoEncoder * enc);
static gboolean gst_mf_video_enc_propose_allocation (GstVideoEncoder * enc,
GstQuery * query);
static gboolean gst_mf_video_enc_sink_query (GstVideoEncoder * enc,
GstQuery * query);
static gboolean gst_mf_video_enc_src_query (GstVideoEncoder * enc,
GstQuery * query);
static HRESULT gst_mf_video_on_new_sample (GstMFTransform * object,
IMFSample * sample, GstMFVideoEnc * self);
......@@ -56,8 +65,14 @@ static HRESULT gst_mf_video_on_new_sample (GstMFTransform * object,
static void
gst_mf_video_enc_class_init (GstMFVideoEncClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstVideoEncoderClass *videoenc_class = GST_VIDEO_ENCODER_CLASS (klass);
gobject_class->dispose = gst_mf_video_enc_dispose;
element_class->set_context = GST_DEBUG_FUNCPTR (gst_mf_video_enc_set_context);
videoenc_class->open = GST_DEBUG_FUNCPTR (gst_mf_video_enc_open);
videoenc_class->close = GST_DEBUG_FUNCPTR (gst_mf_video_enc_close);
videoenc_class->set_format = GST_DEBUG_FUNCPTR (gst_mf_video_enc_set_format);
......@@ -65,6 +80,12 @@ gst_mf_video_enc_class_init (GstMFVideoEncClass * klass)
GST_DEBUG_FUNCPTR (gst_mf_video_enc_handle_frame);
videoenc_class->finish = GST_DEBUG_FUNCPTR (gst_mf_video_enc_finish);
videoenc_class->flush = GST_DEBUG_FUNCPTR (gst_mf_video_enc_flush);
videoenc_class->propose_allocation =
GST_DEBUG_FUNCPTR (gst_mf_video_enc_propose_allocation);
videoenc_class->sink_query =
GST_DEBUG_FUNCPTR (gst_mf_video_enc_sink_query);
videoenc_class->src_query =
GST_DEBUG_FUNCPTR (gst_mf_video_enc_src_query);
gst_type_mark_as_plugin_api (GST_TYPE_MF_VIDEO_ENC, (GstPluginAPIFlags) 0);
}
......@@ -74,15 +95,89 @@ gst_mf_video_enc_init (GstMFVideoEnc * self)
{
}
static void
gst_mf_video_enc_dispose (GObject * object)
{
#if GST_MF_HAVE_D3D11
GstMFVideoEnc *self = GST_MF_VIDEO_ENC (object);
gst_clear_object (&self->d3d11_device);
gst_clear_object (&self->other_d3d11_device);
#endif
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_mf_video_enc_set_context (GstElement * element, GstContext * context)
{
#if GST_MF_HAVE_D3D11
GstMFVideoEnc *self = GST_MF_VIDEO_ENC (element);
gst_d3d11_handle_set_context (element, context, 0, &self->other_d3d11_device);
#endif
GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
}
static gboolean
gst_mf_video_enc_open (GstVideoEncoder * enc)
{
GstMFVideoEnc *self = GST_MF_VIDEO_ENC (enc);
GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (enc);
GstMFVideoEncDeviceCaps *device_caps = &klass->device_caps;
GstMFTransformEnumParams enum_params = { 0, };
gint64 adapter_luid = 0;
MFT_REGISTER_TYPE_INFO output_type;
gboolean ret;
#if GST_MF_HAVE_D3D11
if (device_caps->d3d11_aware) {
HRESULT hr;
ID3D11Device *device_handle;
GstD3D11Device *device;
if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self),
device_caps->adapter, &self->other_d3d11_device)) {
GST_ERROR_OBJECT (self, "Other d3d11 device is unavailable");
return FALSE;
}
/* Create our own device with D3D11_CREATE_DEVICE_VIDEO_SUPPORT */
self->d3d11_device = gst_d3d11_device_new (device_caps->adapter,
D3D11_CREATE_DEVICE_VIDEO_SUPPORT);
if (!self->d3d11_device) {
GST_ERROR_OBJECT (self, "Couldn't create internal d3d11 device");
gst_clear_object (&self->other_d3d11_device);
return FALSE;
}
device = self->d3d11_device;
hr = MFCreateDXGIDeviceManager (&self->reset_token,
&self->device_manager);
if (!gst_mf_result (hr)) {
GST_ERROR_OBJECT (self, "Couldn't create DXGI device manager");
gst_clear_object (&self->other_d3d11_device);
gst_clear_object (&self->d3d11_device);
return FALSE;
}
device_handle = gst_d3d11_device_get_device_handle (device);
hr = self->device_manager->ResetDevice ((IUnknown *) device_handle,
self->reset_token);
if (!gst_mf_result (hr)) {
GST_ERROR_OBJECT (self,
"Couldn't reset device with given d3d11 device");
gst_clear_object (&self->other_d3d11_device);
gst_clear_object (&self->d3d11_device);
return FALSE;
}
g_object_get (self->d3d11_device, "adapter-luid", &adapter_luid, NULL);
}
#endif
output_type.guidMajorType = MFMediaType_Video;
output_type.guidSubtype = klass->codec_id;
......@@ -91,14 +186,21 @@ gst_mf_video_enc_open (GstVideoEncoder * enc)
enum_params.output_typeinfo = &output_type;
enum_params.device_index = klass->device_index;
GST_DEBUG_OBJECT (self, "Create MFT with enum flags 0x%x, device index %d",
klass->enum_flags, klass->device_index);
if (device_caps->d3d11_aware)
enum_params.adapter_luid = adapter_luid;
GST_DEBUG_OBJECT (self,
"Create MFT with enum flags: 0x%x, device index: %d, d3d11 aware: %d, "
"adapter-luid %" G_GINT64_FORMAT, klass->enum_flags, klass->device_index,
device_caps->d3d11_aware, adapter_luid);
self->transform = gst_mf_transform_new (&enum_params);
ret = !!self->transform;
if (!ret)
if (!ret) {
GST_ERROR_OBJECT (self, "Cannot create MFT object");
return FALSE;
}
/* In case of hardware MFT, it will be running on async mode.
* And new output sample callback will be called from Media Foundation's
......@@ -129,6 +231,22 @@ gst_mf_video_enc_close (GstVideoEncoder * enc)
self->input_state = NULL;
}
#if GST_MF_HAVE_D3D11
if (self->device_manager) {
self->device_manager->Release ();
self->device_manager = nullptr;
}
if (self->mf_allocator) {
self->mf_allocator->UninitializeSampleAllocator ();
self->mf_allocator->Release ();
self->mf_allocator = NULL;
}
gst_clear_object (&self->other_d3d11_device);
gst_clear_object (&self->d3d11_device);
#endif
return TRUE;
}
...