nvdec: Create CUDA context with registered device id

Only the default device has been used by NVDEC so far.
This commit make it possible to use registered device id.
To simplify device id selection, GstNvDecCudaContext usage is removed.
This commit is contained in:
Seungha Yang 2019-07-21 21:23:30 +09:00 committed by Sebastian Dröge
parent 1df2f13d0c
commit 0239152bca
2 changed files with 66 additions and 102 deletions

View file

@ -52,58 +52,10 @@ cuda_OK (CUresult result)
return TRUE; return TRUE;
} }
G_DEFINE_TYPE (GstNvDecCudaContext, gst_nvdec_cuda_context, G_TYPE_OBJECT);
static void
gst_nvdec_cuda_context_finalize (GObject * object)
{
GstNvDecCudaContext *self = (GstNvDecCudaContext *) object;
if (self->lock) {
GST_DEBUG ("destroying CUDA context lock");
if (cuda_OK (CuvidCtxLockDestroy (self->lock)))
self->lock = NULL;
else
GST_ERROR ("failed to destroy CUDA context lock");
}
if (self->context) {
GST_DEBUG ("destroying CUDA context");
if (cuda_OK (CuCtxDestroy (self->context)))
self->context = NULL;
else
GST_ERROR ("failed to destroy CUDA context");
}
G_OBJECT_CLASS (gst_nvdec_cuda_context_parent_class)->finalize (object);
}
static void
gst_nvdec_cuda_context_class_init (GstNvDecCudaContextClass * klass)
{
G_OBJECT_CLASS (klass)->finalize = gst_nvdec_cuda_context_finalize;
}
static void
gst_nvdec_cuda_context_init (GstNvDecCudaContext * self)
{
if (!cuda_OK (CuInit (0)))
GST_ERROR ("failed to init CUDA");
if (!cuda_OK (CuCtxCreate (&self->context, CU_CTX_SCHED_AUTO, 0)))
GST_ERROR ("failed to create CUDA context");
if (!cuda_OK (CuCtxPopCurrent (NULL)))
GST_ERROR ("failed to pop current CUDA context");
if (!cuda_OK (CuvidCtxLockCreate (&self->lock, self->context)))
GST_ERROR ("failed to create CUDA context lock");
}
typedef struct _GstNvDecCudaGraphicsResourceInfo typedef struct _GstNvDecCudaGraphicsResourceInfo
{ {
GstGLContext *gl_context; GstGLContext *gl_context;
GstNvDecCudaContext *cuda_context; GstNvDec *nvdec;
CUgraphicsResource resource; CUgraphicsResource resource;
} GstNvDecCudaGraphicsResourceInfo; } GstNvDecCudaGraphicsResourceInfo;
@ -115,38 +67,41 @@ register_cuda_resource (GstGLContext * context, gpointer * args)
(GstNvDecCudaGraphicsResourceInfo *) args[1]; (GstNvDecCudaGraphicsResourceInfo *) args[1];
GstMapInfo map_info = GST_MAP_INFO_INIT; GstMapInfo map_info = GST_MAP_INFO_INIT;
guint texture_id; guint texture_id;
GstNvDec *nvdec = cgr_info->nvdec;
if (!cuda_OK (CuvidCtxLock (cgr_info->cuda_context->lock, 0))) if (!cuda_OK (CuvidCtxLock (nvdec->ctx_lock, 0)))
GST_WARNING ("failed to lock CUDA context"); GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) { if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) {
texture_id = *(guint *) map_info.data; texture_id = *(guint *) map_info.data;
if (!cuda_OK (CuGraphicsGLRegisterImage (&cgr_info->resource, texture_id, if (!cuda_OK (CuGraphicsGLRegisterImage (&cgr_info->resource, texture_id,
GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD))) GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD)))
GST_WARNING ("failed to register texture with CUDA"); GST_WARNING_OBJECT (nvdec, "failed to register texture with CUDA");
gst_memory_unmap (mem, &map_info); gst_memory_unmap (mem, &map_info);
} else } else
GST_WARNING ("failed to map memory"); GST_WARNING_OBJECT (nvdec, "failed to map memory");
if (!cuda_OK (CuvidCtxUnlock (cgr_info->cuda_context->lock, 0))) if (!cuda_OK (CuvidCtxUnlock (nvdec->ctx_lock, 0)))
GST_WARNING ("failed to unlock CUDA context"); GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
} }
static void static void
unregister_cuda_resource (GstGLContext * context, unregister_cuda_resource (GstGLContext * context,
GstNvDecCudaGraphicsResourceInfo * cgr_info) GstNvDecCudaGraphicsResourceInfo * cgr_info)
{ {
if (!cuda_OK (CuvidCtxLock (cgr_info->cuda_context->lock, 0))) GstNvDec *nvdec = cgr_info->nvdec;
GST_WARNING ("failed to lock CUDA context");
if (!cuda_OK (CuvidCtxLock (nvdec->ctx_lock, 0)))
GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
if (!cuda_OK (CuGraphicsUnregisterResource ((const CUgraphicsResource) if (!cuda_OK (CuGraphicsUnregisterResource ((const CUgraphicsResource)
cgr_info->resource))) cgr_info->resource)))
GST_WARNING ("failed to unregister resource"); GST_WARNING_OBJECT (nvdec, "failed to unregister resource");
if (!cuda_OK (CuvidCtxUnlock (cgr_info->cuda_context->lock, 0))) if (!cuda_OK (CuvidCtxUnlock (nvdec->ctx_lock, 0)))
GST_WARNING ("failed to unlock CUDA context"); GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
} }
static void static void
@ -155,13 +110,11 @@ free_cgr_info (GstNvDecCudaGraphicsResourceInfo * cgr_info)
gst_gl_context_thread_add (cgr_info->gl_context, gst_gl_context_thread_add (cgr_info->gl_context,
(GstGLContextThreadFunc) unregister_cuda_resource, cgr_info); (GstGLContextThreadFunc) unregister_cuda_resource, cgr_info);
gst_object_unref (cgr_info->gl_context); gst_object_unref (cgr_info->gl_context);
g_object_unref (cgr_info->cuda_context);
g_slice_free (GstNvDecCudaGraphicsResourceInfo, cgr_info); g_slice_free (GstNvDecCudaGraphicsResourceInfo, cgr_info);
} }
static CUgraphicsResource static CUgraphicsResource
ensure_cuda_graphics_resource (GstMemory * mem, ensure_cuda_graphics_resource (GstMemory * mem, GstNvDec * nvdec)
GstNvDecCudaContext * cuda_context)
{ {
static GQuark quark = 0; static GQuark quark = 0;
GstNvDecCudaGraphicsResourceInfo *cgr_info; GstNvDecCudaGraphicsResourceInfo *cgr_info;
@ -180,7 +133,7 @@ ensure_cuda_graphics_resource (GstMemory * mem,
cgr_info = g_slice_new (GstNvDecCudaGraphicsResourceInfo); cgr_info = g_slice_new (GstNvDecCudaGraphicsResourceInfo);
cgr_info->gl_context = cgr_info->gl_context =
gst_object_ref (GST_GL_BASE_MEMORY_CAST (mem)->context); gst_object_ref (GST_GL_BASE_MEMORY_CAST (mem)->context);
cgr_info->cuda_context = g_object_ref (cuda_context); cgr_info->nvdec = nvdec;
args[0] = mem; args[0] = mem;
args[1] = cgr_info; args[1] = cgr_info;
gst_gl_context_thread_add (cgr_info->gl_context, gst_gl_context_thread_add (cgr_info->gl_context,
@ -248,7 +201,7 @@ parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
GST_DEBUG_OBJECT (nvdec, "width: %u, height: %u", width, height); GST_DEBUG_OBJECT (nvdec, "width: %u, height: %u", width, height);
if (!nvdec->decoder || (nvdec->width != width || nvdec->height != height)) { if (!nvdec->decoder || (nvdec->width != width || nvdec->height != height)) {
if (!cuda_OK (CuvidCtxLock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxLock (nvdec->ctx_lock, 0))) {
GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context"); GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
goto error; goto error;
} }
@ -278,7 +231,7 @@ parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
create_info.ulTargetWidth = width; create_info.ulTargetWidth = width;
create_info.ulTargetHeight = height; create_info.ulTargetHeight = height;
create_info.ulNumOutputSurfaces = 1; create_info.ulNumOutputSurfaces = 1;
create_info.vidLock = nvdec->cuda_context->lock; create_info.vidLock = nvdec->ctx_lock;
create_info.target_rect.left = 0; create_info.target_rect.left = 0;
create_info.target_rect.top = 0; create_info.target_rect.top = 0;
create_info.target_rect.right = width; create_info.target_rect.right = width;
@ -290,7 +243,7 @@ parser_sequence_callback (GstNvDec * nvdec, CUVIDEOFORMAT * format)
goto error; goto error;
} }
if (!cuda_OK (CuvidCtxUnlock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxUnlock (nvdec->ctx_lock, 0))) {
GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context"); GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
goto error; goto error;
} }
@ -402,7 +355,7 @@ parser_decode_callback (GstNvDec * nvdec, CUVIDPICPARAMS * params)
GST_LOG_OBJECT (nvdec, "picture index: %u", params->CurrPicIdx); GST_LOG_OBJECT (nvdec, "picture index: %u", params->CurrPicIdx);
if (!cuda_OK (CuvidCtxLock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxLock (nvdec->ctx_lock, 0))) {
GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context"); GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
goto error; goto error;
} }
@ -412,7 +365,7 @@ parser_decode_callback (GstNvDec * nvdec, CUVIDPICPARAMS * params)
goto error; goto error;
} }
if (!cuda_OK (CuvidCtxUnlock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxUnlock (nvdec->ctx_lock, 0))) {
GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context"); GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
goto error; goto error;
} }
@ -529,7 +482,7 @@ parser_display_callback (GstNvDec * nvdec, CUVIDPARSERDISPINFO * dispinfo)
for (i = 0; i < num_resources; i++) { for (i = 0; i < num_resources; i++) {
mem = gst_buffer_get_memory (output_buffer, i); mem = gst_buffer_get_memory (output_buffer, i);
resources[i] = ensure_cuda_graphics_resource (mem, nvdec->cuda_context); resources[i] = ensure_cuda_graphics_resource (mem, nvdec);
GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD); GST_MINI_OBJECT_FLAG_SET (mem, GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
gst_memory_unref (mem); gst_memory_unref (mem);
} }
@ -576,13 +529,37 @@ static gboolean
gst_nvdec_start (GstVideoDecoder * decoder) gst_nvdec_start (GstVideoDecoder * decoder)
{ {
GstNvDec *nvdec = GST_NVDEC (decoder); GstNvDec *nvdec = GST_NVDEC (decoder);
GstNvDecClass *klass = GST_NVDEC_GET_CLASS (nvdec);
nvdec->state = GST_NVDEC_STATE_INIT; nvdec->state = GST_NVDEC_STATE_INIT;
GST_DEBUG_OBJECT (nvdec, "creating CUDA context"); GST_DEBUG_OBJECT (nvdec, "creating CUDA context");
nvdec->cuda_context = g_object_new (gst_nvdec_cuda_context_get_type (), NULL);
if (!nvdec->cuda_context->context || !nvdec->cuda_context->lock) { if (!cuda_OK (CuInit (0))) {
GST_ERROR_OBJECT (nvdec, "failed to create CUDA context or lock"); GST_ERROR_OBJECT (nvdec, "failed to init CUDA");
return FALSE;
}
if (!cuda_OK (CuCtxCreate (&nvdec->context, 0, klass->cuda_device_id))) {
GST_ERROR_OBJECT (nvdec,
"failed to create CUDA context with device id %d",
klass->cuda_device_id);
return FALSE;
}
if (!cuda_OK (CuCtxPopCurrent (NULL))) {
GST_ERROR_OBJECT (nvdec, "failed to pop current CUDA context");
CuCtxDestroy (nvdec->context);
nvdec->context = NULL;
return FALSE;
}
if (!cuda_OK (CuvidCtxLockCreate (&nvdec->ctx_lock, nvdec->context))) {
GST_ERROR_OBJECT (nvdec, "failed to create CUDA context lock");
CuCtxDestroy (nvdec->context);
nvdec->context = NULL;
return FALSE; return FALSE;
} }
@ -596,7 +573,7 @@ maybe_destroy_decoder_and_parser (GstNvDec * nvdec)
{ {
gboolean ret = TRUE; gboolean ret = TRUE;
if (!cuda_OK (CuvidCtxLock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxLock (nvdec->ctx_lock, 0))) {
GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context"); GST_ERROR_OBJECT (nvdec, "failed to lock CUDA context");
return FALSE; return FALSE;
} }
@ -610,7 +587,7 @@ maybe_destroy_decoder_and_parser (GstNvDec * nvdec)
GST_ERROR_OBJECT (nvdec, "failed to destroy decoder"); GST_ERROR_OBJECT (nvdec, "failed to destroy decoder");
} }
if (!cuda_OK (CuvidCtxUnlock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxUnlock (nvdec->ctx_lock, 0))) {
GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context"); GST_ERROR_OBJECT (nvdec, "failed to unlock CUDA context");
return FALSE; return FALSE;
} }
@ -637,11 +614,6 @@ gst_nvdec_stop (GstVideoDecoder * decoder)
if (!maybe_destroy_decoder_and_parser (nvdec)) if (!maybe_destroy_decoder_and_parser (nvdec))
return FALSE; return FALSE;
if (nvdec->cuda_context) {
g_object_unref (nvdec->cuda_context);
nvdec->cuda_context = NULL;
}
if (nvdec->gl_context) { if (nvdec->gl_context) {
gst_object_unref (nvdec->gl_context); gst_object_unref (nvdec->gl_context);
nvdec->gl_context = NULL; nvdec->gl_context = NULL;
@ -662,6 +634,16 @@ gst_nvdec_stop (GstVideoDecoder * decoder)
nvdec->input_state = NULL; nvdec->input_state = NULL;
} }
if (nvdec->ctx_lock) {
CuvidCtxLockDestroy (nvdec->ctx_lock);
nvdec->ctx_lock = NULL;
}
if (nvdec->context) {
CuCtxDestroy (nvdec->context);
nvdec->context = NULL;
}
return TRUE; return TRUE;
} }
@ -723,7 +705,7 @@ copy_video_frame_to_gl_textures (GstGLContext * context, gpointer * args)
proc_params.top_field_first = dispinfo->top_field_first; proc_params.top_field_first = dispinfo->top_field_first;
proc_params.unpaired_field = dispinfo->repeat_first_field == -1; proc_params.unpaired_field = dispinfo->repeat_first_field == -1;
if (!cuda_OK (CuvidCtxLock (nvdec->cuda_context->lock, 0))) { if (!cuda_OK (CuvidCtxLock (nvdec->ctx_lock, 0))) {
GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context"); GST_WARNING_OBJECT (nvdec, "failed to lock CUDA context");
return; return;
} }
@ -768,7 +750,7 @@ unmap_video_frame:
GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame"); GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA video frame");
unlock_cuda_context: unlock_cuda_context:
if (!cuda_OK (CuvidCtxUnlock (nvdec->cuda_context->lock, 0))) if (!cuda_OK (CuvidCtxUnlock (nvdec->ctx_lock, 0)))
GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context"); GST_WARNING_OBJECT (nvdec, "failed to unlock CUDA context");
} }

