nvdec: Use qdata on memory instead of buffer meta

Using a meta can be problematic since the memory contained in the buffer
can be transferred to a new buffer in which case the meta would be lost.

https://bugzilla.gnome.org/show_bug.cgi?id=784235
This commit is contained in:
Per-Erik Brodin 2017-06-27 18:47:37 -07:00 committed by Sebastian Dröge
parent af6db6861e
commit 3223d605bf

View file

@ -112,180 +112,96 @@ gst_nvdec_cuda_context_init (GstNvDecCudaContext * self)
GST_ERROR ("failed to create CUDA context lock"); GST_ERROR ("failed to create CUDA context lock");
} }
typedef struct _GstNvDecCudaGraphicsResourcesMeta typedef struct _GstNvDecCudaGraphicsResourceInfo
{ {
GstMeta meta; GstGLContext *gl_context;
GstNvDecCudaContext *cuda_context; GstNvDecCudaContext *cuda_context;
CUgraphicsResource *resources; CUgraphicsResource resource;
guint num_resources; } GstNvDecCudaGraphicsResourceInfo;
} GstNvDecCudaGraphicsResourcesMeta;
GType gst_nvdec_cuda_graphics_resources_meta_api_get_type (void);
#define GST_NVDEC_CUDA_GRAPHICS_RESOURCES_META_API_TYPE (gst_nvdec_cuda_graphics_resources_meta_api_get_type())
#define gst_buffer_get_nvdec_cuda_graphics_resources_meta(b) \
((GstNvDecCudaGraphicsResourcesMeta *)gst_buffer_get_meta((b), GST_NVDEC_CUDA_GRAPHICS_RESOURCES_META_API_TYPE))
GType
gst_nvdec_cuda_graphics_resources_meta_api_get_type (void)
{
static volatile GType type;
static const gchar *tags[] = { GST_META_TAG_MEMORY_STR, NULL };
if (g_once_init_enter (&type)) {
GType _type =
gst_meta_api_type_register ("GstNvDecCudaGraphicsResourcesMetaAPI",
tags);
g_once_init_leave (&type, _type);
}
return type;
}
const GstMetaInfo *gst_nvdec_cuda_graphics_resources_meta_get_info (void);
#define GST_NVDEC_CUDA_GRAPHICS_RESOURCES_META_INFO (gst_nvdec_cuda_graphics_resources_meta_get_info())
GstNvDecCudaGraphicsResourcesMeta
* gst_buffer_add_nvdec_cuda_graphics_resources_meta (GstBuffer * buffer,
GstNvDecCudaContext * cuda_context);
static void static void
add_cgr_meta (GstGLContext * context, GstBuffer * buffer) register_cuda_resource (GstGLContext * context, gpointer * args)
{ {
GstNvDecCudaGraphicsResourcesMeta *meta; GstMemory *mem = GST_MEMORY_CAST (args[0]);
GstMemory *mem; GstNvDecCudaGraphicsResourceInfo *cgr_info =
(GstNvDecCudaGraphicsResourceInfo *) args[1];
GstMapInfo map_info = GST_MAP_INFO_INIT; GstMapInfo map_info = GST_MAP_INFO_INIT;
CUgraphicsResource *resources; guint texture_id;
guint n, i, texture_id;
meta = gst_buffer_get_nvdec_cuda_graphics_resources_meta (buffer); if (!cuda_OK (cuvidCtxLock (cgr_info->cuda_context->lock, 0)))
n = gst_buffer_n_memory (buffer);
resources = g_new0 (CUgraphicsResource, n);
if (!cuda_OK (cuvidCtxLock (meta->cuda_context->lock, 0)))
GST_WARNING ("failed to lock CUDA context"); GST_WARNING ("failed to lock CUDA context");
for (i = 0; i < n; i++) { if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) {
mem = gst_buffer_get_memory (buffer, i); texture_id = *(guint *) map_info.data;
if (gst_memory_map (mem, &map_info, GST_MAP_READ | GST_MAP_GL)) { if (!cuda_OK (cuGraphicsGLRegisterImage (&cgr_info->resource, texture_id,
texture_id = *(guint *) map_info.data; GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD)))
GST_WARNING ("failed to register texture with CUDA");
if (!cuda_OK (cuGraphicsGLRegisterImage (&resources[i], texture_id, gst_memory_unmap (mem, &map_info);
GL_TEXTURE_2D, CU_GRAPHICS_REGISTER_FLAGS_WRITE_DISCARD))) } else
GST_WARNING ("failed to register texture with CUDA"); GST_WARNING ("failed to map memory");
gst_memory_unmap (mem, &map_info); if (!cuda_OK (cuvidCtxUnlock (cgr_info->cuda_context->lock, 0)))
} else
GST_WARNING ("failed to map memory");
gst_memory_unref (mem);
}
if (!cuda_OK (cuvidCtxUnlock (meta->cuda_context->lock, 0)))
GST_WARNING ("failed to unlock CUDA context"); GST_WARNING ("failed to unlock CUDA context");
meta->resources = resources;
meta->num_resources = n;
} }
static void static void
free_cgr_meta (GstGLContext * context, GstNvDecCudaGraphicsResourcesMeta * meta) unregister_cuda_resource (GstGLContext * context,
GstNvDecCudaGraphicsResourceInfo * cgr_info)
{ {
guint i; if (!cuda_OK (cuvidCtxLock (cgr_info->cuda_context->lock, 0)))
if (!cuda_OK (cuvidCtxLock (meta->cuda_context->lock, 0)))
GST_WARNING ("failed to lock CUDA context"); GST_WARNING ("failed to lock CUDA context");
for (i = 0; i < meta->num_resources; i++) { if (!cuda_OK (cuGraphicsUnregisterResource ((const CUgraphicsResource)
if (!cuda_OK (cuGraphicsUnregisterResource ((const CUgraphicsResource) cgr_info->resource)))
meta->resources[i]))) GST_WARNING ("failed to unregister resource");
GST_WARNING ("failed to unregister resource");
}
if (!cuda_OK (cuvidCtxUnlock (meta->cuda_context->lock, 0))) if (!cuda_OK (cuvidCtxUnlock (cgr_info->cuda_context->lock, 0)))
GST_WARNING ("failed to unlock CUDA context"); GST_WARNING ("failed to unlock CUDA context");
meta->num_resources = 0;
g_free (meta->resources);
meta->resources = NULL;
g_object_unref (meta->cuda_context);
meta->cuda_context = NULL;
}
static gboolean
gst_nvdec_cuda_graphics_resources_meta_init (GstMeta * meta, gpointer params,
GstBuffer * buffer)
{
GstNvDecCudaGraphicsResourcesMeta *cgrmeta =
(GstNvDecCudaGraphicsResourcesMeta *) meta;
cgrmeta->cuda_context = NULL;
cgrmeta->resources = NULL;
cgrmeta->num_resources = 0;
return TRUE;
}
static gboolean
gst_nvdec_cuda_graphics_resources_meta_transform (GstBuffer * transbuf,
GstMeta * meta, GstBuffer * buffer, GQuark type, gpointer data)
{
return FALSE;
} }
static void static void
gst_nvdec_cuda_graphics_resources_meta_free (GstMeta * meta, GstBuffer * buffer) free_cgr_info (GstNvDecCudaGraphicsResourceInfo * cgr_info)
{ {
GstMemory *mem = gst_buffer_get_memory (buffer, 0); gst_gl_context_thread_add (cgr_info->gl_context,
gst_gl_context_thread_add (GST_GL_BASE_MEMORY_CAST (mem)->context, (GstGLContextThreadFunc) unregister_cuda_resource, cgr_info);
(GstGLContextThreadFunc) free_cgr_meta, meta); gst_object_unref (cgr_info->gl_context);
gst_memory_unref (mem); g_object_unref (cgr_info->cuda_context);
g_slice_free (GstNvDecCudaGraphicsResourceInfo, cgr_info);
} }
const GstMetaInfo * static CUgraphicsResource
gst_nvdec_cuda_graphics_resources_meta_get_info (void) ensure_cuda_graphics_resource (GstMemory * mem,
{
static const GstMetaInfo *meta_info = NULL;
if (g_once_init_enter ((GstMetaInfo **) & meta_info)) {
const GstMetaInfo *mi =
gst_meta_register (GST_NVDEC_CUDA_GRAPHICS_RESOURCES_META_API_TYPE,
"GstNvDecCudaGraphicsResourcesMeta",
sizeof (GstNvDecCudaGraphicsResourcesMeta),
gst_nvdec_cuda_graphics_resources_meta_init,
gst_nvdec_cuda_graphics_resources_meta_free,
gst_nvdec_cuda_graphics_resources_meta_transform);
g_once_init_leave ((GstMetaInfo **) & meta_info, (GstMetaInfo *) mi);
}
return meta_info;
}
GstNvDecCudaGraphicsResourcesMeta *
gst_buffer_add_nvdec_cuda_graphics_resources_meta (GstBuffer * buffer,
GstNvDecCudaContext * cuda_context) GstNvDecCudaContext * cuda_context)
{ {
GstNvDecCudaGraphicsResourcesMeta *meta; static GQuark quark = 0;
GstMemory *mem; GstNvDecCudaGraphicsResourceInfo *cgr_info;
gpointer args[2];
g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL); if (!gst_is_gl_base_memory (mem)) {
g_return_val_if_fail (gst_buffer_n_memory (buffer) > 0, NULL); GST_WARNING ("memory is not GL base memory");
mem = gst_buffer_get_memory (buffer, 0);
if (!gst_is_gl_memory (mem)) {
GST_WARNING ("memory is not GL memory");
gst_memory_unref (mem);
return NULL; return NULL;
} }
meta = (GstNvDecCudaGraphicsResourcesMeta *) gst_buffer_add_meta (buffer, if (!quark)
GST_NVDEC_CUDA_GRAPHICS_RESOURCES_META_INFO, NULL); quark = g_quark_from_static_string ("GstNvDecCudaGraphicsResourceInfo");
meta->cuda_context = g_object_ref (cuda_context);
gst_gl_context_thread_add (GST_GL_BASE_MEMORY_CAST (mem)->context,
(GstGLContextThreadFunc) add_cgr_meta, buffer);
gst_memory_unref (mem);
return meta; cgr_info = gst_mini_object_get_qdata (GST_MINI_OBJECT (mem), quark);
if (!cgr_info) {
cgr_info = g_slice_new (GstNvDecCudaGraphicsResourceInfo);
cgr_info->gl_context =
gst_object_ref (GST_GL_BASE_MEMORY_CAST (mem)->context);
cgr_info->cuda_context = g_object_ref (cuda_context);
args[0] = mem;
args[1] = cgr_info;
gst_gl_context_thread_add (cgr_info->gl_context,
(GstGLContextThreadFunc) register_cuda_resource, args);
gst_mini_object_set_qdata (GST_MINI_OBJECT (mem), quark, cgr_info,
(GDestroyNotify) free_cgr_info);
}
return cgr_info->resource;
} }
static gboolean gst_nvdec_start (GstVideoDecoder * decoder); static gboolean gst_nvdec_start (GstVideoDecoder * decoder);
@ -647,8 +563,8 @@ copy_video_frame_to_gl_textures (GstGLContext * context, gpointer * args)
{ {
GstNvDec *nvdec = GST_NVDEC (args[0]); GstNvDec *nvdec = GST_NVDEC (args[0]);
CUVIDPARSERDISPINFO *dispinfo = (CUVIDPARSERDISPINFO *) args[1]; CUVIDPARSERDISPINFO *dispinfo = (CUVIDPARSERDISPINFO *) args[1];
GstNvDecCudaGraphicsResourcesMeta *meta = CUgraphicsResource *resources = (CUgraphicsResource *) args[2];
(GstNvDecCudaGraphicsResourcesMeta *) args[2]; guint num_resources = GPOINTER_TO_UINT (args[3]);
CUVIDPROCPARAMS proc_params = { 0, }; CUVIDPROCPARAMS proc_params = { 0, };
CUdeviceptr dptr; CUdeviceptr dptr;
CUarray array; CUarray array;
@ -672,8 +588,7 @@ copy_video_frame_to_gl_textures (GstGLContext * context, gpointer * args)
goto unlock_cuda_context; goto unlock_cuda_context;
} }
if (!cuda_OK (cuGraphicsMapResources (meta->num_resources, meta->resources, if (!cuda_OK (cuGraphicsMapResources (num_resources, resources, NULL))) {
NULL))) {
GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources"); GST_WARNING_OBJECT (nvdec, "failed to map CUDA resources");
goto unmap_video_frame; goto unmap_video_frame;
} }
@ -684,9 +599,9 @@ copy_video_frame_to_gl_textures (GstGLContext * context, gpointer * args)
mcpy2d.dstPitch = nvdec->width; mcpy2d.dstPitch = nvdec->width;
mcpy2d.WidthInBytes = nvdec->width; mcpy2d.WidthInBytes = nvdec->width;
for (i = 0; i < meta->num_resources; i++) { for (i = 0; i < num_resources; i++) {
if (!cuda_OK (cuGraphicsSubResourceGetMappedArray (&array, if (!cuda_OK (cuGraphicsSubResourceGetMappedArray (&array, resources[i], 0,
meta->resources[i], 0, 0))) { 0))) {
GST_WARNING_OBJECT (nvdec, "failed to map CUDA array"); GST_WARNING_OBJECT (nvdec, "failed to map CUDA array");
break; break;
} }
@ -699,8 +614,7 @@ copy_video_frame_to_gl_textures (GstGLContext * context, gpointer * args)
GST_WARNING_OBJECT (nvdec, "memcpy to mapped array failed"); GST_WARNING_OBJECT (nvdec, "memcpy to mapped array failed");
} }
if (!cuda_OK (cuGraphicsUnmapResources (meta->num_resources, meta->resources, if (!cuda_OK (cuGraphicsUnmapResources (num_resources, resources, NULL)))
NULL)))
GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA resources"); GST_WARNING_OBJECT (nvdec, "failed to unmap CUDA resources");
unmap_video_frame: unmap_video_frame:
@ -723,11 +637,11 @@ handle_pending_frames (GstNvDec * nvdec)
GstNvDecQueueItem *item; GstNvDecQueueItem *item;
CUVIDEOFORMAT *format; CUVIDEOFORMAT *format;
GstVideoCodecState *state; GstVideoCodecState *state;
guint width, height, fps_n, fps_d, i; guint width, height, fps_n, fps_d, i, num_resources;
CUVIDPICPARAMS *decode_params; CUVIDPICPARAMS *decode_params;
CUVIDPARSERDISPINFO *dispinfo; CUVIDPARSERDISPINFO *dispinfo;
GstNvDecCudaGraphicsResourcesMeta *meta; CUgraphicsResource *resources;
gpointer args[3]; gpointer args[4];
GstMemory *mem; GstMemory *mem;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
@ -850,32 +764,26 @@ handle_pending_frames (GstNvDec * nvdec)
break; break;
} }
meta = gst_buffer_get_nvdec_cuda_graphics_resources_meta num_resources = gst_buffer_n_memory (pending_frame->output_buffer);
(pending_frame->output_buffer); resources = g_new (CUgraphicsResource, num_resources);
if (!meta) {
meta = gst_buffer_add_nvdec_cuda_graphics_resources_meta
(pending_frame->output_buffer, nvdec->cuda_context);
if (!meta) {
GST_WARNING_OBJECT (nvdec,
"failed to add CUDA graphics resources meta");
break;
}
GST_META_FLAG_SET (meta, GST_META_FLAG_POOLED);
}
args[0] = nvdec; for (i = 0; i < num_resources; i++) {
args[1] = dispinfo; mem = gst_buffer_get_memory (pending_frame->output_buffer, i);
args[2] = meta; resources[i] =
gst_gl_context_thread_add (nvdec->gl_context, ensure_cuda_graphics_resource (mem, nvdec->cuda_context);
(GstGLContextThreadFunc) copy_video_frame_to_gl_textures, args);
for (i = gst_buffer_n_memory (pending_frame->output_buffer); i;) {
mem = gst_buffer_get_memory (pending_frame->output_buffer, --i);
GST_MINI_OBJECT_FLAG_SET (mem, GST_MINI_OBJECT_FLAG_SET (mem,
GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD); GST_GL_BASE_MEMORY_TRANSFER_NEED_DOWNLOAD);
gst_memory_unref (mem); gst_memory_unref (mem);
} }
args[0] = nvdec;
args[1] = dispinfo;
args[2] = resources;
args[3] = GUINT_TO_POINTER (num_resources);
gst_gl_context_thread_add (nvdec->gl_context,
(GstGLContextThreadFunc) copy_video_frame_to_gl_textures, args);
g_free (resources);
if (!dispinfo->progressive_frame) { if (!dispinfo->progressive_frame) {
GST_BUFFER_FLAG_SET (pending_frame->output_buffer, GST_BUFFER_FLAG_SET (pending_frame->output_buffer,
GST_VIDEO_BUFFER_FLAG_INTERLACED); GST_VIDEO_BUFFER_FLAG_INTERLACED);