x11: implement pixmap API.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 19 Jul 2013 13:05:34 +0000 (15:05 +0200)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Mon, 22 Jul 2013 13:45:10 +0000 (15:45 +0200)
Implement the new render-to-pixmap API. The only supported pixmap format
that will work is xRGB, with native byte ordering. Others might work but
they were not tested.

docs/reference/libs/libs-docs.xml.in
docs/reference/libs/libs-sections.txt
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/gstvaapidisplay_x11.c
gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h
gst-libs/gst/vaapi/gstvaapipixmap_x11.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapipixmap_x11.h [new file with mode: 0644]

index 24c9e83..f8940f8 100644 (file)
@@ -17,6 +17,7 @@
     <xi:include href="xml/gstvaapiwindow_x11.xml"/>
     <xi:include href="xml/gstvaapiwindow_glx.xml"/>
     <xi:include href="xml/gstvaapipixmap.xml"/>
+    <xi:include href="xml/gstvaapipixmap_x11.xml"/>
     <xi:include href="xml/gstvaapiobject.xml"/>
     <xi:include href="xml/gstvaapisurface.xml"/>
     <xi:include href="xml/gstvaapiimage.xml"/>
index 4544f66..e619f19 100644 (file)
@@ -66,6 +66,19 @@ GST_VAAPI_WINDOW_X11
 </SECTION>
 
 <SECTION>
+<FILE>gstvaapipixmap_x11</FILE>
+<TITLE>GstVaapiPixmapX11</TITLE>
+GstVaapiPixmapX11
+GST_VAAPI_PIXMAP_XPIXMAP
+gst_vaapi_pixmap_x11_new
+gst_vaapi_pixmap_x11_new_with_xid
+gst_vaapi_pixmap_x11_get_xid
+gst_vaapi_pixmap_x11_is_foreign_xid
+<SUBSECTION Standard>
+GST_VAAPI_WINDOW_X11
+</SECTION>
+
+<SECTION>
 <FILE>gstvaapidisplay_glx</FILE>
 <TITLE>GstVaapiDisplayGLX</TITLE>
 GstVaapiDisplayGLX
index 57e49c1..b2a5df5 100644 (file)
@@ -149,6 +149,7 @@ libgstvaapi_drm_source_priv_h =                     \
 
 libgstvaapi_x11_source_c =                     \
        gstvaapidisplay_x11.c                   \
+       gstvaapipixmap_x11.c                    \
        gstvaapiutils.c                         \
        gstvaapiutils_x11.c                     \
        gstvaapiwindow_x11.c                    \
@@ -156,6 +157,7 @@ libgstvaapi_x11_source_c =                  \
 
 libgstvaapi_x11_source_h =                     \
        gstvaapidisplay_x11.h                   \
+       gstvaapipixmap_x11.h                    \
        gstvaapiwindow_x11.h                    \
        $(NULL)
 
index 10f3dfb..5fb0cba 100644 (file)
@@ -203,6 +203,11 @@ gst_vaapi_display_x11_close_display(GstVaapiDisplay *display)
     GstVaapiDisplayX11Private * const priv =
         GST_VAAPI_DISPLAY_X11_PRIVATE(display);
 
