Add VA/X11 window abstraction.
authorgb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Mon, 15 Mar 2010 15:12:27 +0000 (15:12 +0000)
committergb <gb@5584edef-b1fe-4b99-b61b-dd2bab72e969>
Mon, 15 Mar 2010 15:12:27 +0000 (15:12 +0000)
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/gstvaapiwindow.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapiwindow.h [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapiwindow_x11.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapiwindow_x11.h [new file with mode: 0644]
tests/examples/generic/Makefile.am
tests/examples/generic/test-windows.c [new file with mode: 0644]

index f9171c1..127e54c 100644 (file)
@@ -11,6 +11,7 @@ libgstvaapi_source_c =                                \
        gstvaapisurfacepool.c                   \
        gstvaapivideobuffer.c                   \
        gstvaapivideopool.c                     \
+       gstvaapiwindow.c                        \
        vaapi_utils.c                           \
        $(NULL)
 
@@ -25,6 +26,7 @@ libgstvaapi_source_h =                                \
        gstvaapisurfacepool.h                   \
        gstvaapivideobuffer.h                   \
        gstvaapivideopool.h                     \
+       gstvaapiwindow.h                        \
        vaapi_debug.h                           \
        vaapi_utils.h                           \
        $(NULL)
@@ -55,10 +57,12 @@ libgstvaapi_@GST_MAJORMINOR@_la_LIBADD =    \
 
 libgstvaapi_@GST_MAJORMINOR@_la_SOURCES +=     \
        gstvaapidisplay_x11.c                   \
+       gstvaapiwindow_x11.c                    \
        $(NULL)
 
 libgstvaapi_@GST_MAJORMINOR@include_HEADERS += \
        gstvaapidisplay_x11.h                   \
+       gstvaapiwindow_x11.h                    \
        $(NULL)
 
 libgstvaapi_@GST_MAJORMINOR@_la_CFLAGS +=      \
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow.c b/gst-libs/gst/vaapi/gstvaapiwindow.c
new file mode 100644 (file)
index 0000000..6629564
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ *  gstvaapiwindow.c - VA window abstraction
+ *
+ *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include "config.h"
+#include "gstvaapiwindow.h"
+
+#define DEBUG 1
+#include "vaapi_debug.h"
+
+G_DEFINE_TYPE(GstVaapiWindow, gst_vaapi_window, G_TYPE_OBJECT);
+
+#define GST_VAAPI_WINDOW_GET_PRIVATE(obj)                       \
+    (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
+                                 GST_VAAPI_TYPE_WINDOW,         \
+                                 GstVaapiWindowPrivate))
+
+struct _GstVaapiWindowPrivate {
+    gboolean    is_constructed;
+    guint       width;
+    guint       height;
+};
+
+enum {
+    PROP_0,
+
+    PROP_WIDTH,
+    PROP_HEIGHT
+};
+
+static void
+gst_vaapi_window_destroy(GstVaapiWindow *window)
+{
+    GST_VAAPI_WINDOW_GET_CLASS(window)->destroy(window);
+}
+
+static gboolean
+gst_vaapi_window_create(GstVaapiWindow *window, guint width, guint height)
+{
+    if (width == 0 || height == 0)
+        return FALSE;
+
+    return GST_VAAPI_WINDOW_GET_CLASS(window)->create(window, width, height);
+}
+
+static void
+gst_vaapi_window_finalize(GObject *object)
+{
+    gst_vaapi_window_destroy(GST_VAAPI_WINDOW(object));
+
+    G_OBJECT_CLASS(gst_vaapi_window_parent_class)->finalize(object);
+}
+
+static void
+gst_vaapi_window_set_property(
+    GObject      *object,
+    guint         prop_id,
+    const GValue *value,
+    GParamSpec   *pspec
+)
+{
+    GstVaapiWindow * const window = GST_VAAPI_WINDOW(object);
+
+    switch (prop_id) {
+    case PROP_WIDTH:
+        gst_vaapi_window_set_width(window, g_value_get_uint(value));
+        break;
+    case PROP_HEIGHT:
+        gst_vaapi_window_set_height(window, g_value_get_uint(value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_vaapi_window_get_property(
+    GObject    *object,
+    guint       prop_id,
+    GValue     *value,
+    GParamSpec *pspec
+)
+{
+    GstVaapiWindow * const window = GST_VAAPI_WINDOW(object);
+
+    switch (prop_id) {
+    case PROP_WIDTH:
+        g_value_set_uint(value, gst_vaapi_window_get_width(window));
+        break;
+    case PROP_HEIGHT:
+        g_value_set_uint(value, gst_vaapi_window_get_height(window));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_vaapi_window_constructed(GObject *object)
+{
+    GstVaapiWindow * const window = GST_VAAPI_WINDOW(object);
+    GObjectClass *parent_class;
+
+    window->priv->is_constructed = gst_vaapi_window_create(
+        window,
+        window->priv->width,
+        window->priv->height
+    );
+
+    parent_class = G_OBJECT_CLASS(gst_vaapi_window_parent_class);
+    if (parent_class->constructed)
+        parent_class->constructed(object);
+}
+
+static void
+gst_vaapi_window_class_init(GstVaapiWindowClass *klass)
+{
+    GObjectClass * const object_class = G_OBJECT_CLASS(klass);
+
+    g_type_class_add_private(klass, sizeof(GstVaapiWindowPrivate));
+
+    object_class->finalize     = gst_vaapi_window_finalize;
+    object_class->set_property = gst_vaapi_window_set_property;
+    object_class->get_property = gst_vaapi_window_get_property;
+    object_class->constructed  = gst_vaapi_window_constructed;
+
+    g_object_class_install_property
+        (object_class,
+         PROP_WIDTH,
+         g_param_spec_uint("width",
+                           "width",
+                           "Width",
+                           1, G_MAXUINT32, 1,
+                           G_PARAM_READWRITE));
+
+    g_object_class_install_property
+        (object_class,
+         PROP_HEIGHT,
+         g_param_spec_uint("height",
+                           "height",
+                           "Height",
+                           1, G_MAXUINT32, 1,
+                           G_PARAM_READWRITE));
+}
+
+static void
+gst_vaapi_window_init(GstVaapiWindow *window)
+{
+    GstVaapiWindowPrivate *priv = GST_VAAPI_WINDOW_GET_PRIVATE(window);
+
+    window->priv                = priv;
+    priv->is_constructed        = FALSE;
+    priv->width                 = 1;
+    priv->height                = 1;
+}
+
+void
+gst_vaapi_window_show(GstVaapiWindow *window)
+{
+    g_return_if_fail(GST_VAAPI_IS_WINDOW(window));
+    g_return_if_fail(window->priv->is_constructed);
+
+    GST_VAAPI_WINDOW_GET_CLASS(window)->show(window);
+}
+
+void
+gst_vaapi_window_hide(GstVaapiWindow *window)
+{
+    g_return_if_fail(GST_VAAPI_IS_WINDOW(window));
+    g_return_if_fail(window->priv->is_constructed);
+
+    GST_VAAPI_WINDOW_GET_CLASS(window)->hide(window);
+}
+
+guint
+gst_vaapi_window_get_width(GstVaapiWindow *window)
+{
+    g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), 0);
+    g_return_val_if_fail(window->priv->is_constructed, 0);
+
+    return window->priv->width;
+}
+
+guint
+gst_vaapi_window_get_height(GstVaapiWindow *window)
+{
+    g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), 0);
+    g_return_val_if_fail(window->priv->is_constructed, 0);
+
+    return window->priv->height;
+}
+
+void
+gst_vaapi_window_get_size(GstVaapiWindow *window, guint *pwidth, guint *pheight)
+{
+    g_return_if_fail(GST_VAAPI_IS_WINDOW(window));
+    g_return_if_fail(window->priv->is_constructed);
+
+    if (pwidth)
+        *pwidth = window->priv->width;
+
+    if (pheight)
+        *pheight = window->priv->height;
+}
+
+void
+gst_vaapi_window_set_width(GstVaapiWindow *window, guint width)
+{
+    g_return_if_fail(GST_VAAPI_IS_WINDOW(window));
+
+    gst_vaapi_window_set_size(window, width, window->priv->height);
+}
+
+void
+gst_vaapi_window_set_height(GstVaapiWindow *window, guint height)
+{
+    g_return_if_fail(GST_VAAPI_IS_WINDOW(window));
+
+    gst_vaapi_window_set_size(window, window->priv->width, height);
+}
+
+void
+gst_vaapi_window_set_size(GstVaapiWindow *window, guint width, guint height)
+{
+    g_return_if_fail(GST_VAAPI_IS_WINDOW(window));
+
+    if (width == window->priv->width && height == window->priv->height)
+        return;
+
+    window->priv->width  = width;
+    window->priv->height = height;
+
+    if (window->priv->is_constructed)
+        GST_VAAPI_WINDOW_GET_CLASS(window)->resize(window, width, height);
+}
+
+static inline void
+get_surface_rect(GstVaapiSurface *surface, GstVideoRectangle *rect)
+{
+    guint width, height;
+
+    gst_vaapi_surface_get_size(surface, &width, &height);
+    rect->x = 0;
+    rect->y = 0;
+    rect->w = width;
+    rect->h = height;
+}
+
+static inline void
+get_window_rect(GstVaapiWindow *window, GstVideoRectangle *rect)
+{
+    guint width, height;
+
+    gst_vaapi_window_get_size(window, &width, &height);
+    rect->x = 0;
+    rect->y = 0;
+    rect->w = width;
+    rect->h = height;
+}
+
+gboolean
+gst_vaapi_window_put_surface(
+    GstVaapiWindow          *window,
+    GstVaapiSurface         *surface,
+    guint                    flags
+)
+{
+    GstVideoRectangle src_rect, dst_rect;
+
+    g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), FALSE);
+    g_return_val_if_fail(window->priv->is_constructed, FALSE);
+    g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
+
+    get_surface_rect(surface, &src_rect);
+    get_window_rect(window, &dst_rect);
+
+    return GST_VAAPI_WINDOW_GET_CLASS(window)->render(window,
+                                                      surface,
+                                                      &src_rect,
+                                                      &dst_rect,
+                                                      flags);
+}
+
+gboolean
+gst_vaapi_window_put_surface_full(
+    GstVaapiWindow          *window,
+    GstVaapiSurface         *surface,
+    const GstVideoRectangle *src_rect,
+    const GstVideoRectangle *dst_rect,
+    guint                    flags
+)
+{
+    GstVideoRectangle src_rect_default, dst_rect_default;
+
+    g_return_val_if_fail(GST_VAAPI_IS_WINDOW(window), FALSE);
+    g_return_val_if_fail(window->priv->is_constructed, FALSE);
+    g_return_val_if_fail(GST_VAAPI_IS_SURFACE(surface), FALSE);
+
+    if (!src_rect) {
+        src_rect = &src_rect_default;
+        get_surface_rect(surface, &src_rect_default);
+    }
+
+    if (!dst_rect) {
+        dst_rect = &dst_rect_default;
+        get_window_rect(window, &dst_rect_default);
+    }
+
+    return GST_VAAPI_WINDOW_GET_CLASS(window)->render(window,
+                                                      surface,
+                                                      src_rect,
+                                                      dst_rect,
+                                                      flags);
+}
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow.h b/gst-libs/gst/vaapi/gstvaapiwindow.h
new file mode 100644 (file)
index 0000000..1095f7a
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  gstvaapiwindow.h - VA window abstraction
+ *
+ *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_H
+#define GST_VAAPI_WINDOW_H
+
+#include <gst/video/gstvideosink.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapisurface.h>
+
+G_BEGIN_DECLS
+
+enum {
+    GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD       = 1 << 0,
+    GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD    = 1 << 1,
+    GST_VAAPI_PICTURE_STRUCTURE_FRAME           =
+    (
+        GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD |
+        GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD
+    ),
+    GST_VAAPI_COLOR_STANDARD_ITUR_BT_601        = 1 << 2,
+    GST_VAAPI_COLOR_STANDARD_ITUR_BT_709        = 1 << 3,
+};
+
+#define GST_VAAPI_TYPE_WINDOW \
+    (gst_vaapi_window_get_type())
+
+#define GST_VAAPI_WINDOW(obj)                           \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),                  \
+                                GST_VAAPI_TYPE_WINDOW,  \
+                                GstVaapiWindow))
+
+#define GST_VAAPI_WINDOW_CLASS(klass)                   \
+    (G_TYPE_CHECK_CLASS_CAST((klass),                   \
+                             GST_VAAPI_TYPE_WINDOW,     \
+                             GstVaapiWindowClass))
+
+#define GST_VAAPI_IS_WINDOW(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW))
+
+#define GST_VAAPI_IS_WINDOW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW))
+
+#define GST_VAAPI_WINDOW_GET_CLASS(obj)                 \
+    (G_TYPE_INSTANCE_GET_CLASS((obj),                   \
+                               GST_VAAPI_TYPE_WINDOW,   \
+                               GstVaapiWindowClass))
+
+typedef struct _GstVaapiWindow                  GstVaapiWindow;
+typedef struct _GstVaapiWindowPrivate           GstVaapiWindowPrivate;
+typedef struct _GstVaapiWindowClass             GstVaapiWindowClass;
+
+struct _GstVaapiWindow {
+    /*< private >*/
+    GObject parent_instance;
+
+    GstVaapiWindowPrivate *priv;
+};
+
+struct _GstVaapiWindowClass {
+    /*< private >*/
+    GObjectClass parent_class;
+
+    gboolean    (*create) (GstVaapiWindow *window, guint width, guint height);
+    void        (*destroy)(GstVaapiWindow *window);
+    gboolean    (*show)   (GstVaapiWindow *window);
+    gboolean    (*hide)   (GstVaapiWindow *window);
+    gboolean    (*resize) (GstVaapiWindow *window, guint width, guint height);
+    gboolean    (*render) (GstVaapiWindow *window,
+                           GstVaapiSurface *surface,
+                           const GstVideoRectangle *src_rect,
+                           const GstVideoRectangle *dst_rect,
+                           guint flags);
+};
+
+GType
+gst_vaapi_window_get_type(void);
+
+void
+gst_vaapi_window_show(GstVaapiWindow *window);
+
+void
+gst_vaapi_window_hide(GstVaapiWindow *window);
+
+guint
+gst_vaapi_window_get_width(GstVaapiWindow *window);
+
+guint
+gst_vaapi_window_get_height(GstVaapiWindow *window);
+
+void
+gst_vaapi_window_get_size(GstVaapiWindow *window, guint *pwidth, guint *pheight);
+
+void
+gst_vaapi_window_set_width(GstVaapiWindow *window, guint width);
+
+void
+gst_vaapi_window_set_height(GstVaapiWindow *window, guint height);
+
+void
+gst_vaapi_window_set_size(GstVaapiWindow *window, guint width, guint height);
+
+gboolean
+gst_vaapi_window_put_surface(
+    GstVaapiWindow          *window,
+    GstVaapiSurface         *surface,
+    guint                    flags
+);
+
+gboolean
+gst_vaapi_window_put_surface_full(
+    GstVaapiWindow          *window,
+    GstVaapiSurface         *surface,
+    const GstVideoRectangle *src_rect,
+    const GstVideoRectangle *dst_rect,
+    guint                    flags
+);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_H */
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.c b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c
new file mode 100644 (file)
index 0000000..c995a49
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+ *  gstvaapiwindow_x11.c - VA/X11 window abstraction
+ *
+ *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include "config.h"
+#include "gstvaapiwindow_x11.h"
+#include "gstvaapidisplay_x11.h"
+
+#define DEBUG 1
+#include "vaapi_debug.h"
+
+G_DEFINE_TYPE(GstVaapiWindowX11, gst_vaapi_window_x11, GST_VAAPI_TYPE_WINDOW);
+
+#define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj)                   \
+    (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
+                                 GST_VAAPI_TYPE_WINDOW_X11,     \
+                                 GstVaapiWindowX11Private))
+
+struct _GstVaapiWindowX11Private {
+    gboolean            create_window;
+    GstVaapiDisplay    *display;
+    Window              xid;
+};
+
+enum {
+    PROP_0,
+
+    PROP_DISPLAY,
+    PROP_XID,
+};
+
+// X error trap
+static int x11_error_code = 0;
+static int (*old_error_handler)(Display *, XErrorEvent *);
+
+static int error_handler(Display *dpy, XErrorEvent *error)
+{
+    x11_error_code = error->error_code;
+    return 0;
+}
+
+static void x11_trap_errors(void)
+{
+    x11_error_code    = 0;
+    old_error_handler = XSetErrorHandler(error_handler);
+}
+
+static int x11_untrap_errors(void)
+{
+    XSetErrorHandler(old_error_handler);
+    return x11_error_code;
+}
+
+// X window management
+static const int x11_event_mask = (KeyPressMask |
+                                   KeyReleaseMask |
+                                   ButtonPressMask |
+                                   ButtonReleaseMask |
+                                   PointerMotionMask |
+                                   EnterWindowMask |
+                                   ExposureMask |
+                                   StructureNotifyMask);
+
+static Window
+x11_create_window(Display *display, unsigned int width, unsigned int height)
+{
+    Window root_window, window;
+    int screen, depth;
+    Visual *vis;
+    XSetWindowAttributes xswa;
+    unsigned long xswa_mask;
+    XWindowAttributes wattr;
+    unsigned long black_pixel, white_pixel;
+
+    screen      = DefaultScreen(display);
+    vis         = DefaultVisual(display, screen);
+    root_window = RootWindow(display, screen);
+    black_pixel = BlackPixel(display, screen);
+    white_pixel = WhitePixel(display, screen);
+
+    XGetWindowAttributes(display, root_window, &wattr);
+    depth = wattr.depth;
+    if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
+        depth = 24;
+
+    xswa_mask             = CWBorderPixel | CWBackPixel;
+    xswa.border_pixel     = black_pixel;
+    xswa.background_pixel = white_pixel;
+
+    window = XCreateWindow(
+        display,
+        root_window,
+        0, 0, width, height,
+        0,
+        depth,
+        InputOutput,
+        vis,
+        xswa_mask, &xswa
+    );
+    if (window)
+        XSelectInput(display, window, x11_event_mask);
+    return window;
+}
+
+static gboolean
+x11_get_geometry(
+    Display    *dpy,
+    Drawable    drawable,
+    gint       *px,
+    gint       *py,
+    guint      *pwidth,
+    guint      *pheight
+)
+{
+    Window rootwin;
+    int x, y;
+    unsigned int width, height, border_width, depth;
+
+    x11_trap_errors();
+    XGetGeometry(
+        dpy,
+        drawable,
+        &rootwin,
+        &x, &y, &width, &height,
+        &border_width,
+        &depth
+    );
+    if (x11_untrap_errors())
+        return FALSE;
+
+    if (px)      *px      = x;
+    if (py)      *py      = y;
+    if (pwidth)  *pwidth  = width;
+    if (pheight) *pheight = height;
+    return TRUE;
+}
+
+static void x11_wait_event(Display *dpy, Window w, int type)
+{
+    XEvent e;
+    while (!XCheckTypedWindowEvent(dpy, w, type, &e))
+        g_usleep(10);
+}
+
+static gboolean
+gst_vaapi_window_x11_create(GstVaapiWindow *window, guint width, guint height)
+{
+    GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
+    Display *dpy;
+
+    if (!priv->create_window && priv->xid)
+        return TRUE;
+
+    dpy       = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
+    priv->xid = x11_create_window(dpy, width, height);
+
+    XMapRaised(dpy, priv->xid);
+    x11_wait_event(dpy, priv->xid, MapNotify);
+    return TRUE;
+}
+
+static void
+gst_vaapi_window_x11_destroy(GstVaapiWindow *window)
+{
+    GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
+    Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
+
+    if (priv->create_window && priv->xid) {
+        XUnmapWindow(dpy, priv->xid);
+        x11_wait_event(dpy, priv->xid, UnmapNotify);
+        XDestroyWindow(dpy, priv->xid);
+        priv->xid = None;
+    }
+
+    g_object_unref(priv->display);
+    priv->display = NULL;
+}
+
+static gboolean
+gst_vaapi_window_x11_show(GstVaapiWindow *window)
+{
+    GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
+    Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
+
+    x11_trap_errors();
+    XMapWindow(dpy, priv->xid);
+    x11_wait_event(dpy, priv->xid, MapNotify);
+    return x11_untrap_errors() == 0;
+}
+
+static gboolean
+gst_vaapi_window_x11_hide(GstVaapiWindow *window)
+{
+    GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
+    Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
+
+    x11_trap_errors();
+    XUnmapWindow(dpy, priv->xid);
+    x11_wait_event(dpy, priv->xid, UnmapNotify);
+    return x11_untrap_errors() == 0;
+}
+
+static gboolean
+gst_vaapi_window_x11_resize(GstVaapiWindow *window, guint width, guint height)
+{
+    GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
+
+    if (!priv->xid)
+        return FALSE;
+
+    x11_trap_errors();
+    XResizeWindow(
+        GST_VAAPI_DISPLAY_XDISPLAY(priv->display),
+        priv->xid,
+        width,
+        height
+    );
+    if (x11_untrap_errors() != 0)
+        return FALSE;
+    return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_x11_render(
+    GstVaapiWindow          *window,
+    GstVaapiSurface         *surface,
+    const GstVideoRectangle *src_rect,
+    const GstVideoRectangle *dst_rect,
+    guint                    flags
+)
+{
+    VASurfaceID surface_id;
+    VAStatus status;
+    unsigned int va_flags = 0;
+
+    surface_id = gst_vaapi_surface_get_id(surface);
+    if (surface_id == VA_INVALID_ID)
+        return FALSE;
+
+    if (flags & GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD)
+        va_flags |= VA_TOP_FIELD;
+    if (flags & GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD)
+        va_flags |= VA_BOTTOM_FIELD;
+    if ((va_flags ^ (VA_TOP_FIELD|VA_BOTTOM_FIELD)) == 0)
+        va_flags  = VA_FRAME_PICTURE;
+
+    if (flags & GST_VAAPI_COLOR_STANDARD_ITUR_BT_709)
+        va_flags |= VA_SRC_BT709;
+    else if (flags & GST_VAAPI_COLOR_STANDARD_ITUR_BT_601)
+        va_flags |= VA_SRC_BT601;
+
+    status = vaPutSurface(
+        GST_VAAPI_DISPLAY_VADISPLAY(gst_vaapi_surface_get_display(surface)),
+        surface_id,
+        GST_VAAPI_WINDOW_X11(window)->priv->xid,
+        src_rect->x,
+        src_rect->y,
+        src_rect->w,
+        src_rect->h,
+        dst_rect->x,
+        dst_rect->y,
+        dst_rect->w,
+        dst_rect->h,
+        NULL, 0,
+        va_flags
+    );
+    if (!vaapi_check_status(status, "vaPutSurface()"))
+        return FALSE;
+
+    return TRUE;
+}
+
+static void
+gst_vaapi_window_x11_finalize(GObject *object)
+{
+    G_OBJECT_CLASS(gst_vaapi_window_x11_parent_class)->finalize(object);
+}
+
+static void
+gst_vaapi_window_x11_set_property(
+    GObject      *object,
+    guint         prop_id,
+    const GValue *value,
+    GParamSpec   *pspec
+)
+{
+    GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object);
+
+    switch (prop_id) {
+    case PROP_DISPLAY:
+        window->priv->display = g_object_ref(g_value_get_object(value));
+        break;
+    case PROP_XID:
+        window->priv->xid = g_value_get_uint(value);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_vaapi_window_x11_get_property(
+    GObject    *object,
+    guint       prop_id,
+    GValue     *value,
+    GParamSpec *pspec
+)
+{
+    GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object);
+
+    switch (prop_id) {
+    case PROP_DISPLAY:
+        g_value_set_object(value, window->priv->display);
+        break;
+    case PROP_XID:
+        g_value_set_uint(value, gst_vaapi_window_x11_get_xid(window));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gst_vaapi_window_x11_constructed(GObject *object)
+{
+    GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object);
+    GObjectClass *parent_class;
+
+    window->priv->create_window = window->priv->xid == None;
+
+    parent_class = G_OBJECT_CLASS(gst_vaapi_window_x11_parent_class);
+    if (parent_class->constructed)
+        parent_class->constructed(object);
+}
+
+static void
+gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass)
+{
+    GObjectClass * const object_class = G_OBJECT_CLASS(klass);
+    GstVaapiWindowClass * const window_class = GST_VAAPI_WINDOW_CLASS(klass);
+
+    g_type_class_add_private(klass, sizeof(GstVaapiWindowX11Private));
+
+    object_class->finalize      = gst_vaapi_window_x11_finalize;
+    object_class->set_property  = gst_vaapi_window_x11_set_property;
+    object_class->get_property  = gst_vaapi_window_x11_get_property;
+    object_class->constructed   = gst_vaapi_window_x11_constructed;
+
+    window_class->create        = gst_vaapi_window_x11_create;
+    window_class->destroy       = gst_vaapi_window_x11_destroy;
+    window_class->show          = gst_vaapi_window_x11_show;
+    window_class->hide          = gst_vaapi_window_x11_hide;
+    window_class->resize        = gst_vaapi_window_x11_resize;
+    window_class->render        = gst_vaapi_window_x11_render;
+
+    g_object_class_install_property
+        (object_class,
+         PROP_DISPLAY,
+         g_param_spec_object("display",
+                             "display",
+                             "Display",
+                             GST_VAAPI_TYPE_DISPLAY,
+                             G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property
+        (object_class,
+         PROP_XID,
+         g_param_spec_uint("xid",
+                           "X window id",
+                           "X window ID",
+                           0, G_MAXUINT32, 0,
+                           G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gst_vaapi_window_x11_init(GstVaapiWindowX11 *window)
+{
+    GstVaapiWindowX11Private *priv = GST_VAAPI_WINDOW_X11_GET_PRIVATE(window);
+
+    window->priv        = priv;
+    priv->create_window = TRUE;
+    priv->display       = NULL;
+    priv->xid           = None;
+}
+
+GstVaapiWindow *
+gst_vaapi_window_x11_new(GstVaapiDisplay *display, guint width, guint height)
+{
+    GST_DEBUG("new window, size %ux%u", width, height);
+
+    g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
+    g_return_val_if_fail(width > 0, NULL);
+    g_return_val_if_fail(height > 0, NULL);
+
+    return g_object_new(GST_VAAPI_TYPE_WINDOW_X11,
+                        "display", display,
+                        "width",   width,
+                        "height",  height,
+                        NULL);
+}
+
+GstVaapiWindow *
+gst_vaapi_window_x11_new_with_xid(GstVaapiDisplay *display, Window xid)
+{
+    Display *dpy;
+    guint width, height;
+
+    GST_DEBUG("new window from xid 0x%08x", xid);
+
+    g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
+
+    dpy = GST_VAAPI_DISPLAY_XDISPLAY(display);
+    if (!dpy || !x11_get_geometry(dpy, xid, NULL, NULL, &width, &height))
+        return NULL;
+
+    return g_object_new(GST_VAAPI_TYPE_WINDOW_X11,
+                        "display", display,
+                        "xid",     xid,
+                        "width",   width,
+                        "height",  height,
+                        NULL);
+}
+
+Window
+gst_vaapi_window_x11_get_xid(GstVaapiWindowX11 *window)
+{
+    g_return_val_if_fail(GST_VAAPI_WINDOW_X11(window), None);
+
+    return window->priv->xid;
+}
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.h b/gst-libs/gst/vaapi/gstvaapiwindow_x11.h
new file mode 100644 (file)
index 0000000..c1af6ec
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *  gstvaapiwindow_x11.h - VA/X11 window abstraction
+ *
+ *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_X11_H
+#define GST_VAAPI_WINDOW_X11_H
+
+#include <X11/Xlib.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_TYPE_WINDOW_X11 \
+    (gst_vaapi_window_x11_get_type())
+
+#define GST_VAAPI_WINDOW_X11(obj)                               \
+    (G_TYPE_CHECK_INSTANCE_CAST((obj),                          \
+                                GST_VAAPI_TYPE_WINDOW_X11,      \
+                                GstVaapiWindowX11))
+
+#define GST_VAAPI_WINDOW_X11_CLASS(klass)                       \
+    (G_TYPE_CHECK_CLASS_CAST((klass),                           \
+                             GST_VAAPI_TYPE_WINDOW_X11,         \
+                             GstVaapiWindowX11Class))
+
+#define GST_VAAPI_IS_WINDOW_X11(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_X11))
+
+#define GST_VAAPI_IS_WINDOW_X11_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_X11))
+
+#define GST_VAAPI_WINDOW_X11_GET_CLASS(obj)                     \
+    (G_TYPE_INSTANCE_GET_CLASS((obj),                           \
+                               GST_VAAPI_TYPE_WINDOW_X11,       \
+                               GstVaapiWindowX11Class))
+
+typedef struct _GstVaapiWindowX11               GstVaapiWindowX11;
+typedef struct _GstVaapiWindowX11Private        GstVaapiWindowX11Private;
+typedef struct _GstVaapiWindowX11Class          GstVaapiWindowX11Class;
+
+struct _GstVaapiWindowX11 {
+    /*< private >*/
+    GstVaapiWindow parent_instance;
+
+    GstVaapiWindowX11Private *priv;
+};
+
+struct _GstVaapiWindowX11Class {
+    /*< private >*/
+    GstVaapiWindowClass parent_class;
+};
+
+GType
+gst_vaapi_window_x11_get_type(void);
+
+GstVaapiWindow *
+gst_vaapi_window_x11_new(GstVaapiDisplay *display, guint width, guint height);
+
+GstVaapiWindow *
+gst_vaapi_window_x11_new_with_xid(GstVaapiDisplay *display, Window xid);
+
+Window
+gst_vaapi_window_x11_get_xid(GstVaapiWindowX11 *window);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_X11_H */
index a914fff..cc7cdcf 100644 (file)
@@ -1,6 +1,7 @@
 noinst_PROGRAMS =      \
        test-display    \
        test-surfaces   \
+       test-windows    \
        $(NULL)
 
 TEST_CFLAGS = \
@@ -20,5 +21,9 @@ test_surfaces_SOURCES = test-surfaces.c
 test_surfaces_CFLAGS   = $(TEST_CFLAGS)
 test_surfaces_LDADD    = $(TEST_LIBS)
 
+test_windows_SOURCES   = test-windows.c
+test_windows_CFLAGS    = $(TEST_CFLAGS)
+test_windows_LDADD     = $(TEST_LIBS)
+
 # Extra clean files so that maintainer-clean removes *everything*
 MAINTAINERCLEANFILES = Makefile.in
diff --git a/tests/examples/generic/test-windows.c b/tests/examples/generic/test-windows.c
new file mode 100644 (file)
index 0000000..bd3f106
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  test-windows.c - Test GstVaapiWindow
+ *
+ *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <gst/vaapi/gstvaapidisplay_x11.h>
+#include <gst/vaapi/gstvaapiwindow_x11.h>
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapiimage.h>
+
+static inline void pause(void)
+{
+    g_print("Press any key to continue...\n");
+    getchar();
+}
+
+int
+main(int argc, char *argv[])
+{
+    GstVaapiDisplay *display;
+    GstVaapiWindow  *window;
+    GstVaapiSurface *surface;
+    GstVaapiImage   *image;
+    guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+
+    static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+    static const guint              width       = 320;
+    static const guint              height      = 240;
+    static const guint              win_width   = 640;
+    static const guint              win_height  = 480;
+
+    gst_init(&argc, &argv);
+
+    display = gst_vaapi_display_x11_new(NULL);
+    if (!display)
+        g_error("could not create Gst/VA display");
+
+    surface = gst_vaapi_surface_new(display, chroma_type, width, height);
+    if (!surface)
+        g_error("could not create Gst/VA surface");
+
+    image = gst_vaapi_image_new(display, GST_VAAPI_IMAGE_NV12, width, height);
+    if (!image)
+        g_error("could not create Gst/VA image");
+
+    g_print("#\n");
+    g_print("# Create window with gst_vaapi_window_x11_new()\n");
+    g_print("#\n");
+    {
+        window = gst_vaapi_window_x11_new(display, win_width, win_height);
+        if (!window)
+            g_error("could not create window");
+
+        if (!gst_vaapi_window_put_surface(window, surface, flags))
+            g_error("could not render surface");
+
+        pause();
+        g_object_unref(window);
+    }
+
+    g_print("#\n");
+    g_print("# Create window with gst_vaapi_window_x11_new_with_xid()\n");
+    g_print("#\n");
+    {
+        Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(display);
+        Window rootwin, win;
+        int screen;
+        unsigned long white_pixel, black_pixel;
+
+        screen      = DefaultScreen(dpy);
+        rootwin     = RootWindow(dpy, screen);
+        white_pixel = WhitePixel(dpy, screen);
+        black_pixel = BlackPixel(dpy, screen);
+        win     = XCreateSimpleWindow(
+            dpy,
+            rootwin,
+            0, 0, win_width, win_height,
+            0, black_pixel,
+            white_pixel
+        );
+        if (!win)
+            g_error("could not create X window");
+
+        XMapRaised(dpy, win);
+        XSync(dpy, False);
+
+        window = gst_vaapi_window_x11_new_with_xid(display, win);
+        if (!window)
+            g_error("could not create window");
+
+        if (!gst_vaapi_window_put_surface(window, surface, flags))
+            g_error("could not render surface");
+
+        pause();
+        g_object_unref(window);
+        XUnmapWindow(dpy, win);
+        XDestroyWindow(dpy, win);
+    }
+
+    g_object_unref(image);
+    g_object_unref(surface);
+    g_object_unref(display);
+    gst_deinit();
+    return 0;
+}