vaapivideomemory: add support for raw pixels mappings.

Allow raw pixels of the whole frame to be mapped read-only. i.e. in
cases where the buffer pool is allocated without VideoMeta API, thus
individual planes cannot be mapped.

This is initial support for Firefox >= 30.

https://bugzilla.gnome.org/show_bug.cgi?id=731886
This commit is contained in:
Gwenole Beauchesne 2014-07-23 18:54:13 +02:00
parent 9cb3acc813
commit 9cad85a936
2 changed files with 92 additions and 17 deletions

View file

@ -35,6 +35,20 @@ GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapivideomemory);
/* --- GstVaapiVideoMemory --- */ /* --- GstVaapiVideoMemory --- */
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static guchar *
get_image_data(GstVaapiImage *image)
{
guchar *data;
VAImage va_image;
data = gst_vaapi_image_get_plane(image, 0);
if (!data || !gst_vaapi_image_get_image(image, &va_image))
return NULL;
data -= va_image.offsets[0];
return data;
}
static GstVaapiImage * static GstVaapiImage *
new_image(GstVaapiDisplay *display, const GstVideoInfo *vip) new_image(GstVaapiDisplay *display, const GstVideoInfo *vip)
{ {
@ -289,40 +303,98 @@ gst_vaapi_video_memory_reset_surface(GstVaapiVideoMemory *mem)
static gpointer static gpointer
gst_vaapi_video_memory_map(GstVaapiVideoMemory *mem, gsize maxsize, guint flags) gst_vaapi_video_memory_map(GstVaapiVideoMemory *mem, gsize maxsize, guint flags)
{ {
if (mem->map_type && gpointer data;
mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE)
goto error_incompatible_map;
if (mem->map_count == 0) { if (mem->map_count == 0) {
gst_vaapi_surface_proxy_replace(&mem->proxy, switch (flags & GST_MAP_READWRITE) {
gst_vaapi_video_meta_get_surface_proxy(mem->meta)); case 0:
// No flags set: return a GstVaapiSurfaceProxy
gst_vaapi_surface_proxy_replace(&mem->proxy,
gst_vaapi_video_meta_get_surface_proxy(mem->meta));
if (!mem->proxy)
goto error_no_surface_proxy;
mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE;
break;
case GST_MAP_READ:
// Only read flag set: return raw pixels
if (!ensure_surface(mem))
return NULL;
if (!ensure_image(mem))
goto error_ensure_image;
if (!mem->use_direct_rendering)
gst_vaapi_surface_get_image(mem->surface, mem->image);
if (!gst_vaapi_image_map(mem->image))
goto error_map_image;
mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR;
break;
default:
goto error_unsupported_map;
}
}
switch (mem->map_type) {
case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE:
if (!mem->proxy) if (!mem->proxy)
goto error_no_surface_proxy; goto error_no_surface_proxy;
mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE; data = mem->proxy;
break;
case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR:
if (!mem->image)
goto error_no_image;
data = get_image_data(mem->image);
break;
default:
goto error_unsupported_map_type;
} }
mem->map_count++; mem->map_count++;
return mem->proxy; return data;
/* ERRORS */ /* ERRORS */
error_incompatible_map: error_unsupported_map:
GST_ERROR("failed to map memory to a GstVaapiSurfaceProxy"); GST_ERROR("unsupported map flags (0x%x)", flags);
return NULL;
error_unsupported_map_type:
GST_ERROR("unsupported map type (%d)", mem->map_type);
return NULL; return NULL;
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; return NULL;
error_no_image:
GST_ERROR("failed to extract raw pixels from mapped VA image");
return NULL;
error_ensure_image:
{
const GstVideoInfo * const vip = mem->image_info;
GST_ERROR("failed to create %s image of size %ux%u",
GST_VIDEO_INFO_FORMAT_STRING(vip),
GST_VIDEO_INFO_WIDTH(vip), GST_VIDEO_INFO_HEIGHT(vip));
return FALSE;
}
error_map_image:
{
GST_ERROR("failed to map image %" GST_VAAPI_ID_FORMAT,
GST_VAAPI_ID_ARGS(gst_vaapi_image_get_id(mem->image)));
return FALSE;
}
} }
static void static void
gst_vaapi_video_memory_unmap(GstVaapiVideoMemory *mem) gst_vaapi_video_memory_unmap(GstVaapiVideoMemory *mem)
{ {
if (mem->map_type && if (mem->map_count == 1) {
mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE) switch (mem->map_type) {
goto error_incompatible_map; case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE:
gst_vaapi_surface_proxy_replace(&mem->proxy, NULL);
if (--mem->map_count == 0) { break;
gst_vaapi_surface_proxy_replace(&mem->proxy, NULL); case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR:
gst_vaapi_image_unmap(mem->image);
break;
default:
goto error_incompatible_map;
}
mem->map_type = 0; mem->map_type = 0;
} }
mem->map_count--;
return; return;
/* ERRORS */ /* ERRORS */

View file

@ -51,15 +51,18 @@ typedef struct _GstVaapiVideoAllocatorClass GstVaapiVideoAllocatorClass;
/** /**
* GstVaapiVideoMemoryMapType: * GstVaapiVideoMemoryMapType:
* @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: map with gst_buffer_map() * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: map with gst_buffer_map()
* as a whole and return a #GstVaapiSurfaceProxy * and flags = 0x00 to return a #GstVaapiSurfaceProxy
* @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR: map individual plane with * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR: map individual plane with
* gst_video_frame_map() * gst_video_frame_map()
* @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR: map with gst_buffer_map()
* and flags = GST_MAP_READ to return the raw pixels of the whole image
* *
* The set of all #GstVaapiVideoMemory map types. * The set of all #GstVaapiVideoMemory map types.
*/ */
typedef enum { typedef enum {
GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE = 1, GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE = 1,
GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR,
GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR
} GstVaapiVideoMemoryMapType; } GstVaapiVideoMemoryMapType;
/** /**