View file

@ -35,25 +35,6 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _GstNvDecCudaContext GstNvDecCudaContext;
typedef struct _GstNvDecCudaContextClass GstNvDecCudaContextClass;
struct _GstNvDecCudaContext
{
GObject parent;
CUcontext context;
CUvideoctxlock lock;
};
struct _GstNvDecCudaContextClass
{
GObjectClass parent_class;
};
GType gst_nvdec_cuda_context_get_type (void);
#define GST_TYPE_NVDEC (gst_nvdec_get_type()) #define GST_TYPE_NVDEC (gst_nvdec_get_type())
#define GST_NVDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NVDEC, GstNvDec)) #define GST_NVDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_NVDEC, GstNvDec))
#define GST_NVDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_NVDEC, GstNvDecClass)) #define GST_NVDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_NVDEC, GstNvDecClass))
@ -79,9 +60,10 @@ struct _GstNvDec
GstGLContext *gl_context; GstGLContext *gl_context;
GstGLContext *other_gl_context; GstGLContext *other_gl_context;
GstNvDecCudaContext *cuda_context;
CUvideoparser parser; CUvideoparser parser;
CUvideodecoder decoder; CUvideodecoder decoder;
CUcontext context;
CUvideoctxlock ctx_lock;
guint width; guint width;
guint height; guint height;