+    if (priv->pixmap_formats) {
+        g_array_free(priv->pixmap_formats, TRUE);
+        priv->pixmap_formats = NULL;
+    }
+
     if (priv->x11_display) {
         if (!priv->use_foreign_display)
             XCloseDisplay(priv->x11_display);
@@ -478,3 +483,113 @@ gst_vaapi_display_x11_set_synchronous(GstVaapiDisplayX11 *display,
 
     set_synchronous(display, synchronous);
 }
+
+typedef struct _GstVaapiPixmapFormatX11 GstVaapiPixmapFormatX11;
+struct _GstVaapiPixmapFormatX11 {
+    GstVideoFormat      format;
+    gint                depth;
+    gint                bpp;
+};
+
+static GstVideoFormat
+pix_fmt_to_video_format(gint depth, gint bpp)
+{
+    GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
+
+    switch (bpp) {
+    case 16:
+        if (depth == 15)
+            format = GST_VIDEO_FORMAT_RGB15;
+        else if (depth == 16)
+            format = GST_VIDEO_FORMAT_RGB16;
+        break;
+    case 24:
+        if (depth == 24)
+            format = GST_VIDEO_FORMAT_RGB;
+        break;
+    case 32:
+        if (depth == 24 || depth == 32)
+            format = GST_VIDEO_FORMAT_xRGB;
+        break;
+    }
+    return format;
+}
+
+static gboolean
+ensure_pix_fmts(GstVaapiDisplayX11 *display)
+{
+    GstVaapiDisplayX11Private * const priv =
+        GST_VAAPI_DISPLAY_X11_PRIVATE(display);
+    XPixmapFormatValues *pix_fmts;
+    int i, n, num_pix_fmts;
+
+    if (priv->pixmap_formats)
+        return TRUE;
+
+    GST_VAAPI_DISPLAY_LOCK(display);
+    pix_fmts = XListPixmapFormats(GST_VAAPI_DISPLAY_XDISPLAY(display),
+        &num_pix_fmts);
+    GST_VAAPI_DISPLAY_UNLOCK(display);
+    if (!pix_fmts)
+        return FALSE;
+
+    priv->pixmap_formats = g_array_sized_new(FALSE, FALSE,
+        sizeof(GstVaapiPixmapFormatX11), num_pix_fmts);
+    if (!priv->pixmap_formats) {
+        XFree(pix_fmts);
+        return FALSE;
+    }
+
+    for (i = 0, n = 0; i < num_pix_fmts; i++) {
+        GstVaapiPixmapFormatX11 * const pix_fmt =
+            &g_array_index(priv->pixmap_formats, GstVaapiPixmapFormatX11, n);
+
+        pix_fmt->depth  = pix_fmts[i].depth;
+        pix_fmt->bpp    = pix_fmts[i].bits_per_pixel;
+        pix_fmt->format = pix_fmt_to_video_format(pix_fmt->depth, pix_fmt->bpp);
+        if (pix_fmt->format != GST_VIDEO_FORMAT_UNKNOWN)
+            n++;
+    }
+    priv->pixmap_formats->len = n;
+    return TRUE;
+}
+
+/* Determine the GstVideoFormat based on a supported Pixmap depth */
+GstVideoFormat
+gst_vaapi_display_x11_get_pixmap_format(GstVaapiDisplayX11 *display,
+    guint depth)
+{
+    if (ensure_pix_fmts(display)) {
+        GstVaapiDisplayX11Private * const priv =
+            GST_VAAPI_DISPLAY_X11_PRIVATE(display);
+        guint i;
+
+        for (i = 0; i < priv->pixmap_formats->len; i++) {
+            GstVaapiPixmapFormatX11 * const pix_fmt = &g_array_index(
+                priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
+            if (pix_fmt->depth == depth)
+                return pix_fmt->format;
+        }
+    }
+    return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+/* Determine the Pixmap depth based on a GstVideoFormat */
+guint
+gst_vaapi_display_x11_get_pixmap_depth(GstVaapiDisplayX11 *display,
+    GstVideoFormat format)
+{
+    if (ensure_pix_fmts(display)) {
+        GstVaapiDisplayX11Private * const priv =
+            GST_VAAPI_DISPLAY_X11_PRIVATE(display);
+        guint i;
+
+        for (i = 0; i < priv->pixmap_formats->len; i++) {
+            GstVaapiPixmapFormatX11 * const pix_fmt = &g_array_index(
+                priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
+            if (pix_fmt->format == format)
+                return pix_fmt->depth;
+        }
+    }
+    return 0;
+}
index 843950b..0593317 100644 (file)
@@ -67,6 +67,7 @@ struct _GstVaapiDisplayX11Private {
     gchar              *display_name;
     Display            *x11_display;
     int                 x11_screen;
+    GArray             *pixmap_formats;
     guint               use_foreign_display     : 1; // Foreign native_display?
     guint               use_xrandr              : 1;
     guint               synchronous             : 1;
@@ -97,6 +98,16 @@ struct _GstVaapiDisplayX11Class {
 void
 gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass);
 
+G_GNUC_INTERNAL
+GstVideoFormat
+gst_vaapi_display_x11_get_pixmap_format(GstVaapiDisplayX11 *display,
+    guint depth);
+
+G_GNUC_INTERNAL
+guint
+gst_vaapi_display_x11_get_pixmap_depth(GstVaapiDisplayX11 *display,
+    GstVideoFormat format);
+
 G_END_DECLS
 
 #endif /* GST_VAAPI_DISPLAY_X11_PRIV_H */
diff --git a/gst-libs/gst/vaapi/gstvaapipixmap_x11.c b/gst-libs/gst/vaapi/gstvaapipixmap_x11.c
new file mode 100644 (file)
index 0000000..eed11dd
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ *  gstvaapipixmap_x11.c - X11 pixmap abstraction
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapipixmap_x11
+ * @short_description: X11 pixmap abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapipixmap_x11.h"
+#include "gstvaapipixmap_priv.h"
+#include "gstvaapidisplay_x11.h"
+#include "gstvaapidisplay_x11_priv.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_x11.h"
+#include "gstvaapisurface_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+typedef struct _GstVaapiPixmapX11Class          GstVaapiPixmapX11Class;
+
+struct _GstVaapiPixmapX11 {
+    GstVaapiPixmap      parent_instance;
+};
+
+struct _GstVaapiPixmapX11Class {
+    GstVaapiPixmapClass parent_class;
+};
+
+static gboolean
+gst_vaapi_pixmap_x11_create_from_xid(GstVaapiPixmap *pixmap, Pixmap xid)
+{
+    guint depth;
+    gboolean success;
+
+    if (!xid)
+        return FALSE;
+
+    GST_VAAPI_OBJECT_LOCK_DISPLAY(pixmap);
+    success = x11_get_geometry(GST_VAAPI_OBJECT_XDISPLAY(pixmap), xid,
+        NULL, NULL, &pixmap->width, &pixmap->height, &depth);
+    GST_VAAPI_OBJECT_UNLOCK_DISPLAY(pixmap);
+    if (!success)
+        return FALSE;
+
+    pixmap->format = gst_vaapi_display_x11_get_pixmap_format(
+        GST_VAAPI_DISPLAY_X11(GST_VAAPI_OBJECT_DISPLAY(pixmap)), depth);
+    if (pixmap->format == GST_VIDEO_FORMAT_UNKNOWN)
+        return FALSE;
+    return TRUE;
+}
+
+static gboolean
+gst_vaapi_pixmap_x11_create(GstVaapiPixmap *pixmap)
+{
+    GstVaapiDisplayX11 * const display =
+        GST_VAAPI_DISPLAY_X11(GST_VAAPI_OBJECT_DISPLAY(pixmap));
+    Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(display);
+    Window rootwin;
+    Pixmap xid;
+    guint depth;
+
+    if (pixmap->use_foreign_pixmap)
+        return gst_vaapi_pixmap_x11_create_from_xid(pixmap,
+            GST_VAAPI_OBJECT_ID(pixmap));
+
+    depth = gst_vaapi_display_x11_get_pixmap_depth(display, pixmap->format);
+    if (!depth)
+        return FALSE;
+
+    GST_VAAPI_OBJECT_LOCK_DISPLAY(pixmap);
+    rootwin = RootWindow(dpy, GST_VAAPI_DISPLAY_XSCREEN(display));
+    xid = XCreatePixmap(dpy, rootwin, pixmap->width, pixmap->height, depth);
+    GST_VAAPI_OBJECT_UNLOCK_DISPLAY(pixmap);
+
+    GST_DEBUG("xid %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS(xid));
+    GST_VAAPI_OBJECT_ID(pixmap) = xid;
+    return xid != None;
+}
+
+static void
+gst_vaapi_pixmap_x11_destroy(GstVaapiPixmap *pixmap)
+{
+    Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(pixmap);
+    const Pixmap xid = GST_VAAPI_OBJECT_ID(pixmap);
+
+    if (xid) {
+        if (!pixmap->use_foreign_pixmap) {
+            GST_VAAPI_OBJECT_LOCK_DISPLAY(pixmap);
+            XFreePixmap(dpy, xid);
+            GST_VAAPI_OBJECT_UNLOCK_DISPLAY(pixmap);
+        }
+        GST_VAAPI_OBJECT_ID(pixmap) = None;
+    }
+}
+
+static gboolean
+gst_vaapi_pixmap_x11_render(GstVaapiPixmap *pixmap, GstVaapiSurface *surface,
+    const GstVaapiRectangle *crop_rect, guint flags)
+{
+    VASurfaceID surface_id;
+    VAStatus status;
+
+    surface_id = GST_VAAPI_OBJECT_ID(surface);
+    if (surface_id == VA_INVALID_ID)
+        return FALSE;
+
+    GST_VAAPI_OBJECT_LOCK_DISPLAY(pixmap);
+    status = vaPutSurface(
+        GST_VAAPI_OBJECT_VADISPLAY(pixmap),
+        surface_id,
+        GST_VAAPI_OBJECT_ID(pixmap),
+        crop_rect->x, crop_rect->y,
+        crop_rect->width, crop_rect->height,
+        0, 0,
+        GST_VAAPI_PIXMAP_WIDTH(pixmap),
+        GST_VAAPI_PIXMAP_HEIGHT(pixmap),
+        NULL, 0,
+        from_GstVaapiSurfaceRenderFlags(flags)
+    );
+    GST_VAAPI_OBJECT_UNLOCK_DISPLAY(pixmap);
+    if (!vaapi_check_status(status, "vaPutSurface() [pixmap]"))
+        return FALSE;
+    return TRUE;
+}
+
+void
+gst_vaapi_pixmap_x11_class_init(GstVaapiPixmapX11Class *klass)
+{
+    GstVaapiObjectClass * const object_class =
+        GST_VAAPI_OBJECT_CLASS(klass);
+    GstVaapiPixmapClass * const pixmap_class =
+        GST_VAAPI_PIXMAP_CLASS(klass);
+
+    object_class->finalize = (GstVaapiObjectFinalizeFunc)
+        gst_vaapi_pixmap_x11_destroy;
+
+    pixmap_class->create        = gst_vaapi_pixmap_x11_create;
+    pixmap_class->render        = gst_vaapi_pixmap_x11_render;
+}
+
+#define gst_vaapi_pixmap_x11_finalize \
+    gst_vaapi_pixmap_x11_destroy
+
+GST_VAAPI_OBJECT_DEFINE_CLASS_WITH_CODE(
+    GstVaapiPixmapX11,
+    gst_vaapi_pixmap_x11,
+    gst_vaapi_pixmap_x11_class_init(&g_class))
+
+/**
+ * gst_vaapi_pixmap_x11_new:
+ * @display: a #GstVaapiDisplay
+ * @format: the requested pixmap format
+ * @width: the requested pixmap width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a pixmap with the specified @format, @width and
+ * @height. The pixmap will be attached to the @display.
+ *
+ * Return value: the newly allocated #GstVaapiPixmap object
+ */
+GstVaapiPixmap *
+gst_vaapi_pixmap_x11_new(GstVaapiDisplay *display, GstVideoFormat format,
+    guint width, guint height)
+{
+    GST_DEBUG("new pixmap, format %s, size %ux%u",
+              gst_vaapi_video_format_to_string(format), width, height);
+
+    g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
+
+    return gst_vaapi_pixmap_new(GST_VAAPI_PIXMAP_CLASS(
+            gst_vaapi_pixmap_x11_class()), display, format, width, height);
+}
+
+/**
+ * gst_vaapi_pixmap_x11_new_with_xid:
+ * @display: a #GstVaapiDisplay
+ * @xid: an X11 #Pixmap id
+ *
+ * Creates a #GstVaapiPixmap using the X11 Pixmap @xid. The caller
+ * still owns the pixmap and must call XFreePixmap() when all
+ * #GstVaapiPixmap references are released. Doing so too early can
+ * yield undefined behaviour.
+ *
+ * Return value: the newly allocated #GstVaapiPixmap object
+ */
+GstVaapiPixmap *
+gst_vaapi_pixmap_x11_new_with_xid(GstVaapiDisplay *display, Pixmap xid)
+{
+    GST_DEBUG("new pixmap from xid 0x%08x", xid);
+
+    g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
+    g_return_val_if_fail(xid != None, NULL);
+
+    return gst_vaapi_pixmap_new_from_native(GST_VAAPI_PIXMAP_CLASS(
+            gst_vaapi_pixmap_x11_class()), display, GSIZE_TO_POINTER(xid));
+}
+
+/**
+ * gst_vaapi_pixmap_x11_get_xid:
+ * @pixmap: a #GstVaapiPixmapX11
+ *
+ * Returns the underlying X11 Pixmap that was created by
+ * gst_vaapi_pixmap_x11_new() or that was bound with
+ * gst_vaapi_pixmap_x11_new_with_xid().
+ *
+ * Return value: the underlying X11 Pixmap bound to @pixmap.
+ */
+Pixmap
+gst_vaapi_pixmap_x11_get_xid(GstVaapiPixmapX11 *pixmap)
+{
+    g_return_val_if_fail(pixmap != NULL, None);
+
+    return GST_VAAPI_OBJECT_ID(pixmap);
+}
+
+/**
+ * gst_vaapi_pixmap_x11_is_foreign_xid:
+ * @pixmap: a #GstVaapiPixmapX11
+ *
+ * Checks whether the @pixmap XID was created by gst_vaapi_pixmap_x11_new()
+ * or was bound with gst_vaapi_pixmap_x11_new_with_xid().
+ *
+ * Return value: %TRUE if the underlying X pixmap is owned by the
+ *   caller (foreign pixmap)
+ */
+gboolean
+gst_vaapi_pixmap_x11_is_foreign_xid(GstVaapiPixmapX11 *pixmap)
+{
+    g_return_val_if_fail(pixmap != NULL, FALSE);
+
+    return GST_VAAPI_PIXMAP(pixmap)->use_foreign_pixmap;
+}
diff --git a/gst-libs/gst/vaapi/gstvaapipixmap_x11.h b/gst-libs/gst/vaapi/gstvaapipixmap_x11.h
new file mode 100644 (file)
index 0000000..2c27ad4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  gstvaapipixmap_x11.h - X11 pixmap abstraction
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_PIXMAP_X11_H
+#define GST_VAAPI_PIXMAP_X11_H
+
+#include <X11/Xlib.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapipixmap.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_PIXMAP_X11(obj) \
+    ((GstVaapiPixmapX11 *)(obj))
+
+/**
+ * GST_VAAPI_PIXMAP_XPIXMAP:
+ * @pixmap: a #GstVaapiPixmap
+ *
+ * Macro that evaluates to the underlying X11 #Pixmap of @pixmap
+ */
+#define GST_VAAPI_PIXMAP_XPIXMAP(pixmap) \
+    gst_vaapi_pixmap_x11_get_xid(GST_VAAPI_PIXMAP_X11(pixmap))
+
+typedef struct _GstVaapiPixmapX11               GstVaapiPixmapX11;
+
+GstVaapiPixmap *
+gst_vaapi_pixmap_x11_new(GstVaapiDisplay *display, GstVideoFormat format,
+    guint width, guint height);
+
+GstVaapiPixmap *
+gst_vaapi_pixmap_x11_new_with_xid(GstVaapiDisplay *display, Pixmap xid);
+
+Pixmap
+gst_vaapi_pixmap_x11_get_xid(GstVaapiPixmapX11 *pixmap);
+
+gboolean
+gst_vaapi_pixmap_x11_is_foreign_xid(GstVaapiPixmapX11 *pixmap);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_PIXMAP_X11_H */