Add gst_vaapi_surface_{,de}associate_subpicture() API.
authorgb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Tue, 23 Mar 2010 10:36:20 +0000 (10:36 +0000)
committergb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Tue, 23 Mar 2010 10:36:20 +0000 (10:36 +0000)
docs/reference/libs/libs-sections.txt
gst-libs/gst/vaapi/gstvaapisurface.c
gst-libs/gst/vaapi/gstvaapisurface.h
tests/test-windows.c

index 9178ba7..2ca4349 100644 (file)
@@ -242,6 +242,8 @@ gst_vaapi_surface_get_size
 gst_vaapi_surface_derive_image
 gst_vaapi_surface_get_image
 gst_vaapi_surface_put_image
+gst_vaapi_surface_associate_subpicture
+gst_vaapi_surface_deassociate_subpicture
 gst_vaapi_surface_sync
 <SUBSECTION Standard>
 GST_VAAPI_SURFACE
index b82b40d..eca7b95 100644 (file)
@@ -45,6 +45,7 @@ struct _GstVaapiSurfacePrivate {
     guint               width;
     guint               height;
     GstVaapiChromaType  chroma_type;
+    GPtrArray          *subpictures;
 };
 
 enum {
@@ -58,6 +59,12 @@ enum {
 };
 
 static void
+destroy_subpicture_cb(gpointer subpicture, gpointer user_data)
+{
+    g_object_unref(subpicture);
+}
+
+static void
 gst_vaapi_surface_destroy(GstVaapiSurface *surface)
 {
     GstVaapiSurfacePrivate * const priv = surface->priv;
@@ -75,6 +82,12 @@ gst_vaapi_surface_destroy(GstVaapiSurface *surface)
         priv->surface_id = VA_INVALID_SURFACE;
     }
 
+    if (priv->subpictures) {
+        g_ptr_array_foreach(priv->subpictures, destroy_subpicture_cb, NULL);
+        g_ptr_array_free(priv->subpictures, TRUE);
+        priv->subpictures = NULL;
+    }
+
     if (priv->display) {
         g_object_unref(priv->display);
         priv->display = NULL;
@@ -282,6 +295,7 @@ gst_vaapi_surface_init(GstVaapiSurface *surface)
     priv->width         = 0;
     priv->height        = 0;
     priv->chroma_type   = 0;
+    priv->subpictures   = NULL;
 }
 
 /**
@@ -554,6 +568,130 @@ gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image)
 }
 
 /**
+ * gst_vaapi_surface_associate_subpicture:
+ * @surface: a #GstVaapiSurface
+ * @subpicture: a #GstVaapiSubpicture
+ * @src_rect: (allow-none): the sub-rectangle of the source subpicture
+ *   image to extract and process. If %NULL, the entire image will be used.
+ * @dst_rect: (allow-none): the sub-rectangle of the destination
+ *   surface into which the image is rendered. If %NULL, the entire
+ *   surface will be used.
+ *
+ * Associates the @subpicture with the @surface. The @src_rect
+ * coordinates and size are relative to the source image bound to
+ * @subpicture. The @dst_rect coordinates and size are relative to the
+ * target @surface.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_associate_subpicture(
+    GstVaapiSurface         *surface,
+    GstVaapiSubpicture      *subpicture,
+    const GstVaapiRectangle *src_rect,
+    const GstVaapiRectangle *dst_rect
+)
+{
+    GstVaapiRectangle src_rect_default, dst_rect_default;
+    GstVaapiImage *image;
+    VAStatus status;
+
+    g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
+    g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
+
+    if (!gst_vaapi_surface_deassociate_subpicture(surface, subpicture))
+        return FALSE;
+
+    if (!surface->priv->subpictures) {
+        surface->priv->subpictures = g_ptr_array_new();
+        if (!surface->priv->subpictures)
+            return FALSE;
+    }
+
+    if (!src_rect) {
+        image = gst_vaapi_subpicture_get_image(subpicture);
+        if (!image)
+            return FALSE;
+        src_rect                = &src_rect_default;
+        src_rect_default.x      = 0;
+        src_rect_default.y      = 0;
+        gst_vaapi_image_get_size(
+            image,
+            &src_rect_default.width,
+            &src_rect_default.height
+        );
+    }
+
+    if (!dst_rect) {
+        dst_rect                = &dst_rect_default;
+        dst_rect_default.x      = 0;
+        dst_rect_default.y      = 0;
+        dst_rect_default.width  = surface->priv->width;
+        dst_rect_default.height = surface->priv->height;
+    }
+
+    GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
+    status = vaAssociateSubpicture(
+        GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
+        gst_vaapi_subpicture_get_id(subpicture),
+        &surface->priv->surface_id, 1,
+        src_rect->x, src_rect->y, src_rect->width, src_rect->height,
+        dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
+        0
+    );
+    GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
+    if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
+        return FALSE;
+
+    g_ptr_array_add(surface->priv->subpictures, g_object_ref(subpicture));
+    return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_deassociate_subpicture:
+ * @surface: a #GstVaapiSurface
+ * @subpicture: a #GstVaapiSubpicture
+ *
+ * Deassociates @subpicture from @surface. Other associations are kept.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_deassociate_subpicture(
+    GstVaapiSurface         *surface,
+    GstVaapiSubpicture      *subpicture
+)
+{
+    VAStatus status;
+
+    g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
+    g_return_val_if_fail(GST_VAAPI_IS_SUBPICTURE(subpicture), FALSE);
+
+    if (!surface->priv->subpictures)
+        return TRUE;
+
+    /* First, check subpicture was really associated with this surface */
+    if (!g_ptr_array_remove_fast(surface->priv->subpictures, subpicture)) {
+        GST_DEBUG("subpicture 0x%08x was not bound to surface 0x%08x",
+                  gst_vaapi_subpicture_get_id(subpicture),
+                  surface->priv->surface_id);
+        return TRUE;
+    }
+
+    GST_VAAPI_DISPLAY_LOCK(surface->priv->display);
+    status = vaDeassociateSubpicture(
+        GST_VAAPI_DISPLAY_VADISPLAY(surface->priv->display),
+        gst_vaapi_subpicture_get_id(subpicture),
+        &surface->priv->surface_id, 1
+    );
+    GST_VAAPI_DISPLAY_UNLOCK(surface->priv->display);
+    g_object_unref(subpicture);
+    if (!vaapi_check_status(status, "vaDeassociateSubpicture()"))
+        return FALSE;
+    return TRUE;
+}
+
+/**
  * gst_vaapi_surface_sync:
  * @surface: a #GstVaapiSurface
  *
index 4a48438..2a8d722 100644 (file)
 #ifndef GST_VAAPI_SURFACE_H
 #define GST_VAAPI_SURFACE_H
 
-#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/vaapi/gstvaapitypes.h>
 #include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/vaapi/gstvaapisubpicture.h>
 
 G_BEGIN_DECLS
 
@@ -163,6 +165,20 @@ gboolean
 gst_vaapi_surface_put_image(GstVaapiSurface *surface, GstVaapiImage *image);
 
 gboolean
+gst_vaapi_surface_associate_subpicture(
+    GstVaapiSurface         *surface,
+    GstVaapiSubpicture      *subpicture,
+    const GstVaapiRectangle *src_rect,
+    const GstVaapiRectangle *dst_rect
+);
+
+gboolean
+gst_vaapi_surface_deassociate_subpicture(
+    GstVaapiSurface         *surface,
+    GstVaapiSubpicture      *subpicture
+);
+
+gboolean
 gst_vaapi_surface_sync(GstVaapiSurface *surface);
 
 G_END_DECLS
index 6813c94..cea4d18 100644 (file)
@@ -39,6 +39,77 @@ typedef void (*DrawRectFunc)(
     guint32 color
 );
 
+static void draw_rect_ARGB(
+    guchar *pixels[3],
+    guint   stride[3],
+    gint    x,
+    gint    y,
+    guint   width,
+    guint   height,
+    guint32 color
+)
+{
+    guint i, j;
+
+    color = GUINT32_TO_BE(color);
+
+    for (j = 0; j < height; j++) {
+        guint32 *p = (guint32 *)(pixels[0] + (y + j) * stride[0] + x * 4);
+        for (i = 0; i < width; i++)
+            p[i] = color;
+    }
+}
+
+static void draw_rect_BGRA(
+    guchar *pixels[3],
+    guint   stride[3],
+    gint    x,
+    gint    y,
+    guint   width,
+    guint   height,
+    guint32 color
+)
+{
+    // Converts ARGB color to BGRA
+    color = GUINT32_SWAP_LE_BE(color);
+
+    draw_rect_ARGB(pixels, stride, x, y, width, height, color);
+}
+
+static void draw_rect_RGBA(
+    guchar *pixels[3],
+    guint   stride[3],
+    gint    x,
+    gint    y,
+    guint   width,
+    guint   height,
+    guint32 color
+)
+{
+    // Converts ARGB color to RGBA
+    color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8);
+
+    draw_rect_ARGB(pixels, stride, x, y, width, height, color);
+}
+
+static void draw_rect_ABGR(
+    guchar *pixels[3],
+    guint   stride[3],
+    gint    x,
+    gint    y,
+    guint   width,
+    guint   height,
+    guint32 color
+)
+{
+    // Converts ARGB color to ABGR
+    color = ((color & 0xff00ff00)   |
+             ((color >> 16) & 0xff) |
+             ((color & 0xff) << 16));
+
+    draw_rect_ARGB(pixels, stride, x, y, width, height, color);
+}
+
 static void draw_rect_NV12( // Y, UV planes
     guchar *pixels[3],
     guint   stride[3],
@@ -122,6 +193,25 @@ static gboolean draw_rgb_rects(GstVaapiImage *image)
         return FALSE;
 
     switch (format) {
+    case GST_VAAPI_IMAGE_ARGB:
+        draw_rect   = draw_rect_ARGB;
+        goto RGB_colors;
+    case GST_VAAPI_IMAGE_BGRA:
+        draw_rect   = draw_rect_BGRA;
+        goto RGB_colors;
+    case GST_VAAPI_IMAGE_RGBA:
+        draw_rect   = draw_rect_RGBA;
+        goto RGB_colors;
+    case GST_VAAPI_IMAGE_ABGR:
+        draw_rect   = draw_rect_ABGR;
+    RGB_colors:
+        pixels[0]   = gst_vaapi_image_get_plane(image, 0);
+        stride[0]   = gst_vaapi_image_get_pitch(image, 0);
+        red_color   = 0xffff0000;
+        green_color = 0xff00ff00;
+        blue_color  = 0xff0000ff;
+        black_color = 0xff000000;
+        break;
     case GST_VAAPI_IMAGE_NV12:
         draw_rect   = draw_rect_NV12;
         pixels[0]   = gst_vaapi_image_get_plane(image, 0);
@@ -171,10 +261,11 @@ static gboolean draw_rgb_rects(GstVaapiImage *image)
 int
 main(int argc, char *argv[])
 {
-    GstVaapiDisplay *display;
-    GstVaapiWindow  *window;
-    GstVaapiSurface *surface;
-    GstVaapiImage   *image = NULL;
+    GstVaapiDisplay    *display;
+    GstVaapiWindow     *window;
+    GstVaapiSurface    *surface;
+    GstVaapiImage      *image      = NULL;
+    GstVaapiSubpicture *subpicture = NULL;
     GstVaapiImageFormat format;
     guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
     guint i;
@@ -183,6 +274,10 @@ main(int argc, char *argv[])
         GST_VAAPI_IMAGE_NV12,
         GST_VAAPI_IMAGE_YV12,
         GST_VAAPI_IMAGE_I420,
+        GST_VAAPI_IMAGE_ARGB,
+        GST_VAAPI_IMAGE_BGRA,
+        GST_VAAPI_IMAGE_RGBA,
+        GST_VAAPI_IMAGE_ABGR,
         0
     };
 
@@ -215,8 +310,19 @@ main(int argc, char *argv[])
     if (!draw_rgb_rects(image))
         g_error("could not draw RGB rectangles");
 
-    if (!gst_vaapi_surface_put_image(surface, image))
-        g_error("could not upload image");
+    if (gst_vaapi_image_format_is_rgb(format)) {
+        subpicture = gst_vaapi_subpicture_new(image);
+        if (!subpicture)
+            g_error("could not create Gst/VA subpicture");
+
+        if (!gst_vaapi_surface_associate_subpicture(surface, subpicture,
+                                                    NULL, NULL))
+            g_error("could not associate subpicture to surface");
+    }
+    else {
+        if (!gst_vaapi_surface_put_image(surface, image))
+            g_error("could not upload image");
+    }
 
     if (!gst_vaapi_surface_sync(surface))
         g_error("could not complete image upload");
@@ -277,6 +383,8 @@ main(int argc, char *argv[])
         XDestroyWindow(dpy, win);
     }
 
+    if (subpicture)
+        g_object_unref(subpicture);
     g_object_unref(image);
     g_object_unref(surface);
     g_object_unref(display);