From 7fe02f31a50583c6d4d97a29df30c9df83612e37 Mon Sep 17 00:00:00 2001 From: gb Date: Mon, 15 Mar 2010 15:12:27 +0000 Subject: [PATCH] Add VA/X11 window abstraction. --- gst-libs/gst/vaapi/Makefile.am | 4 + gst-libs/gst/vaapi/gstvaapiwindow.c | 332 +++++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiwindow.h | 138 ++++++++++ gst-libs/gst/vaapi/gstvaapiwindow_x11.c | 448 ++++++++++++++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiwindow_x11.h | 84 ++++++ tests/examples/generic/Makefile.am | 5 + tests/examples/generic/test-windows.c | 120 +++++++++ 7 files changed, 1131 insertions(+) create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_x11.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_x11.h create mode 100644 tests/examples/generic/test-windows.c diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index f9171c1..127e54c 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -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 index 0000000..6629564 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow.c @@ -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 index 0000000..1095f7a --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow.h @@ -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 +#include +#include + +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 index 0000000..c995a49 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c @@ -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 index 0000000..c1af6ec --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.h @@ -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 +#include +#include + +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 */ diff --git a/tests/examples/generic/Makefile.am b/tests/examples/generic/Makefile.am index a914fff..cc7cdcf 100644 --- a/tests/examples/generic/Makefile.am +++ b/tests/examples/generic/Makefile.am @@ -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 index 0000000..bd3f106 --- /dev/null +++ b/tests/examples/generic/test-windows.c @@ -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 +#include +#include +#include + +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; +} -- 2.7.4