vaapivideomemory: lock map and unmap operations

In order to avoid race condition when two threads call map/unmap the same
VA surface, this patch mutex these operations.

https://bugzilla.gnome.org/show_bug.cgi?id=774213
This commit is contained in:
Víctor Manuel Jáquez Leal 2016-11-09 18:39:06 +01:00
parent 4ae9428072
commit 3fa9af225f
2 changed files with 30 additions and 11 deletions

View file

@ -294,6 +294,7 @@ gboolean
gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane, gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane,
GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags) GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
{ {
gboolean ret = FALSE;
GstAllocator *allocator; GstAllocator *allocator;
GstVaapiVideoMemory *const mem = GstVaapiVideoMemory *const mem =
GST_VAAPI_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0)); GST_VAAPI_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
@ -303,13 +304,14 @@ gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane,
g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE); g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE);
g_return_val_if_fail (mem->meta, FALSE); g_return_val_if_fail (mem->meta, FALSE);
g_mutex_lock (&mem->lock);
if (mem->map_type && mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR) if (mem->map_type && mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR)
goto error_incompatible_map; goto error_incompatible_map;
/* Map for writing */ /* Map for writing */
if (mem->map_count == 0) { if (mem->map_count == 0) {
if (!map_vaapi_memory (mem, flags)) if (!map_vaapi_memory (mem, flags))
return FALSE; goto out;
mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR; mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR;
} }
mem->map_count++; mem->map_count++;
@ -317,13 +319,17 @@ gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane,
*data = gst_vaapi_image_get_plane (mem->image, plane); *data = gst_vaapi_image_get_plane (mem->image, plane);
*stride = gst_vaapi_image_get_pitch (mem->image, plane); *stride = gst_vaapi_image_get_pitch (mem->image, plane);
info->flags = flags; info->flags = flags;
return TRUE; ret = TRUE;
out:
g_mutex_unlock (&mem->lock);
return ret;
/* ERRORS */ /* ERRORS */
error_incompatible_map: error_incompatible_map:
{ {
GST_ERROR ("incompatible map type (%d)", mem->map_type); GST_ERROR ("incompatible map type (%d)", mem->map_type);
return FALSE; goto out;
} }
} }
@ -342,6 +348,7 @@ gst_video_meta_unmap_vaapi_memory (GstVideoMeta * meta, guint plane,
g_return_val_if_fail (mem->surface, FALSE); g_return_val_if_fail (mem->surface, FALSE);
g_return_val_if_fail (mem->image, FALSE); g_return_val_if_fail (mem->image, FALSE);
g_mutex_lock (&mem->lock);
if (--mem->map_count == 0) { if (--mem->map_count == 0) {
mem->map_type = 0; mem->map_type = 0;
@ -349,6 +356,7 @@ gst_video_meta_unmap_vaapi_memory (GstVideoMeta * meta, guint plane,
if (info->flags & GST_MAP_READWRITE) if (info->flags & GST_MAP_READWRITE)
unmap_vaapi_memory (mem, info->flags); unmap_vaapi_memory (mem, info->flags);
} }
g_mutex_unlock (&mem->lock);
return TRUE; return TRUE;
} }
@ -381,6 +389,7 @@ gst_vaapi_video_memory_new (GstAllocator * base_allocator,
mem->map_type = 0; mem->map_type = 0;
mem->map_count = 0; mem->map_count = 0;
mem->usage_flag = allocator->usage_flag; mem->usage_flag = allocator->usage_flag;
g_mutex_init (&mem->lock);
GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem, GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem,
GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT); GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT);
@ -395,6 +404,7 @@ gst_vaapi_video_memory_free (GstVaapiVideoMemory * mem)
gst_vaapi_surface_proxy_replace (&mem->proxy, NULL); gst_vaapi_surface_proxy_replace (&mem->proxy, NULL);
gst_vaapi_video_meta_replace (&mem->meta, NULL); gst_vaapi_video_meta_replace (&mem->meta, NULL);
gst_object_unref (GST_MEMORY_CAST (mem)->allocator); gst_object_unref (GST_MEMORY_CAST (mem)->allocator);
g_mutex_clear (&mem->lock);
g_slice_free (GstVaapiVideoMemory, mem); g_slice_free (GstVaapiVideoMemory, mem);
} }
@ -442,11 +452,12 @@ static gpointer
gst_vaapi_video_memory_map (GstVaapiVideoMemory * mem, gsize maxsize, gst_vaapi_video_memory_map (GstVaapiVideoMemory * mem, gsize maxsize,
guint flags) guint flags)
{ {
gpointer data; gpointer data = NULL;
g_return_val_if_fail (mem, NULL); g_return_val_if_fail (mem, NULL);
g_return_val_if_fail (mem->meta, NULL); g_return_val_if_fail (mem->meta, NULL);
g_mutex_lock (&mem->lock);
if (mem->map_count == 0) { if (mem->map_count == 0) {
switch (flags & GST_MAP_READWRITE) { switch (flags & GST_MAP_READWRITE) {
case 0: case 0:
@ -461,7 +472,7 @@ gst_vaapi_video_memory_map (GstVaapiVideoMemory * mem, gsize maxsize,
break; break;
case GST_MAP_READ: case GST_MAP_READ:
if (!map_vaapi_memory (mem, flags)) if (!map_vaapi_memory (mem, flags))
return NULL; goto out;
mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR; mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR;
break; break;
default: default:
@ -484,39 +495,43 @@ gst_vaapi_video_memory_map (GstVaapiVideoMemory * mem, gsize maxsize,
goto error_unsupported_map_type; goto error_unsupported_map_type;
} }
mem->map_count++; mem->map_count++;
out:
g_mutex_unlock (&mem->lock);
return data; return data;
/* ERRORS */ /* ERRORS */
error_unsupported_map: error_unsupported_map:
{ {
GST_ERROR ("unsupported map flags (0x%x)", flags); GST_ERROR ("unsupported map flags (0x%x)", flags);
return NULL; goto out;
} }
error_unsupported_map_type: error_unsupported_map_type:
{ {
GST_ERROR ("unsupported map type (%d)", mem->map_type); GST_ERROR ("unsupported map type (%d)", mem->map_type);
return NULL; goto out;
} }
error_no_surface_proxy: error_no_surface_proxy:
{ {
GST_ERROR ("failed to extract GstVaapiSurfaceProxy from video meta"); GST_ERROR ("failed to extract GstVaapiSurfaceProxy from video meta");
return NULL; goto out;
} }
error_no_current_surface: error_no_current_surface:
{ {
GST_ERROR ("failed to make surface current"); GST_ERROR ("failed to make surface current");
return NULL; goto out;
} }
error_no_image: error_no_image:
{ {
GST_ERROR ("failed to extract VA image from video buffer"); GST_ERROR ("failed to extract VA image from video buffer");
return NULL; goto out;
} }
} }
static void static void
gst_vaapi_video_memory_unmap_full (GstVaapiVideoMemory * mem, GstMapInfo * info) gst_vaapi_video_memory_unmap_full (GstVaapiVideoMemory * mem, GstMapInfo * info)
{ {
g_mutex_lock (&mem->lock);
if (mem->map_count == 1) { if (mem->map_count == 1) {
switch (mem->map_type) { switch (mem->map_type) {
case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE:
@ -531,13 +546,16 @@ gst_vaapi_video_memory_unmap_full (GstVaapiVideoMemory * mem, GstMapInfo * info)
mem->map_type = 0; mem->map_type = 0;
} }
mem->map_count--; mem->map_count--;
out:
g_mutex_unlock (&mem->lock);
return; return;
/* ERRORS */ /* ERRORS */
error_incompatible_map: error_incompatible_map:
{ {
GST_ERROR ("incompatible map type (%d)", mem->map_type); GST_ERROR ("incompatible map type (%d)", mem->map_type);
return; goto out;
} }
} }

View file

@ -127,6 +127,7 @@ struct _GstVaapiVideoMemory
guint map_type; guint map_type;
gint map_count; gint map_count;
GstVaapiImageUsageFlags usage_flag; GstVaapiImageUsageFlags usage_flag;
GMutex lock;
}; };
G_GNUC_INTERNAL G_GNUC_INTERNAL