vaapivideomemory: add support for raw pixels mappings.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Wed, 23 Jul 2014 16:54:13 +0000 (18:54 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Wed, 23 Jul 2014 17:14:47 +0000 (19:14 +0200)
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

gst/vaapi/gstvaapivideomemory.c
gst/vaapi/gstvaapivideomemory.h

index 9c0b5b9..ee85eea 100644 (file)
@@ -35,6 +35,20 @@ GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapivideomemory);
 /* --- 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 *
 new_image(GstVaapiDisplay *display, const GstVideoInfo *vip)
 {
@@ -289,40 +303,98 @@ gst_vaapi_video_memory_reset_surface(GstVaapiVideoMemory *mem)
 static gpointer
 gst_vaapi_video_memory_map(GstVaapiVideoMemory *mem, gsize maxsize, guint flags)
 {
-    if (mem->map_type &&
-        mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE)
-        goto error_incompatible_map;
+    gpointer data;
 
     if (mem->map_count == 0) {
-        gst_vaapi_surface_proxy_replace(&mem->proxy,
-            gst_vaapi_video_meta_get_surface_proxy(mem->meta));
+        switch (flags & GST_MAP_READWRITE) {
+        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)
             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++;
-    return mem->proxy;
+    return data;
 
     /* ERRORS */
-error_incompatible_map:
-    GST_ERROR("failed to map memory to a GstVaapiSurfaceProxy");
+error_unsupported_map:
+    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;
 error_no_surface_proxy:
     GST_ERROR("failed to extract GstVaapiSurfaceProxy from video meta");
     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
 gst_vaapi_video_memory_unmap(GstVaapiVideoMemory *mem)
 {
-    if (mem->map_type &&
-        mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE)
-        goto error_incompatible_map;
-
-    if (--mem->map_count == 0) {
-        gst_vaapi_surface_proxy_replace(&mem->proxy, NULL);
+    if (mem->map_count == 1) {
+        switch (mem->map_type) {
+        case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE:
+            gst_vaapi_surface_proxy_replace(&mem->proxy, NULL);
+            break;
+        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_count--;
     return;
 
     /* ERRORS */
index c28efb8..d58501d 100644 (file)
@@ -51,15 +51,18 @@ typedef struct _GstVaapiVideoAllocatorClass     GstVaapiVideoAllocatorClass;
 /**
  * GstVaapiVideoMemoryMapType:
  * @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_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.
  */
 typedef enum {
     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;
 
 /**