nvdecoder: Add support for D3D11 output

Since DXVA does not support some profiles such as HEVC RExt,
vendor specific decoding API is still required.
When decoder is negotiated with d3d11 caps, decoder will convert
semi-planar frame to planar since semi-planar format (e.g.,
DXGI_FORMAT_NV12) is not supported by CUDA/D3D11 interop.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5409>
This commit is contained in:
Seungha Yang 2023-09-28 00:03:08 +09:00 committed by GStreamer Marge Bot
parent 57e0a0bd61
commit 42560c24df
13 changed files with 513 additions and 89 deletions

View file

@ -79,6 +79,7 @@ typedef struct _GstNvAV1DecClass
{ {
GstAV1DecoderClass parent_class; GstAV1DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
gint64 adapter_luid;
guint max_width; guint max_width;
guint max_height; guint max_height;
} GstNvAV1DecClass; } GstNvAV1DecClass;
@ -262,6 +263,7 @@ gst_nv_av1_dec_class_init (GstNvAV1DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_av1_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_av1_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->adapter_luid = cdata->adapter_luid;
klass->max_width = cdata->max_width; klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height; klass->max_height = cdata->max_height;
@ -275,7 +277,8 @@ gst_nv_av1_dec_init (GstNvAV1Dec * self)
{ {
GstNvAV1DecClass *klass = GST_NV_AV1_DEC_GET_CLASS (self); GstNvAV1DecClass *klass = GST_NV_AV1_DEC_GET_CLASS (self);
self->decoder = gst_nv_decoder_new (klass->cuda_device_id); self->decoder =
gst_nv_decoder_new (klass->cuda_device_id, klass->adapter_luid);
self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES; self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES;
self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY;
@ -1015,8 +1018,8 @@ gst_nv_av1_dec_get_preferred_output_delay (GstAV1Decoder * decoder,
} }
void void
gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, guint rank, gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id,
GstCaps * sink_caps, GstCaps * src_caps) gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps)
{ {
GType type; GType type;
gchar *type_name; gchar *type_name;
@ -1051,6 +1054,7 @@ gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, guint rank,
cdata->sink_caps = gst_caps_ref (sink_caps); cdata->sink_caps = gst_caps_ref (sink_caps);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;
cdata->adapter_luid = adapter_luid;
type_info.class_data = cdata; type_info.class_data = cdata;

View file

@ -26,6 +26,7 @@ G_BEGIN_DECLS
void gst_nv_av1_dec_register (GstPlugin * plugin, void gst_nv_av1_dec_register (GstPlugin * plugin,
guint device_id, guint device_id,
gint64 adapter_luid,
guint rank, guint rank,
GstCaps * sink_caps, GstCaps * sink_caps,
GstCaps * src_caps); GstCaps * src_caps);

View file

@ -50,10 +50,14 @@
#include <gst/gl/gstglfuncs.h> #include <gst/gl/gstglfuncs.h>
#endif #endif
#include <gst/cuda/gstcudamemory.h> #ifdef G_OS_WIN32
#include <gst/cuda/gstcudabufferpool.h> #include <gst/d3d11/gstd3d11.h>
#include <gst/cuda/gstcudastream.h> #endif
#include <gst/cuda/gstcuda.h>
#include <gst/cuda/gstcuda-private.h>
#include "gstnvdecoder.h" #include "gstnvdecoder.h"
#include "gstcudaconverter.h"
#include <string.h> #include <string.h>
#include <string> #include <string>
#include <set> #include <set>
@ -71,10 +75,11 @@ extern "C"
typedef enum typedef enum
{ {
GST_NV_DECODER_OUTPUT_TYPE_SYSTEM = 0, GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN = 0,
GST_NV_DECODER_OUTPUT_TYPE_GL, GST_NV_DECODER_OUTPUT_TYPE_SYSTEM = (1 << 0),
GST_NV_DECODER_OUTPUT_TYPE_CUDA, GST_NV_DECODER_OUTPUT_TYPE_GL = (1 << 1),
/* FIXME: add support D3D11 memory */ GST_NV_DECODER_OUTPUT_TYPE_CUDA = (1 << 2),
GST_NV_DECODER_OUTPUT_TYPE_D3D11 = (1 << 3),
} GstNvDecoderOutputType; } GstNvDecoderOutputType;
struct _GstNvDecoder struct _GstNvDecoder
@ -82,6 +87,7 @@ struct _GstNvDecoder
GstObject parent; GstObject parent;
guint device_id; guint device_id;
gint64 adapter_luid;
GstNvDecObject *object; GstNvDecObject *object;
GstCudaContext *context; GstCudaContext *context;
@ -104,6 +110,13 @@ struct _GstNvDecoder
GstObject *gl_context; GstObject *gl_context;
GstObject *other_gl_context; GstObject *other_gl_context;
/* D3D11 interop */
GstObject *d3d11_device;
GstCudaConverter *converter;
GstBuffer *export_buf;
GstBuffer *convert_buf;
GstVideoInfo output_info;
GstNvDecoderOutputType output_type; GstNvDecoderOutputType output_type;
}; };
@ -155,7 +168,6 @@ chroma_format_from_video_format (GstVideoFormat format)
case GST_VIDEO_FORMAT_NV12: case GST_VIDEO_FORMAT_NV12:
case GST_VIDEO_FORMAT_P010_10LE: case GST_VIDEO_FORMAT_P010_10LE:
case GST_VIDEO_FORMAT_P012_LE: case GST_VIDEO_FORMAT_P012_LE:
case GST_VIDEO_FORMAT_P016_LE:
return cudaVideoChromaFormat_420; return cudaVideoChromaFormat_420;
case GST_VIDEO_FORMAT_Y444: case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y444_16LE: case GST_VIDEO_FORMAT_Y444_16LE:
@ -178,7 +190,6 @@ output_format_from_video_format (GstVideoFormat format)
return cudaVideoSurfaceFormat_NV12; return cudaVideoSurfaceFormat_NV12;
case GST_VIDEO_FORMAT_P010_10LE: case GST_VIDEO_FORMAT_P010_10LE:
case GST_VIDEO_FORMAT_P012_LE: case GST_VIDEO_FORMAT_P012_LE:
case GST_VIDEO_FORMAT_P016_LE:
return cudaVideoSurfaceFormat_P016; return cudaVideoSurfaceFormat_P016;
case GST_VIDEO_FORMAT_Y444: case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_GBR: case GST_VIDEO_FORMAT_GBR:
@ -195,12 +206,13 @@ output_format_from_video_format (GstVideoFormat format)
} }
GstNvDecoder * GstNvDecoder *
gst_nv_decoder_new (guint device_id) gst_nv_decoder_new (guint device_id, gint64 adapter_luid)
{ {
GstNvDecoder *self; GstNvDecoder *self;
self = (GstNvDecoder *) g_object_new (GST_TYPE_NV_DECODER, nullptr); self = (GstNvDecoder *) g_object_new (GST_TYPE_NV_DECODER, nullptr);
self->device_id = device_id; self->device_id = device_id;
self->adapter_luid = adapter_luid;
gst_object_ref_sink (self); gst_object_ref_sink (self);
return self; return self;
@ -229,7 +241,7 @@ gst_nv_decoder_reset_unlocked (GstNvDecoder * self)
gst_clear_object (&self->object); gst_clear_object (&self->object);
self->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM; self->output_type = GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN;
self->configured = FALSE; self->configured = FALSE;
self->downstream_min_buffers = 0; self->downstream_min_buffers = 0;
self->num_output_surfaces = 0; self->num_output_surfaces = 0;
@ -246,6 +258,11 @@ gst_nv_decoder_close (GstNvDecoder * decoder)
gst_clear_object (&decoder->gl_context); gst_clear_object (&decoder->gl_context);
gst_clear_object (&decoder->other_gl_context); gst_clear_object (&decoder->other_gl_context);
gst_clear_object (&decoder->d3d11_device);
gst_clear_object (&decoder->converter);
gst_clear_buffer (&decoder->convert_buf);
gst_clear_buffer (&decoder->export_buf);
return TRUE; return TRUE;
} }
@ -275,6 +292,10 @@ gst_nv_decoder_configure (GstNvDecoder * decoder, cudaVideoCodec codec,
g_return_val_if_fail (coded_bitdepth >= 8, FALSE); g_return_val_if_fail (coded_bitdepth >= 8, FALSE);
g_return_val_if_fail (pool_size > 0, FALSE); g_return_val_if_fail (pool_size > 0, FALSE);
gst_clear_buffer (&decoder->export_buf);
gst_clear_buffer (&decoder->convert_buf);
gst_clear_object (&decoder->converter);
format = GST_VIDEO_INFO_FORMAT (info); format = GST_VIDEO_INFO_FORMAT (info);
if (decoder->info.finfo) if (decoder->info.finfo)
prev_format = GST_VIDEO_INFO_FORMAT (&decoder->info); prev_format = GST_VIDEO_INFO_FORMAT (&decoder->info);
@ -613,7 +634,7 @@ unmap_video_frame:
GST_WARNING_OBJECT (self, "Failed to pop CUDA context"); GST_WARNING_OBJECT (self, "Failed to pop CUDA context");
} }
static gboolean static GstFlowReturn
gst_nv_decoder_copy_frame_to_gl (GstNvDecoder * decoder, gst_nv_decoder_copy_frame_to_gl (GstNvDecoder * decoder,
GstGLContext * context, GstNvDecSurface * surface, GstBuffer * buffer) GstGLContext * context, GstNvDecSurface * surface, GstBuffer * buffer)
{ {
@ -628,23 +649,100 @@ gst_nv_decoder_copy_frame_to_gl (GstNvDecoder * decoder,
GST_LOG_OBJECT (decoder, "Copy frame to GL ret %d", data.ret); GST_LOG_OBJECT (decoder, "Copy frame to GL ret %d", data.ret);
return data.ret; if (!data.ret)
return GST_FLOW_ERROR;
return GST_FLOW_OK;
} }
#endif #endif
static gboolean #ifdef G_OS_WIN32
static GstFlowReturn
gst_nv_decoder_copy_frame_to_d3d11 (GstNvDecoder * self,
GstNvDecSurface * surface, GstBuffer * buffer)
{
GstFlowReturn ret;
GstMemory *mem;
GstCudaMemory *cmem;
GstVideoFrame src_frame, dst_frame;
gboolean convert_ret;
if (!self->converter || !self->convert_buf) {
GST_ERROR_OBJECT (self, "D3D11 output is not configured");
return GST_FLOW_ERROR;
}
ret = gst_nv_dec_object_export_surface (self->object,
surface, self->stream, &mem);
if (ret != GST_FLOW_OK) {
GST_WARNING_OBJECT (self, "Couldn't export surface");
gst_nv_dec_object_unmap_surface (self->object, surface);
return ret;
}
cmem = GST_CUDA_MEMORY_CAST (mem);
/* TODO: convert without buffer wrapping */
if (!self->export_buf) {
self->export_buf = gst_buffer_new ();
gst_buffer_add_video_meta_full (self->export_buf, GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (&self->info),
GST_VIDEO_INFO_WIDTH (&self->info),
GST_VIDEO_INFO_HEIGHT (&self->info),
GST_VIDEO_INFO_N_PLANES (&self->info),
cmem->info.offset, cmem->info.stride);
}
gst_buffer_append_memory (self->export_buf, mem);
if (!gst_video_frame_map (&src_frame, &self->info, self->export_buf,
(GstMapFlags) (GST_MAP_READ | GST_MAP_CUDA))) {
GST_ERROR_OBJECT (self, "Couldn't map exported buffer");
gst_buffer_remove_all_memory (self->export_buf);
return GST_FLOW_ERROR;
}
if (!gst_video_frame_map (&dst_frame, &self->output_info, self->convert_buf,
(GstMapFlags) (GST_MAP_WRITE | GST_MAP_CUDA))) {
GST_ERROR_OBJECT (self, "Couldn't map converter output buffer");
gst_buffer_remove_all_memory (self->export_buf);
return GST_FLOW_ERROR;
}
convert_ret = gst_cuda_converter_convert_frame (self->converter, &src_frame,
&dst_frame, gst_cuda_stream_get_handle (self->stream), nullptr);
gst_video_frame_unmap (&dst_frame);
gst_video_frame_unmap (&src_frame);
gst_buffer_remove_all_memory (self->export_buf);
if (!convert_ret) {
GST_ERROR_OBJECT (self, "Couldn't convert frame");
return GST_FLOW_ERROR;
}
if (!gst_cuda_buffer_copy (buffer, GST_CUDA_BUFFER_COPY_D3D11,
&self->output_info, self->convert_buf, GST_CUDA_BUFFER_COPY_CUDA,
&self->output_info, self->context, self->stream)) {
GST_ERROR_OBJECT (self, "Couldn't copy buffer to d3d11 output");
return GST_FLOW_ERROR;
}
return GST_FLOW_OK;
}
#endif
static GstFlowReturn
gst_nv_decoder_copy_frame_to_system (GstNvDecoder * decoder, gst_nv_decoder_copy_frame_to_system (GstNvDecoder * decoder,
GstNvDecSurface * surface, GstBuffer * buffer) GstNvDecSurface * surface, GstBuffer * buffer)
{ {
GstVideoFrame video_frame; GstVideoFrame video_frame;
CUDA_MEMCPY2D copy_params = { 0, }; CUDA_MEMCPY2D copy_params = { 0, };
gboolean ret = FALSE; GstFlowReturn ret = GST_FLOW_ERROR;
CUstream stream = gst_cuda_stream_get_handle (decoder->stream); CUstream stream = gst_cuda_stream_get_handle (decoder->stream);
if (!gst_video_frame_map (&video_frame, &decoder->info, buffer, if (!gst_video_frame_map (&video_frame, &decoder->info, buffer,
GST_MAP_WRITE)) { GST_MAP_WRITE)) {
GST_ERROR_OBJECT (decoder, "Couldn't map video frame"); GST_ERROR_OBJECT (decoder, "Couldn't map video frame");
return FALSE; return GST_FLOW_ERROR;
} }
copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE; copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
@ -667,38 +765,35 @@ gst_nv_decoder_copy_frame_to_system (GstNvDecoder * decoder,
} }
gst_cuda_result (CuStreamSynchronize (stream)); gst_cuda_result (CuStreamSynchronize (stream));
ret = GST_FLOW_OK;
ret = TRUE;
done: done:
gst_video_frame_unmap (&video_frame); gst_video_frame_unmap (&video_frame);
GST_LOG_OBJECT (decoder, "Copy frame to system ret %d", ret);
return ret; return ret;
} }
static gboolean static GstFlowReturn
gst_nv_decoder_copy_frame_to_cuda (GstNvDecoder * decoder, gst_nv_decoder_copy_frame_to_cuda (GstNvDecoder * decoder,
GstNvDecSurface * surface, GstBuffer * buffer, GstCudaStream * stream) GstNvDecSurface * surface, GstBuffer * buffer, GstCudaStream * stream)
{ {
CUDA_MEMCPY2D copy_params = { 0, }; CUDA_MEMCPY2D copy_params = { 0, };
GstMemory *mem; GstMemory *mem;
gboolean ret = FALSE;
GstVideoFrame video_frame; GstVideoFrame video_frame;
CUstream stream_handle = gst_cuda_stream_get_handle (stream); CUstream stream_handle = gst_cuda_stream_get_handle (stream);
GstFlowReturn ret = GST_FLOW_ERROR;
mem = gst_buffer_peek_memory (buffer, 0); mem = gst_buffer_peek_memory (buffer, 0);
if (!gst_is_cuda_memory (mem)) { if (!gst_is_cuda_memory (mem)) {
GST_WARNING_OBJECT (decoder, "Not a CUDA memory"); GST_WARNING_OBJECT (decoder, "Not a CUDA memory");
return FALSE; return GST_FLOW_ERROR;
} }
if (!gst_video_frame_map (&video_frame, if (!gst_video_frame_map (&video_frame,
&decoder->info, buffer, &decoder->info, buffer,
(GstMapFlags) (GST_MAP_WRITE | GST_MAP_CUDA))) { (GstMapFlags) (GST_MAP_WRITE | GST_MAP_CUDA))) {
GST_ERROR_OBJECT (decoder, "frame map failure"); GST_ERROR_OBJECT (decoder, "frame map failure");
return FALSE; return GST_FLOW_ERROR;
} }
copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE; copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE;
@ -727,13 +822,11 @@ gst_nv_decoder_copy_frame_to_cuda (GstNvDecoder * decoder,
else else
GST_MINI_OBJECT_FLAG_SET (mem, GST_CUDA_MEMORY_TRANSFER_NEED_SYNC); GST_MINI_OBJECT_FLAG_SET (mem, GST_CUDA_MEMORY_TRANSFER_NEED_SYNC);
ret = TRUE; ret = GST_FLOW_OK;
done: done:
gst_video_frame_unmap (&video_frame); gst_video_frame_unmap (&video_frame);
GST_LOG_OBJECT (decoder, "Copy frame to CUDA ret %d", ret);
return ret; return ret;
} }
@ -748,11 +841,20 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
gboolean can_export = FALSE; gboolean can_export = FALSE;
if (picture->discont_state) { if (picture->discont_state) {
GST_DEBUG_OBJECT (videodec, "Negotiate again on input state change");
if (!gst_nv_decoder_negotiate (decoder, videodec, picture->discont_state)) { if (!gst_nv_decoder_negotiate (decoder, videodec, picture->discont_state)) {
GST_ERROR_OBJECT (videodec, "Couldn't re-negotiate with updated state"); GST_ERROR_OBJECT (videodec, "Couldn't re-negotiate with updated state");
ret = GST_FLOW_NOT_NEGOTIATED; ret = GST_FLOW_NOT_NEGOTIATED;
goto error; goto error;
} }
} else if (gst_pad_check_reconfigure (videodec->srcpad)) {
GST_DEBUG_OBJECT (videodec, "Negotiate again on reconfigure");
if (!gst_video_decoder_negotiate (videodec)) {
GST_ERROR_OBJECT (videodec,
"Couldn't re-negotiate on downstram reconfigure");
ret = GST_FLOW_NOT_NEGOTIATED;
goto error;
}
} }
surface = (GstNvDecSurface *) gst_codec_picture_get_user_data (picture); surface = (GstNvDecSurface *) gst_codec_picture_get_user_data (picture);
@ -827,7 +929,7 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
frame->output_buffer = buf; frame->output_buffer = buf;
} else { } else {
gboolean copy_ret = FALSE; gboolean need_unmap = TRUE;
frame->output_buffer = gst_video_decoder_allocate_output_buffer (videodec); frame->output_buffer = gst_video_decoder_allocate_output_buffer (videodec);
if (!frame->output_buffer) { if (!frame->output_buffer) {
@ -839,21 +941,29 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
} }
switch (decoder->output_type) { switch (decoder->output_type) {
case GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN:
case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM: case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM:
copy_ret = gst_nv_decoder_copy_frame_to_system (decoder, ret = gst_nv_decoder_copy_frame_to_system (decoder,
surface, frame->output_buffer); surface, frame->output_buffer);
break; break;
#ifdef G_OS_WIN32
case GST_NV_DECODER_OUTPUT_TYPE_D3D11:
ret = gst_nv_decoder_copy_frame_to_d3d11 (decoder, surface,
frame->output_buffer);
need_unmap = FALSE;
break;
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
case GST_NV_DECODER_OUTPUT_TYPE_GL: case GST_NV_DECODER_OUTPUT_TYPE_GL:
g_assert (decoder->gl_context != nullptr); g_assert (decoder->gl_context != nullptr);
copy_ret = gst_nv_decoder_copy_frame_to_gl (decoder, ret = gst_nv_decoder_copy_frame_to_gl (decoder,
GST_GL_CONTEXT (decoder->gl_context), surface, GST_GL_CONTEXT (decoder->gl_context), surface,
frame->output_buffer); frame->output_buffer);
break; break;
#endif #endif
case GST_NV_DECODER_OUTPUT_TYPE_CUDA: case GST_NV_DECODER_OUTPUT_TYPE_CUDA:
copy_ret = gst_nv_decoder_copy_frame_to_cuda (decoder, ret = gst_nv_decoder_copy_frame_to_cuda (decoder,
surface, frame->output_buffer, stream); surface, frame->output_buffer, stream);
break; break;
default: default:
@ -868,19 +978,21 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder,
* belongs to non-nvidia (or different device). * belongs to non-nvidia (or different device).
* There should be enhancement to ensure nvdec has compatible OpenGL context * There should be enhancement to ensure nvdec has compatible OpenGL context
*/ */
if (!copy_ret && decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL) { if (ret != GST_FLOW_OK &&
decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL) {
GST_WARNING_OBJECT (videodec, GST_WARNING_OBJECT (videodec,
"Couldn't copy frame to GL memory, fallback to system memory"); "Couldn't copy frame to GL memory, fallback to system memory");
decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM; decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
copy_ret = gst_nv_decoder_copy_frame_to_system (decoder, surface, ret = gst_nv_decoder_copy_frame_to_system (decoder, surface,
frame->output_buffer); frame->output_buffer);
} }
gst_nv_dec_object_unmap_surface (decoder->object, surface); if (need_unmap)
gst_nv_dec_object_unmap_surface (decoder->object, surface);
gst_cuda_context_pop (nullptr); gst_cuda_context_pop (nullptr);
if (!copy_ret) { if (ret != GST_FLOW_OK) {
GST_WARNING_OBJECT (videodec, "Failed to copy frame"); GST_WARNING_OBJECT (videodec, "Failed to copy frame");
goto error; goto error;
} }
@ -1100,6 +1212,22 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec,
guint i; guint i;
gboolean ret = FALSE; gboolean ret = FALSE;
std::set < std::string > formats; std::set < std::string > formats;
std::set < std::string > planar_formats;
#ifdef G_OS_WIN32
gboolean is_stateless = FALSE;
switch (codec) {
case cudaVideoCodec_H264:
case cudaVideoCodec_HEVC:
case cudaVideoCodec_VP8:
case cudaVideoCodec_VP9:
case cudaVideoCodec_AV1:
is_stateless = TRUE;
break;
default:
break;
}
#endif
for (i = 0; i < G_N_ELEMENTS (codec_map_list); i++) { for (i = 0; i < G_N_ELEMENTS (codec_map_list); i++) {
if (codec_map_list[i].codec == codec) { if (codec_map_list[i].codec == codec) {
@ -1123,6 +1251,17 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec,
gst_caps_set_features_simple (cuda_caps, gst_caps_set_features_simple (cuda_caps,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)); gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY));
#ifdef G_OS_WIN32
if (is_stateless) {
GstCaps *d3d11_caps =
gst_caps_from_string (GST_VIDEO_CAPS_MAKE ("I420"));
gst_caps_set_features_simple (d3d11_caps,
gst_caps_features_from_string
(GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY));
gst_caps_append (src_templ, d3d11_caps);
}
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
{ {
GstCaps *gl_caps = gst_caps_copy (src_templ); GstCaps *gl_caps = gst_caps_copy (src_templ);
@ -1195,10 +1334,13 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec,
case cudaVideoChromaFormat_420: case cudaVideoChromaFormat_420:
if (bitdepth_minus8[b_idx] == 0) { if (bitdepth_minus8[b_idx] == 0) {
formats.insert ("NV12"); formats.insert ("NV12");
planar_formats.insert ("I420");
} else if (bitdepth_minus8[b_idx] == 2) { } else if (bitdepth_minus8[b_idx] == 2) {
formats.insert ("P010_10LE"); formats.insert ("P010_10LE");
planar_formats.insert ("I420_10LE");
} else if (bitdepth_minus8[b_idx] == 4) { } else if (bitdepth_minus8[b_idx] == 4) {
formats.insert ("P012_LE"); formats.insert ("P012_LE");
planar_formats.insert ("I420_12LE");
} else { } else {
GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8); GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8);
break; break;
@ -1213,12 +1355,18 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec,
if (bitdepth_minus8[b_idx] == 0) { if (bitdepth_minus8[b_idx] == 0) {
formats.insert ("Y444"); formats.insert ("Y444");
if (codec == cudaVideoCodec_HEVC) planar_formats.insert ("Y444");
if (codec == cudaVideoCodec_HEVC) {
formats.insert ("GBR"); formats.insert ("GBR");
planar_formats.insert ("GBR");
}
} else if (bitdepth_minus8[b_idx] == 2 || bitdepth_minus8[b_idx] == 4) { } else if (bitdepth_minus8[b_idx] == 2 || bitdepth_minus8[b_idx] == 4) {
formats.insert ("Y444_16LE"); formats.insert ("Y444_16LE");
if (codec == cudaVideoCodec_HEVC) planar_formats.insert ("Y444_16LE");
if (codec == cudaVideoCodec_HEVC) {
formats.insert ("GBR_16LE"); formats.insert ("GBR_16LE");
planar_formats.insert ("GBR_16LE");
}
} else { } else {
GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8); GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8);
break; break;
@ -1268,6 +1416,33 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec,
gst_caps_set_features_simple (src_templ, gst_caps_set_features_simple (src_templ,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)); gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY));
#ifdef G_OS_WIN32
if (is_stateless) {
format_str.clear ();
if (planar_formats.size () == 1) {
format_str += *(planar_formats.begin ());
} else {
bool first = true;
format_str += "{ ";
APPEND_STRING (format_str, planar_formats, "I420");
APPEND_STRING (format_str, planar_formats, "I420_10LE");
APPEND_STRING (format_str, planar_formats, "I420_12LE");
APPEND_STRING (format_str, planar_formats, "Y444");
APPEND_STRING (format_str, planar_formats, "Y444_16LE");
APPEND_STRING (format_str, planar_formats, "GBR");
APPEND_STRING (format_str, planar_formats, "GBR_16LE");
format_str += " }";
}
src_caps_string = "video/x-raw, format = (string) " + format_str;
GstCaps *d3d11_caps = gst_caps_from_string (src_caps_string.c_str ());
gst_caps_set_features_simple (d3d11_caps,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY));
gst_caps_append (src_templ, d3d11_caps);
}
#endif
/* OpenGL specific */ /* OpenGL specific */
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
format_str.clear (); format_str.clear ();
@ -1355,6 +1530,13 @@ gst_nv_decoder_handle_set_context (GstNvDecoder * decoder,
&decoder->context)) { &decoder->context)) {
return; return;
} }
#ifdef G_OS_WIN32
if (gst_d3d11_handle_set_context_for_adapter_luid (element, context,
decoder->adapter_luid, (GstD3D11Device **) & decoder->d3d11_device)) {
return;
}
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
gst_gl_handle_set_context (element, context, gst_gl_handle_set_context (element, context,
(GstGLDisplay **) & decoder->gl_display, (GstGLDisplay **) & decoder->gl_display,
@ -1372,6 +1554,13 @@ gst_nv_decoder_handle_query (GstNvDecoder * decoder, GstElement * element,
if (gst_cuda_handle_context_query (element, query, decoder->context)) if (gst_cuda_handle_context_query (element, query, decoder->context))
return TRUE; return TRUE;
#ifdef G_OS_WIN32
if (gst_d3d11_handle_context_query (element,
query, (GstD3D11Device *) decoder->d3d11_device)) {
return TRUE;
}
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
if (gst_gl_handle_context_query (element, query, if (gst_gl_handle_context_query (element, query,
(GstGLDisplay *) decoder->gl_display, (GstGLDisplay *) decoder->gl_display,
@ -1475,12 +1664,89 @@ gst_nv_decoder_ensure_gl_context (GstNvDecoder * decoder, GstElement * videodec)
} }
#endif #endif
#ifdef G_OS_WIN32
static gboolean
gst_nv_decoder_ensure_d3d11_output (GstNvDecoder * self, GstElement * element)
{
GstVideoFormat out_format = GST_VIDEO_FORMAT_UNKNOWN;
GstVideoFormat decoder_format;
if (!gst_d3d11_ensure_element_data_for_adapter_luid (GST_ELEMENT (element),
self->adapter_luid, (GstD3D11Device **) & self->d3d11_device)) {
GST_WARNING_OBJECT (element, "D3D11 device is not available");
return FALSE;
}
decoder_format = GST_VIDEO_INFO_FORMAT (&self->info);
switch (decoder_format) {
case GST_VIDEO_FORMAT_NV12:
out_format = GST_VIDEO_FORMAT_I420;
break;
case GST_VIDEO_FORMAT_P010_10LE:
out_format = GST_VIDEO_FORMAT_I420_10LE;
break;
case GST_VIDEO_FORMAT_P012_LE:
out_format = GST_VIDEO_FORMAT_I420_12LE;
break;
case GST_VIDEO_FORMAT_Y444:
case GST_VIDEO_FORMAT_Y444_16LE:
case GST_VIDEO_FORMAT_GBR:
case GST_VIDEO_FORMAT_GBR_16LE:
out_format = GST_VIDEO_INFO_FORMAT (&self->info);
break;
default:
GST_WARNING_OBJECT (element,
"Unexpected format %s", gst_video_format_to_string (decoder_format));
return FALSE;
}
gst_video_info_set_interlaced_format (&self->output_info, out_format,
GST_VIDEO_INFO_INTERLACE_MODE (&self->info), self->info.width,
self->info.height);
if (!self->converter) {
self->converter = gst_cuda_converter_new (&self->info, &self->output_info,
self->context, nullptr);
if (!self->converter) {
GST_WARNING_OBJECT (element, "Couldn't create converter");
return FALSE;
}
}
if (!self->convert_buf) {
GstMemory *mem = gst_cuda_allocator_alloc (nullptr, self->context,
self->stream, &self->output_info);
GstCudaMemory *cmem;
if (!mem) {
GST_WARNING_OBJECT (element, "Couldn't allocate memory for conversion");
return FALSE;
}
cmem = GST_CUDA_MEMORY_CAST (mem);
self->convert_buf = gst_buffer_new ();
gst_buffer_append_memory (self->convert_buf, mem);
gst_buffer_add_video_meta_full (self->convert_buf,
GST_VIDEO_FRAME_FLAG_NONE,
GST_VIDEO_INFO_FORMAT (&self->output_info),
GST_VIDEO_INFO_WIDTH (&self->output_info),
GST_VIDEO_INFO_HEIGHT (&self->output_info),
GST_VIDEO_INFO_N_PLANES (&self->output_info),
cmem->info.offset, cmem->info.stride);
}
return TRUE;
}
#endif
gboolean gboolean
gst_nv_decoder_negotiate (GstNvDecoder * decoder, gst_nv_decoder_negotiate (GstNvDecoder * decoder,
GstVideoDecoder * videodec, GstVideoCodecState * input_state) GstVideoDecoder * videodec, GstVideoCodecState * input_state)
{ {
GstVideoCodecState *state; GstVideoCodecState *state;
GstVideoInfo *info; guint prev_output_type, available_types, selected_type;
g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE); g_return_val_if_fail (GST_IS_NV_DECODER (decoder), FALSE);
g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE); g_return_val_if_fail (GST_IS_VIDEO_DECODER (videodec), FALSE);
@ -1491,16 +1757,9 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder,
return FALSE; return FALSE;
} }
info = &decoder->info; decoder->output_info = decoder->info;
state = gst_video_decoder_set_interlaced_output_state (videodec, prev_output_type = decoder->output_type;
GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info), available_types = selected_type = 0;
GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), input_state);
state->caps = gst_video_info_to_caps (&state->info);
/* decoder baseclass will hold other reference to output state */
gst_video_codec_state_unref (state);
decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
{ {
GstCaps *caps; GstCaps *caps;
@ -1514,37 +1773,66 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder,
GstCapsFeatures *features; GstCapsFeatures *features;
guint size = gst_caps_get_size (caps); guint size = gst_caps_get_size (caps);
guint i; guint i;
gboolean have_cuda = FALSE;
gboolean have_gl = FALSE;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
features = gst_caps_get_features (caps, i); features = gst_caps_get_features (caps, i);
if (features && gst_caps_features_contains (features, if (features && gst_caps_features_contains (features,
GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) { GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) {
GST_DEBUG_OBJECT (videodec, "found CUDA memory feature"); GST_DEBUG_OBJECT (videodec, "found CUDA memory feature");
have_cuda = TRUE; available_types |= GST_NV_DECODER_OUTPUT_TYPE_CUDA;
break;
} }
#ifdef G_OS_WIN32
if (features && gst_caps_features_contains (features,
GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)) {
GST_DEBUG_OBJECT (videodec, "found D3D11 memory feature");
available_types |= GST_NV_DECODER_OUTPUT_TYPE_D3D11;
}
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
/* TODO: gl does not support Y444_16 and GBR_16 */ /* TODO: gl does not support Y444_16 and GBR_16 */
if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_Y444_16LE && if (GST_VIDEO_INFO_FORMAT (&decoder->info) !=
GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_GBR_16LE && GST_VIDEO_FORMAT_Y444_16LE &&
GST_VIDEO_INFO_FORMAT (&decoder->info) !=
GST_VIDEO_FORMAT_GBR_16LE &&
features && gst_caps_features_contains (features, features && gst_caps_features_contains (features,
GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) { GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) {
GST_DEBUG_OBJECT (videodec, "found GL memory feature"); GST_DEBUG_OBJECT (videodec, "found GL memory feature");
have_gl = TRUE; available_types |= GST_NV_DECODER_OUTPUT_TYPE_GL;
} }
#endif #endif
} }
if (have_cuda) if (prev_output_type != GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN &&
decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_CUDA; (prev_output_type & available_types) == prev_output_type) {
else if (have_gl) selected_type = prev_output_type;
decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_GL; }
if (selected_type == GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN) {
if ((available_types & GST_NV_DECODER_OUTPUT_TYPE_CUDA) != 0)
selected_type = GST_NV_DECODER_OUTPUT_TYPE_CUDA;
else if ((available_types & GST_NV_DECODER_OUTPUT_TYPE_D3D11) != 0)
selected_type = GST_NV_DECODER_OUTPUT_TYPE_D3D11;
else if ((available_types & GST_NV_DECODER_OUTPUT_TYPE_GL) != 0)
selected_type = GST_NV_DECODER_OUTPUT_TYPE_GL;
else
selected_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
}
decoder->output_type = (GstNvDecoderOutputType) selected_type;
GST_DEBUG_OBJECT (videodec, "Selected type %d", selected_type);
} }
gst_clear_caps (&caps); gst_clear_caps (&caps);
} }
#ifdef G_OS_WIN32
if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_D3D11 &&
!gst_nv_decoder_ensure_d3d11_output (decoder, GST_ELEMENT (videodec))) {
GST_WARNING_OBJECT (videodec, "D3D11 setup failed");
decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_SYSTEM;
decoder->output_info = decoder->info;
}
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL && if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL &&
!gst_nv_decoder_ensure_gl_context (decoder, GST_ELEMENT (videodec))) { !gst_nv_decoder_ensure_gl_context (decoder, GST_ELEMENT (videodec))) {
@ -1554,17 +1842,30 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder,
} }
#endif #endif
state = gst_video_decoder_set_interlaced_output_state (videodec,
GST_VIDEO_INFO_FORMAT (&decoder->output_info),
GST_VIDEO_INFO_INTERLACE_MODE (&decoder->output_info),
GST_VIDEO_INFO_WIDTH (&decoder->output_info),
GST_VIDEO_INFO_HEIGHT (&decoder->output_info), input_state);
state->caps = gst_video_info_to_caps (&state->info);
switch (decoder->output_type) { switch (decoder->output_type) {
case GST_NV_DECODER_OUTPUT_TYPE_CUDA: case GST_NV_DECODER_OUTPUT_TYPE_CUDA:
GST_DEBUG_OBJECT (videodec, "using CUDA memory"); GST_DEBUG_OBJECT (videodec, "using CUDA memory");
gst_caps_set_features (state->caps, 0, gst_caps_set_features (state->caps, 0,
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY, nullptr)); gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY));
break; break;
#ifdef G_OS_WIN32
case GST_NV_DECODER_OUTPUT_TYPE_D3D11:
gst_caps_set_features (state->caps, 0,
gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY));
break;
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
case GST_NV_DECODER_OUTPUT_TYPE_GL: case GST_NV_DECODER_OUTPUT_TYPE_GL:
GST_DEBUG_OBJECT (videodec, "using GL memory"); GST_DEBUG_OBJECT (videodec, "using GL memory");
gst_caps_set_features (state->caps, 0, gst_caps_set_features (state->caps, 0,
gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_GL_MEMORY, nullptr)); gst_caps_features_new_single (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
gst_caps_set_simple (state->caps, "texture-target", G_TYPE_STRING, gst_caps_set_simple (state->caps, "texture-target", G_TYPE_STRING,
"2D", nullptr); "2D", nullptr);
break; break;
@ -1574,6 +1875,9 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder,
break; break;
} }
/* decoder baseclass will hold other reference to output state */
gst_video_codec_state_unref (state);
return TRUE; return TRUE;
} }
@ -1699,6 +2003,90 @@ gst_nv_decoder_ensure_gl_pool (GstNvDecoder * decoder, GstQuery * query)
} }
#endif #endif
#ifdef G_OS_WIN32
static gboolean
gst_nv_decoder_ensure_d3d11_pool (GstNvDecoder * self, GstElement * element,
GstQuery * query)
{
GstCaps *outcaps;
GstBufferPool *pool = NULL;
guint n, size, min = 0, max = 0;
GstVideoInfo info;
GstStructure *config;
GstD3D11AllocationParams *d3d11_params;
GstD3D11Device *device;
gst_query_parse_allocation (query, &outcaps, nullptr);
if (!outcaps) {
GST_DEBUG_OBJECT (element, "No output caps");
return FALSE;
}
if (!gst_d3d11_ensure_element_data_for_adapter_luid (element,
self->adapter_luid, (GstD3D11Device **) & self->d3d11_device)) {
GST_ERROR_OBJECT (element, "Couldn't create d3d11 device");
return FALSE;
}
device = GST_D3D11_DEVICE (self->d3d11_device);
gst_video_info_from_caps (&info, outcaps);
n = gst_query_get_n_allocation_pools (query);
if (n > 0)
gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
/* create our own pool */
if (pool) {
if (!GST_IS_D3D11_BUFFER_POOL (pool)) {
GST_DEBUG_OBJECT (self,
"Downstream pool is not d3d11, will create new one");
gst_clear_object (&pool);
} else {
GstD3D11BufferPool *dpool = GST_D3D11_BUFFER_POOL (pool);
if (dpool->device != device) {
GST_DEBUG_OBJECT (element, "Different device, will create new one");
gst_clear_object (&pool);
}
}
}
if (!pool) {
pool = gst_d3d11_buffer_pool_new (device);
size = info.size;
}
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_set_params (config, outcaps, size, min, max);
gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
d3d11_params = gst_buffer_pool_config_get_d3d11_allocation_params (config);
if (!d3d11_params) {
d3d11_params = gst_d3d11_allocation_params_new (device, &info,
GST_D3D11_ALLOCATION_FLAG_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0);
}
gst_buffer_pool_config_set_d3d11_allocation_params (config, d3d11_params);
gst_d3d11_allocation_params_free (d3d11_params);
gst_buffer_pool_set_config (pool, config);
/* d3d11 buffer pool will update buffer size based on allocated texture,
* get size from config again */
config = gst_buffer_pool_get_config (pool);
gst_buffer_pool_config_get_params (config, nullptr, &size, nullptr, nullptr);
gst_structure_free (config);
if (n > 0)
gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
else
gst_query_add_allocation_pool (query, pool, size, min, max);
gst_object_unref (pool);
return TRUE;
}
#endif
gboolean gboolean
gst_nv_decoder_decide_allocation (GstNvDecoder * decoder, gst_nv_decoder_decide_allocation (GstNvDecoder * decoder,
GstVideoDecoder * videodec, GstQuery * query) GstVideoDecoder * videodec, GstQuery * query)
@ -1708,9 +2096,16 @@ gst_nv_decoder_decide_allocation (GstNvDecoder * decoder,
GST_DEBUG_OBJECT (videodec, "decide allocation"); GST_DEBUG_OBJECT (videodec, "decide allocation");
switch (decoder->output_type) { switch (decoder->output_type) {
case GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN:
case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM: case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM:
/* GstVideoDecoder will take care this case */ /* GstVideoDecoder will take care this case */
break; break;
#ifdef G_OS_WIN32
case GST_NV_DECODER_OUTPUT_TYPE_D3D11:
ret = gst_nv_decoder_ensure_d3d11_pool (decoder, GST_ELEMENT (videodec),
query);
break;
#endif
#ifdef HAVE_CUDA_GST_GL #ifdef HAVE_CUDA_GST_GL
case GST_NV_DECODER_OUTPUT_TYPE_GL: case GST_NV_DECODER_OUTPUT_TYPE_GL:
ret = gst_nv_decoder_ensure_gl_pool (decoder, query); ret = gst_nv_decoder_ensure_gl_pool (decoder, query);

View file

@ -38,11 +38,13 @@ typedef struct _GstNvDecoderClassData
GstCaps *sink_caps; GstCaps *sink_caps;
GstCaps *src_caps; GstCaps *src_caps;
guint cuda_device_id; guint cuda_device_id;
gint64 adapter_luid;
guint max_width; guint max_width;
guint max_height; guint max_height;
} GstNvDecoderClassData; } GstNvDecoderClassData;
GstNvDecoder * gst_nv_decoder_new (guint device_id); GstNvDecoder * gst_nv_decoder_new (guint device_id,
gint64 adapter_luid);
gboolean gst_nv_decoder_open (GstNvDecoder * decoder, gboolean gst_nv_decoder_open (GstNvDecoder * decoder,
GstElement * element); GstElement * element);

View file

@ -135,6 +135,7 @@ typedef struct _GstNvH264DecClass
{ {
GstH264DecoderClass parent_class; GstH264DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
gint64 adapter_luid;
guint max_width; guint max_width;
guint max_height; guint max_height;
} GstNvH264DecClass; } GstNvH264DecClass;
@ -330,6 +331,7 @@ gst_nv_h264_dec_class_init (GstNvH264DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_h264_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_h264_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->adapter_luid = cdata->adapter_luid;
klass->max_width = cdata->max_width; klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height; klass->max_height = cdata->max_height;
@ -343,7 +345,8 @@ gst_nv_h264_dec_init (GstNvH264Dec * self)
{ {
GstNvH264DecClass *klass = GST_NV_H264_DEC_GET_CLASS (self); GstNvH264DecClass *klass = GST_NV_H264_DEC_GET_CLASS (self);
self->decoder = gst_nv_decoder_new (klass->cuda_device_id); self->decoder =
gst_nv_decoder_new (klass->cuda_device_id, klass->adapter_luid);
self->ref_list = g_array_sized_new (FALSE, TRUE, self->ref_list = g_array_sized_new (FALSE, TRUE,
sizeof (GstH264Picture *), 16); sizeof (GstH264Picture *), 16);
g_array_set_clear_func (self->ref_list, g_array_set_clear_func (self->ref_list,
@ -1044,8 +1047,8 @@ gst_nv_h264_dec_get_preferred_output_delay (GstH264Decoder * decoder,
} }
void void
gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, guint rank, gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id,
GstCaps * sink_caps, GstCaps * src_caps) gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps)
{ {
GType type; GType type;
gchar *type_name; gchar *type_name;
@ -1088,6 +1091,7 @@ gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, guint rank,
GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;
cdata->adapter_luid = adapter_luid;
type_name = g_strdup ("GstNvH264Dec"); type_name = g_strdup ("GstNvH264Dec");
feature_name = g_strdup ("nvh264dec"); feature_name = g_strdup ("nvh264dec");

View file

@ -27,6 +27,7 @@ G_BEGIN_DECLS
void gst_nv_h264_dec_register (GstPlugin * plugin, void gst_nv_h264_dec_register (GstPlugin * plugin,
guint device_id, guint device_id,
gint64 adapter_luid,
guint rank, guint rank,
GstCaps * sink_caps, GstCaps * sink_caps,
GstCaps * src_caps); GstCaps * src_caps);

View file

@ -134,6 +134,7 @@ typedef struct _GstNvH265DecClass
{ {
GstH265DecoderClass parent_class; GstH265DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
gint64 adapter_luid;
guint max_width; guint max_width;
guint max_height; guint max_height;
} GstNvH265DecClass; } GstNvH265DecClass;
@ -324,6 +325,7 @@ gst_nv_h265_dec_class_init (GstNvH265DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_h265_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_h265_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->adapter_luid = cdata->adapter_luid;
klass->max_width = cdata->max_width; klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height; klass->max_height = cdata->max_height;
@ -337,7 +339,8 @@ gst_nv_h265_dec_init (GstNvH265Dec * self)
{ {
GstNvH265DecClass *klass = GST_NV_H265_DEC_GET_CLASS (self); GstNvH265DecClass *klass = GST_NV_H265_DEC_GET_CLASS (self);
self->decoder = gst_nv_decoder_new (klass->cuda_device_id); self->decoder =
gst_nv_decoder_new (klass->cuda_device_id, klass->adapter_luid);
self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES; self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES;
self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY;
@ -1150,8 +1153,8 @@ gst_nv_h265_dec_get_preferred_output_delay (GstH265Decoder * decoder,
} }
void void
gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank, gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id,
GstCaps * sink_caps, GstCaps * src_caps) gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps)
{ {
GType type; GType type;
gchar *type_name; gchar *type_name;
@ -1207,6 +1210,7 @@ gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank,
GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;
cdata->adapter_luid = adapter_luid;
type_name = g_strdup ("GstNvH265Dec"); type_name = g_strdup ("GstNvH265Dec");
feature_name = g_strdup ("nvh265dec"); feature_name = g_strdup ("nvh265dec");

View file

@ -27,6 +27,7 @@ G_BEGIN_DECLS
void gst_nv_h265_dec_register (GstPlugin * plugin, void gst_nv_h265_dec_register (GstPlugin * plugin,
guint device_id, guint device_id,
gint64 adapter_luid,
guint rank, guint rank,
GstCaps * sink_caps, GstCaps * sink_caps,
GstCaps * src_caps); GstCaps * src_caps);

View file

@ -63,6 +63,7 @@ typedef struct _GstNvVp8DecClass
{ {
GstVp8DecoderClass parent_class; GstVp8DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
gint64 adapter_luid;
guint max_width; guint max_width;
guint max_height; guint max_height;
} GstNvVp8DecClass; } GstNvVp8DecClass;
@ -243,6 +244,7 @@ gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->adapter_luid = cdata->adapter_luid;
klass->max_width = cdata->max_width; klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height; klass->max_height = cdata->max_height;
@ -256,7 +258,8 @@ gst_nv_vp8_dec_init (GstNvVp8Dec * self)
{ {
GstNvVp8DecClass *klass = GST_NV_VP8_DEC_GET_CLASS (self); GstNvVp8DecClass *klass = GST_NV_VP8_DEC_GET_CLASS (self);
self->decoder = gst_nv_decoder_new (klass->cuda_device_id); self->decoder =
gst_nv_decoder_new (klass->cuda_device_id, klass->adapter_luid);
self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES; self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES;
self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY;
@ -629,8 +632,8 @@ gst_nv_vp8_dec_get_preferred_output_delay (GstVp8Decoder * decoder,
} }
void void
gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, guint rank, gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id,
GstCaps * sink_caps, GstCaps * src_caps) gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps)
{ {
GType type; GType type;
gchar *type_name; gchar *type_name;
@ -665,6 +668,7 @@ gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, guint rank,
cdata->sink_caps = gst_caps_ref (sink_caps); cdata->sink_caps = gst_caps_ref (sink_caps);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;
cdata->adapter_luid = adapter_luid;
type_name = g_strdup ("GstNvVp8Dec"); type_name = g_strdup ("GstNvVp8Dec");
feature_name = g_strdup ("nvvp8dec"); feature_name = g_strdup ("nvvp8dec");

View file

@ -27,6 +27,7 @@ G_BEGIN_DECLS
void gst_nv_vp8_dec_register (GstPlugin * plugin, void gst_nv_vp8_dec_register (GstPlugin * plugin,
guint device_id, guint device_id,
gint64 adapter_luid,
guint rank, guint rank,
GstCaps * sink_caps, GstCaps * sink_caps,
GstCaps * src_caps); GstCaps * src_caps);

View file

@ -64,6 +64,7 @@ typedef struct _GstNvVp9DecClass
{ {
GstVp9DecoderClass parent_class; GstVp9DecoderClass parent_class;
guint cuda_device_id; guint cuda_device_id;
gint64 adapter_luid;
guint max_width; guint max_width;
guint max_height; guint max_height;
} GstNvVp9DecClass; } GstNvVp9DecClass;
@ -248,6 +249,7 @@ gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass,
GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_get_preferred_output_delay); GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_get_preferred_output_delay);
klass->cuda_device_id = cdata->cuda_device_id; klass->cuda_device_id = cdata->cuda_device_id;
klass->adapter_luid = cdata->adapter_luid;
klass->max_width = cdata->max_width; klass->max_width = cdata->max_width;
klass->max_height = cdata->max_height; klass->max_height = cdata->max_height;
@ -261,7 +263,8 @@ gst_nv_vp9_dec_init (GstNvVp9Dec * self)
{ {
GstNvVp9DecClass *klass = GST_NV_VP9_DEC_GET_CLASS (self); GstNvVp9DecClass *klass = GST_NV_VP9_DEC_GET_CLASS (self);
self->decoder = gst_nv_decoder_new (klass->cuda_device_id); self->decoder =
gst_nv_decoder_new (klass->cuda_device_id, klass->adapter_luid);
self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES; self->num_output_surfaces = DEFAULT_NUM_OUTPUT_SURFACES;
self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; self->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY;
@ -725,8 +728,8 @@ gst_nv_vp9_dec_get_preferred_output_delay (GstVp9Decoder * decoder,
} }
void void
gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank, gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id,
GstCaps * sink_caps, GstCaps * src_caps) gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps)
{ {
GType type; GType type;
gchar *type_name; gchar *type_name;
@ -765,6 +768,7 @@ gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank,
GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);
cdata->src_caps = gst_caps_ref (src_caps); cdata->src_caps = gst_caps_ref (src_caps);
cdata->cuda_device_id = device_id; cdata->cuda_device_id = device_id;
cdata->adapter_luid = adapter_luid;
type_name = g_strdup ("GstNvVp9Dec"); type_name = g_strdup ("GstNvVp9Dec");
feature_name = g_strdup ("nvvp9dec"); feature_name = g_strdup ("nvvp9dec");

View file

@ -27,6 +27,7 @@ G_BEGIN_DECLS
void gst_nv_vp9_dec_register (GstPlugin * plugin, void gst_nv_vp9_dec_register (GstPlugin * plugin,
guint device_id, guint device_id,
gint64 adapter_luid,
guint rank, guint rank,
GstCaps * sink_caps, GstCaps * sink_caps,
GstCaps * src_caps); GstCaps * src_caps);

View file

@ -136,11 +136,15 @@ plugin_init (GstPlugin * plugin)
for (i = 0; i < dev_count; i++) { for (i = 0; i < dev_count; i++) {
GstCudaContext *context = gst_cuda_context_new (i); GstCudaContext *context = gst_cuda_context_new (i);
CUcontext cuda_ctx; CUcontext cuda_ctx;
gint64 adapter_luid = 0;
if (!context) { if (!context) {
GST_WARNING ("Failed to create context for device %d", i); GST_WARNING ("Failed to create context for device %d", i);
continue; continue;
} }
#ifdef G_OS_WIN32
g_object_get (context, "dxgi-adapter-luid", &adapter_luid, NULL);
#endif
cuda_ctx = gst_cuda_context_get_handle (context); cuda_ctx = gst_cuda_context_get_handle (context);
if (nvdec_available) { if (nvdec_available) {
@ -163,26 +167,26 @@ plugin_init (GstPlugin * plugin)
switch (codec) { switch (codec) {
case cudaVideoCodec_H264: case cudaVideoCodec_H264:
/* higher than avdec_h264 */ /* higher than avdec_h264 */
gst_nv_h264_dec_register (plugin, gst_nv_h264_dec_register (plugin, i, adapter_luid,
i, GST_RANK_PRIMARY + 1, sink_template, src_template); GST_RANK_PRIMARY + 1, sink_template, src_template);
break; break;
case cudaVideoCodec_HEVC: case cudaVideoCodec_HEVC:
/* higher than avdec_h265 */ /* higher than avdec_h265 */
gst_nv_h265_dec_register (plugin, gst_nv_h265_dec_register (plugin, i, adapter_luid,
i, GST_RANK_PRIMARY + 1, sink_template, src_template); GST_RANK_PRIMARY + 1, sink_template, src_template);
break; break;
case cudaVideoCodec_VP8: case cudaVideoCodec_VP8:
gst_nv_vp8_dec_register (plugin, gst_nv_vp8_dec_register (plugin, i, adapter_luid,
i, GST_RANK_PRIMARY, sink_template, src_template); GST_RANK_PRIMARY, sink_template, src_template);
break; break;
case cudaVideoCodec_VP9: case cudaVideoCodec_VP9:
gst_nv_vp9_dec_register (plugin, gst_nv_vp9_dec_register (plugin, i, adapter_luid,
i, GST_RANK_PRIMARY, sink_template, src_template); GST_RANK_PRIMARY, sink_template, src_template);
break; break;
case cudaVideoCodec_AV1: case cudaVideoCodec_AV1:
/* rust dav1ddec has "primary" rank */ /* rust dav1ddec has "primary" rank */
gst_nv_av1_dec_register (plugin, i, GST_RANK_PRIMARY + 1, gst_nv_av1_dec_register (plugin, i, adapter_luid,
sink_template, src_template); GST_RANK_PRIMARY + 1, sink_template, src_template);
break; break;
default: default:
register_cuviddec = TRUE; register_cuviddec = TRUE;
@ -205,10 +209,8 @@ plugin_init (GstPlugin * plugin)
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
if (g_win32_check_windows_version (6, 0, 0, G_WIN32_OS_ANY)) { if (g_win32_check_windows_version (6, 0, 0, G_WIN32_OS_ANY)) {
gint64 adapter_luid;
GstD3D11Device *d3d11_device; GstD3D11Device *d3d11_device;
g_object_get (context, "dxgi-adapter-luid", &adapter_luid, NULL);
d3d11_device = gst_d3d11_device_new_for_adapter_luid (adapter_luid, d3d11_device = gst_d3d11_device_new_for_adapter_luid (adapter_luid,
D3D11_CREATE_DEVICE_BGRA_SUPPORT); D3D11_CREATE_DEVICE_BGRA_SUPPORT);
if (!d3d11_device) { if (!d3d11_device) {