diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp index b9eadf294c..a67d8a7cc7 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.cpp @@ -79,6 +79,7 @@ typedef struct _GstNvAV1DecClass { GstAV1DecoderClass parent_class; guint cuda_device_id; + gint64 adapter_luid; guint max_width; guint max_height; } GstNvAV1DecClass; @@ -262,6 +263,7 @@ gst_nv_av1_dec_class_init (GstNvAV1DecClass * klass, GST_DEBUG_FUNCPTR (gst_nv_av1_dec_get_preferred_output_delay); klass->cuda_device_id = cdata->cuda_device_id; + klass->adapter_luid = cdata->adapter_luid; klass->max_width = cdata->max_width; 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); - 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->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; @@ -1015,8 +1018,8 @@ gst_nv_av1_dec_get_preferred_output_delay (GstAV1Decoder * decoder, } void -gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) +gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps) { GType type; 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->src_caps = gst_caps_ref (src_caps); cdata->cuda_device_id = device_id; + cdata->adapter_luid = adapter_luid; type_info.class_data = cdata; diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.h index 0924dd3abd..72c77f831c 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvav1dec.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS void gst_nv_av1_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp index cf55c43a33..26b3cbcd3f 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.cpp @@ -50,10 +50,14 @@ #include #endif -#include -#include -#include +#ifdef G_OS_WIN32 +#include +#endif + +#include +#include #include "gstnvdecoder.h" +#include "gstcudaconverter.h" #include #include #include @@ -71,10 +75,11 @@ extern "C" typedef enum { - GST_NV_DECODER_OUTPUT_TYPE_SYSTEM = 0, - GST_NV_DECODER_OUTPUT_TYPE_GL, - GST_NV_DECODER_OUTPUT_TYPE_CUDA, - /* FIXME: add support D3D11 memory */ + GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN = 0, + GST_NV_DECODER_OUTPUT_TYPE_SYSTEM = (1 << 0), + GST_NV_DECODER_OUTPUT_TYPE_GL = (1 << 1), + GST_NV_DECODER_OUTPUT_TYPE_CUDA = (1 << 2), + GST_NV_DECODER_OUTPUT_TYPE_D3D11 = (1 << 3), } GstNvDecoderOutputType; struct _GstNvDecoder @@ -82,6 +87,7 @@ struct _GstNvDecoder GstObject parent; guint device_id; + gint64 adapter_luid; GstNvDecObject *object; GstCudaContext *context; @@ -104,6 +110,13 @@ struct _GstNvDecoder GstObject *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; }; @@ -155,7 +168,6 @@ chroma_format_from_video_format (GstVideoFormat format) case GST_VIDEO_FORMAT_NV12: case GST_VIDEO_FORMAT_P010_10LE: case GST_VIDEO_FORMAT_P012_LE: - case GST_VIDEO_FORMAT_P016_LE: return cudaVideoChromaFormat_420; case GST_VIDEO_FORMAT_Y444: case GST_VIDEO_FORMAT_Y444_16LE: @@ -178,7 +190,6 @@ output_format_from_video_format (GstVideoFormat format) return cudaVideoSurfaceFormat_NV12; case GST_VIDEO_FORMAT_P010_10LE: case GST_VIDEO_FORMAT_P012_LE: - case GST_VIDEO_FORMAT_P016_LE: return cudaVideoSurfaceFormat_P016; case GST_VIDEO_FORMAT_Y444: case GST_VIDEO_FORMAT_GBR: @@ -195,12 +206,13 @@ output_format_from_video_format (GstVideoFormat format) } GstNvDecoder * -gst_nv_decoder_new (guint device_id) +gst_nv_decoder_new (guint device_id, gint64 adapter_luid) { GstNvDecoder *self; self = (GstNvDecoder *) g_object_new (GST_TYPE_NV_DECODER, nullptr); self->device_id = device_id; + self->adapter_luid = adapter_luid; gst_object_ref_sink (self); return self; @@ -229,7 +241,7 @@ gst_nv_decoder_reset_unlocked (GstNvDecoder * self) 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->downstream_min_buffers = 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->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; } @@ -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 (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); if (decoder->info.finfo) prev_format = GST_VIDEO_INFO_FORMAT (&decoder->info); @@ -613,7 +634,7 @@ unmap_video_frame: GST_WARNING_OBJECT (self, "Failed to pop CUDA context"); } -static gboolean +static GstFlowReturn gst_nv_decoder_copy_frame_to_gl (GstNvDecoder * decoder, 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); - return data.ret; + if (!data.ret) + return GST_FLOW_ERROR; + + return GST_FLOW_OK; } #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, GstNvDecSurface * surface, GstBuffer * buffer) { GstVideoFrame video_frame; CUDA_MEMCPY2D copy_params = { 0, }; - gboolean ret = FALSE; + GstFlowReturn ret = GST_FLOW_ERROR; CUstream stream = gst_cuda_stream_get_handle (decoder->stream); if (!gst_video_frame_map (&video_frame, &decoder->info, buffer, GST_MAP_WRITE)) { GST_ERROR_OBJECT (decoder, "Couldn't map video frame"); - return FALSE; + return GST_FLOW_ERROR; } copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE; @@ -667,38 +765,35 @@ gst_nv_decoder_copy_frame_to_system (GstNvDecoder * decoder, } gst_cuda_result (CuStreamSynchronize (stream)); - - ret = TRUE; + ret = GST_FLOW_OK; done: gst_video_frame_unmap (&video_frame); - GST_LOG_OBJECT (decoder, "Copy frame to system ret %d", ret); - return ret; } -static gboolean +static GstFlowReturn gst_nv_decoder_copy_frame_to_cuda (GstNvDecoder * decoder, GstNvDecSurface * surface, GstBuffer * buffer, GstCudaStream * stream) { CUDA_MEMCPY2D copy_params = { 0, }; GstMemory *mem; - gboolean ret = FALSE; GstVideoFrame video_frame; CUstream stream_handle = gst_cuda_stream_get_handle (stream); + GstFlowReturn ret = GST_FLOW_ERROR; mem = gst_buffer_peek_memory (buffer, 0); if (!gst_is_cuda_memory (mem)) { GST_WARNING_OBJECT (decoder, "Not a CUDA memory"); - return FALSE; + return GST_FLOW_ERROR; } if (!gst_video_frame_map (&video_frame, &decoder->info, buffer, (GstMapFlags) (GST_MAP_WRITE | GST_MAP_CUDA))) { GST_ERROR_OBJECT (decoder, "frame map failure"); - return FALSE; + return GST_FLOW_ERROR; } copy_params.srcMemoryType = CU_MEMORYTYPE_DEVICE; @@ -727,13 +822,11 @@ gst_nv_decoder_copy_frame_to_cuda (GstNvDecoder * decoder, else GST_MINI_OBJECT_FLAG_SET (mem, GST_CUDA_MEMORY_TRANSFER_NEED_SYNC); - ret = TRUE; + ret = GST_FLOW_OK; done: gst_video_frame_unmap (&video_frame); - GST_LOG_OBJECT (decoder, "Copy frame to CUDA ret %d", ret); - return ret; } @@ -748,11 +841,20 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder, gboolean can_export = FALSE; if (picture->discont_state) { + GST_DEBUG_OBJECT (videodec, "Negotiate again on input state change"); if (!gst_nv_decoder_negotiate (decoder, videodec, picture->discont_state)) { GST_ERROR_OBJECT (videodec, "Couldn't re-negotiate with updated state"); ret = GST_FLOW_NOT_NEGOTIATED; 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); @@ -827,7 +929,7 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder, frame->output_buffer = buf; } else { - gboolean copy_ret = FALSE; + gboolean need_unmap = TRUE; frame->output_buffer = gst_video_decoder_allocate_output_buffer (videodec); if (!frame->output_buffer) { @@ -839,21 +941,29 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder, } switch (decoder->output_type) { + case GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN: 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); 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 case GST_NV_DECODER_OUTPUT_TYPE_GL: 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, frame->output_buffer); break; #endif 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); break; default: @@ -868,19 +978,21 @@ gst_nv_decoder_output_picture (GstNvDecoder * decoder, * belongs to non-nvidia (or different device). * 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, "Couldn't copy frame to GL memory, fallback to system memory"); 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); } - 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); - if (!copy_ret) { + if (ret != GST_FLOW_OK) { GST_WARNING_OBJECT (videodec, "Failed to copy frame"); goto error; } @@ -1100,6 +1212,22 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec, guint i; gboolean ret = FALSE; 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++) { 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_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 { 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: if (bitdepth_minus8[b_idx] == 0) { formats.insert ("NV12"); + planar_formats.insert ("I420"); } else if (bitdepth_minus8[b_idx] == 2) { formats.insert ("P010_10LE"); + planar_formats.insert ("I420_10LE"); } else if (bitdepth_minus8[b_idx] == 4) { formats.insert ("P012_LE"); + planar_formats.insert ("I420_12LE"); } else { GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8); break; @@ -1213,12 +1355,18 @@ gst_nv_decoder_check_device_caps (CUcontext cuda_ctx, cudaVideoCodec codec, if (bitdepth_minus8[b_idx] == 0) { formats.insert ("Y444"); - if (codec == cudaVideoCodec_HEVC) + planar_formats.insert ("Y444"); + if (codec == cudaVideoCodec_HEVC) { formats.insert ("GBR"); + planar_formats.insert ("GBR"); + } } else if (bitdepth_minus8[b_idx] == 2 || bitdepth_minus8[b_idx] == 4) { formats.insert ("Y444_16LE"); - if (codec == cudaVideoCodec_HEVC) + planar_formats.insert ("Y444_16LE"); + if (codec == cudaVideoCodec_HEVC) { formats.insert ("GBR_16LE"); + planar_formats.insert ("GBR_16LE"); + } } else { GST_WARNING ("unhandled bitdepth %d", bitdepth_minus8[b_idx] + 8); 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_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 */ #ifdef HAVE_CUDA_GST_GL format_str.clear (); @@ -1355,6 +1530,13 @@ gst_nv_decoder_handle_set_context (GstNvDecoder * decoder, &decoder->context)) { 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 gst_gl_handle_set_context (element, context, (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)) 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 if (gst_gl_handle_context_query (element, query, (GstGLDisplay *) decoder->gl_display, @@ -1475,12 +1664,89 @@ gst_nv_decoder_ensure_gl_context (GstNvDecoder * decoder, GstElement * videodec) } #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 gst_nv_decoder_negotiate (GstNvDecoder * decoder, GstVideoDecoder * videodec, GstVideoCodecState * input_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_VIDEO_DECODER (videodec), FALSE); @@ -1491,16 +1757,9 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder, return FALSE; } - info = &decoder->info; - state = gst_video_decoder_set_interlaced_output_state (videodec, - GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_INTERLACE_MODE (info), - 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; + decoder->output_info = decoder->info; + prev_output_type = decoder->output_type; + available_types = selected_type = 0; { GstCaps *caps; @@ -1514,37 +1773,66 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder, GstCapsFeatures *features; guint size = gst_caps_get_size (caps); guint i; - gboolean have_cuda = FALSE; - gboolean have_gl = FALSE; for (i = 0; i < size; i++) { features = gst_caps_get_features (caps, i); if (features && gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_CUDA_MEMORY)) { GST_DEBUG_OBJECT (videodec, "found CUDA memory feature"); - have_cuda = TRUE; - break; + available_types |= GST_NV_DECODER_OUTPUT_TYPE_CUDA; } +#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 /* TODO: gl does not support Y444_16 and GBR_16 */ - if (GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_Y444_16LE && - GST_VIDEO_INFO_FORMAT (info) != GST_VIDEO_FORMAT_GBR_16LE && + if (GST_VIDEO_INFO_FORMAT (&decoder->info) != + GST_VIDEO_FORMAT_Y444_16LE && + GST_VIDEO_INFO_FORMAT (&decoder->info) != + GST_VIDEO_FORMAT_GBR_16LE && features && gst_caps_features_contains (features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) { GST_DEBUG_OBJECT (videodec, "found GL memory feature"); - have_gl = TRUE; + available_types |= GST_NV_DECODER_OUTPUT_TYPE_GL; } #endif } - if (have_cuda) - decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_CUDA; - else if (have_gl) - decoder->output_type = GST_NV_DECODER_OUTPUT_TYPE_GL; + if (prev_output_type != GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN && + (prev_output_type & available_types) == prev_output_type) { + selected_type = prev_output_type; + } + + 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); } +#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 if (decoder->output_type == GST_NV_DECODER_OUTPUT_TYPE_GL && !gst_nv_decoder_ensure_gl_context (decoder, GST_ELEMENT (videodec))) { @@ -1554,17 +1842,30 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder, } #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) { case GST_NV_DECODER_OUTPUT_TYPE_CUDA: GST_DEBUG_OBJECT (videodec, "using CUDA memory"); 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; +#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 case GST_NV_DECODER_OUTPUT_TYPE_GL: GST_DEBUG_OBJECT (videodec, "using GL memory"); 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, "2D", nullptr); break; @@ -1574,6 +1875,9 @@ gst_nv_decoder_negotiate (GstNvDecoder * decoder, break; } + /* decoder baseclass will hold other reference to output state */ + gst_video_codec_state_unref (state); + return TRUE; } @@ -1699,6 +2003,90 @@ gst_nv_decoder_ensure_gl_pool (GstNvDecoder * decoder, GstQuery * query) } #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 gst_nv_decoder_decide_allocation (GstNvDecoder * decoder, GstVideoDecoder * videodec, GstQuery * query) @@ -1708,9 +2096,16 @@ gst_nv_decoder_decide_allocation (GstNvDecoder * decoder, GST_DEBUG_OBJECT (videodec, "decide allocation"); switch (decoder->output_type) { + case GST_NV_DECODER_OUTPUT_TYPE_UNKNOWN: case GST_NV_DECODER_OUTPUT_TYPE_SYSTEM: /* GstVideoDecoder will take care this case */ 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 case GST_NV_DECODER_OUTPUT_TYPE_GL: ret = gst_nv_decoder_ensure_gl_pool (decoder, query); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h index 0a6fc7c05e..d33a959b64 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvdecoder.h @@ -38,11 +38,13 @@ typedef struct _GstNvDecoderClassData GstCaps *sink_caps; GstCaps *src_caps; guint cuda_device_id; + gint64 adapter_luid; guint max_width; guint max_height; } 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, GstElement * element); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp index c551824ed3..ccb1930573 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.cpp @@ -135,6 +135,7 @@ typedef struct _GstNvH264DecClass { GstH264DecoderClass parent_class; guint cuda_device_id; + gint64 adapter_luid; guint max_width; guint max_height; } GstNvH264DecClass; @@ -330,6 +331,7 @@ gst_nv_h264_dec_class_init (GstNvH264DecClass * klass, GST_DEBUG_FUNCPTR (gst_nv_h264_dec_get_preferred_output_delay); klass->cuda_device_id = cdata->cuda_device_id; + klass->adapter_luid = cdata->adapter_luid; klass->max_width = cdata->max_width; 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); - 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, sizeof (GstH264Picture *), 16); g_array_set_clear_func (self->ref_list, @@ -1044,8 +1047,8 @@ gst_nv_h264_dec_get_preferred_output_delay (GstH264Decoder * decoder, } void -gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) +gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps) { GType type; 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); cdata->src_caps = gst_caps_ref (src_caps); cdata->cuda_device_id = device_id; + cdata->adapter_luid = adapter_luid; type_name = g_strdup ("GstNvH264Dec"); feature_name = g_strdup ("nvh264dec"); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.h index e19cd21178..47875d87a5 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh264dec.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS void gst_nv_h264_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp index 368fef9109..40c89a0d7b 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.cpp @@ -134,6 +134,7 @@ typedef struct _GstNvH265DecClass { GstH265DecoderClass parent_class; guint cuda_device_id; + gint64 adapter_luid; guint max_width; guint max_height; } GstNvH265DecClass; @@ -324,6 +325,7 @@ gst_nv_h265_dec_class_init (GstNvH265DecClass * klass, GST_DEBUG_FUNCPTR (gst_nv_h265_dec_get_preferred_output_delay); klass->cuda_device_id = cdata->cuda_device_id; + klass->adapter_luid = cdata->adapter_luid; klass->max_width = cdata->max_width; 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); - 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->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; @@ -1150,8 +1153,8 @@ gst_nv_h265_dec_get_preferred_output_delay (GstH265Decoder * decoder, } void -gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) +gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps) { GType type; 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); cdata->src_caps = gst_caps_ref (src_caps); cdata->cuda_device_id = device_id; + cdata->adapter_luid = adapter_luid; type_name = g_strdup ("GstNvH265Dec"); feature_name = g_strdup ("nvh265dec"); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.h index 395c81e6f8..3a769a7cd5 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvh265dec.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS void gst_nv_h265_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp index 868cd6c36d..970f8afeee 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.cpp @@ -63,6 +63,7 @@ typedef struct _GstNvVp8DecClass { GstVp8DecoderClass parent_class; guint cuda_device_id; + gint64 adapter_luid; guint max_width; guint max_height; } GstNvVp8DecClass; @@ -243,6 +244,7 @@ gst_nv_vp8_dec_class_init (GstNvVp8DecClass * klass, GST_DEBUG_FUNCPTR (gst_nv_vp8_dec_get_preferred_output_delay); klass->cuda_device_id = cdata->cuda_device_id; + klass->adapter_luid = cdata->adapter_luid; klass->max_width = cdata->max_width; 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); - 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->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; @@ -629,8 +632,8 @@ gst_nv_vp8_dec_get_preferred_output_delay (GstVp8Decoder * decoder, } void -gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) +gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps) { GType type; 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->src_caps = gst_caps_ref (src_caps); cdata->cuda_device_id = device_id; + cdata->adapter_luid = adapter_luid; type_name = g_strdup ("GstNvVp8Dec"); feature_name = g_strdup ("nvvp8dec"); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.h index 9dd5e145f0..6f124d2567 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp8dec.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS void gst_nv_vp8_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp index 851d4e8615..97ac6f54f4 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.cpp @@ -64,6 +64,7 @@ typedef struct _GstNvVp9DecClass { GstVp9DecoderClass parent_class; guint cuda_device_id; + gint64 adapter_luid; guint max_width; guint max_height; } GstNvVp9DecClass; @@ -248,6 +249,7 @@ gst_nv_vp9_dec_class_init (GstNvVp9DecClass * klass, GST_DEBUG_FUNCPTR (gst_nv_vp9_dec_get_preferred_output_delay); klass->cuda_device_id = cdata->cuda_device_id; + klass->adapter_luid = cdata->adapter_luid; klass->max_width = cdata->max_width; 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); - 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->max_display_delay = DEFAULT_MAX_DISPLAY_DELAY; @@ -725,8 +728,8 @@ gst_nv_vp9_dec_get_preferred_output_delay (GstVp9Decoder * decoder, } void -gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, guint rank, - GstCaps * sink_caps, GstCaps * src_caps) +gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps) { GType type; 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); cdata->src_caps = gst_caps_ref (src_caps); cdata->cuda_device_id = device_id; + cdata->adapter_luid = adapter_luid; type_name = g_strdup ("GstNvVp9Dec"); feature_name = g_strdup ("nvvp9dec"); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.h b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.h index bd60964511..0766d92d74 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.h +++ b/subprojects/gst-plugins-bad/sys/nvcodec/gstnvvp9dec.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS void gst_nv_vp9_dec_register (GstPlugin * plugin, guint device_id, + gint64 adapter_luid, guint rank, GstCaps * sink_caps, GstCaps * src_caps); diff --git a/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c b/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c index f20d5cf5f5..6f51eb262c 100644 --- a/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c +++ b/subprojects/gst-plugins-bad/sys/nvcodec/plugin.c @@ -136,11 +136,15 @@ plugin_init (GstPlugin * plugin) for (i = 0; i < dev_count; i++) { GstCudaContext *context = gst_cuda_context_new (i); CUcontext cuda_ctx; + gint64 adapter_luid = 0; if (!context) { GST_WARNING ("Failed to create context for device %d", i); continue; } +#ifdef G_OS_WIN32 + g_object_get (context, "dxgi-adapter-luid", &adapter_luid, NULL); +#endif cuda_ctx = gst_cuda_context_get_handle (context); if (nvdec_available) { @@ -163,26 +167,26 @@ plugin_init (GstPlugin * plugin) switch (codec) { case cudaVideoCodec_H264: /* higher than avdec_h264 */ - gst_nv_h264_dec_register (plugin, - i, GST_RANK_PRIMARY + 1, sink_template, src_template); + gst_nv_h264_dec_register (plugin, i, adapter_luid, + GST_RANK_PRIMARY + 1, sink_template, src_template); break; case cudaVideoCodec_HEVC: /* higher than avdec_h265 */ - gst_nv_h265_dec_register (plugin, - i, GST_RANK_PRIMARY + 1, sink_template, src_template); + gst_nv_h265_dec_register (plugin, i, adapter_luid, + GST_RANK_PRIMARY + 1, sink_template, src_template); break; case cudaVideoCodec_VP8: - gst_nv_vp8_dec_register (plugin, - i, GST_RANK_PRIMARY, sink_template, src_template); + gst_nv_vp8_dec_register (plugin, i, adapter_luid, + GST_RANK_PRIMARY, sink_template, src_template); break; case cudaVideoCodec_VP9: - gst_nv_vp9_dec_register (plugin, - i, GST_RANK_PRIMARY, sink_template, src_template); + gst_nv_vp9_dec_register (plugin, i, adapter_luid, + GST_RANK_PRIMARY, sink_template, src_template); break; case cudaVideoCodec_AV1: /* rust dav1ddec has "primary" rank */ - gst_nv_av1_dec_register (plugin, i, GST_RANK_PRIMARY + 1, - sink_template, src_template); + gst_nv_av1_dec_register (plugin, i, adapter_luid, + GST_RANK_PRIMARY + 1, sink_template, src_template); break; default: register_cuviddec = TRUE; @@ -205,10 +209,8 @@ plugin_init (GstPlugin * plugin) #ifdef G_OS_WIN32 if (g_win32_check_windows_version (6, 0, 0, G_WIN32_OS_ANY)) { - gint64 adapter_luid; 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_CREATE_DEVICE_BGRA_SUPPORT); if (!d3d11_device) {