From 89a99d828c5527baa311b80fa63f5a51c4e78c47 Mon Sep 17 00:00:00 2001 From: gb Date: Thu, 25 Mar 2010 17:28:49 +0000 Subject: [PATCH] Add initial VA/GLX support. --- configure.ac | 47 ++- gst-libs/gst/vaapi/Makefile.am | 49 ++++ gst-libs/gst/vaapi/gstvaapidisplay_glx.c | 99 +++++++ gst-libs/gst/vaapi/gstvaapidisplay_glx.h | 90 ++++++ gst-libs/gst/vaapi/gstvaapiutils_glx.c | 183 ++++++++++++ gst-libs/gst/vaapi/gstvaapiutils_glx.h | 57 ++++ gst-libs/gst/vaapi/gstvaapiwindow_glx.c | 488 +++++++++++++++++++++++++++++++ gst-libs/gst/vaapi/gstvaapiwindow_glx.h | 100 +++++++ pkgconfig/Makefile.am | 16 +- pkgconfig/gstreamer-vaapi-glx.pc.in | 12 + tests/Makefile.am | 21 +- tests/test-textures.c | 141 +++++++++ 12 files changed, 1289 insertions(+), 14 deletions(-) create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapidisplay_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapiutils_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapiutils_glx.h create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_glx.c create mode 100644 gst-libs/gst/vaapi/gstvaapiwindow_glx.h create mode 100644 pkgconfig/gstreamer-vaapi-glx.pc.in create mode 100644 tests/test-textures.c diff --git a/configure.ac b/configure.ac index a8d73a0..3b73507 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,11 @@ AC_PROG_CC AM_PROG_CC_C_O AC_PROG_LIBTOOL +AC_ARG_ENABLE(glx, + AC_HELP_STRING([--enable-glx], + [enable OpenGL/X11 @<:@default=yes@:>@]), + [], [enable_glx="yes"]) + dnl Check for __attribute__((visibility())) AC_CACHE_CHECK([whether __attribute__((visibility())) is supported], vaapi_cv_visibility_attribute, @@ -150,11 +155,28 @@ AC_SUBST(plugindir) dnl Check for X11 PKG_CHECK_MODULES(X11, [x11]) +dnl Check for OpenGL +USE_GLX=1 +if test "$enable_glx" != "yes"; then + USE_GLX=0 +fi +OPENGL_CFLAGS="" +OPENGL_LIBS="" +AC_CHECK_HEADERS([GL/gl.h GL/glext.h GL/glx.h], [], [USE_GLX=0], [ +#ifdef HAVE_GL_GL_H +# include +#endif +]) +AC_CHECK_LIB(GL, glXCreateContext, [OPENGL_LIBS="-lGL -ldl"], [USE_GLX=0]) +AC_SUBST(OPENGL_CFLAGS) +AC_SUBST(OPENGL_LIBS) + dnl Check for VA-API LIBVA_PKGNAME="libva" PKG_CHECK_MODULES(LIBVA, [$LIBVA_PKGNAME]) AC_SUBST(LIBVA_PKGNAME) +dnl ... original VA-API 0.29 AC_CACHE_CHECK([for old VA-API 0.29], ac_cv_have_vaapi_old, [ saved_CFLAGS="$CFLAGS" @@ -173,6 +195,7 @@ if test "$ac_cv_have_vaapi_old" = "yes"; then LIBVA_EXTRA_CFLAGS="$LIBVA_CFLAGS -DGST_VAAPI_USE_OLD_VAAPI_0_29" fi +dnl ... VA-API >= 0.31 or -sds LIBVA_X11_PKGNAME="libva-x11" PKG_CHECK_MODULES(LIBVA_X11, [$LIBVA_X11_PKGNAME], [ac_cv_have_vaapi_x11="yes"], @@ -189,9 +212,24 @@ if test "$ac_cv_have_vaapi_x11" = "no"; then fi AC_SUBST(LIBVA_X11_PKGNAME) +dnl ... VA-API >= 0.31 or -sds +LIBVA_GLX_PKGNAME="libva-glx" +PKG_CHECK_MODULES(LIBVA_GLX, [$LIBVA_GLX_PKGNAME], + [ac_cv_have_vaapi_glx="yes"], + [ac_cv_have_vaapi_glx="no"] +) +if test "$ac_cv_have_vaapi_glx" = "no"; then + AC_MSG_WARN([could not find VA/GLX extensions. Disabling GLX support]) + USE_GLX=0 +fi +AC_SUBST(LIBVA_GLX_PKGNAME) + AC_SUBST(LIBVA_EXTRA_CFLAGS) AC_SUBST(LIBVA_EXTRA_LIBS) +AC_DEFINE_UNQUOTED(USE_GLX, $USE_GLX, [Defined to 1 if GLX is enabled]) +AM_CONDITIONAL(USE_GLX, test $USE_GLX -eq 1) + VA_VERSION=`$PKG_CONFIG --modversion libva` VA_MAJOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f1` VA_MINOR_VERSION=`echo "$VA_VERSION" | cut -d'.' -f2` @@ -231,8 +269,12 @@ debian.upstream/libgstvaapi-x11.install.in gst-libs/gst/Makefile gst-libs/gst/vaapi/Makefile pkgconfig/Makefile - pkgconfig/gstreamer-vaapi.pc - pkgconfig/gstreamer-vaapi-x11.pc + pkgconfig/gstreamer-vaapi-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi.pc.in + pkgconfig/gstreamer-vaapi-glx-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-glx.pc.in + pkgconfig/gstreamer-vaapi-x11-$GST_MAJORMINOR.pc:\ +pkgconfig/gstreamer-vaapi-x11.pc.in sys/Makefile sys/vaapiconvert/Makefile sys/vaapisink/Makefile @@ -244,4 +286,5 @@ echo echo $PACKAGE configuration summary: echo echo VA-API version ................... : $VA_VERSION_STR +echo GLX support ...................... : $(test $USE_GLX -eq 1 && echo yes || echo no) echo diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index b1bef04..d9626f9 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -3,6 +3,10 @@ lib_LTLIBRARIES = \ libgstvaapi-x11-@GST_MAJORMINOR@.la \ $(NULL) +if USE_GLX +lib_LTLIBRARIES += libgstvaapi-glx-@GST_MAJORMINOR@.la +endif + libgstvaapi_includedir = \ $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/vaapi @@ -68,6 +72,26 @@ libgstvaapi_x11_source_priv_h = \ gstvaapiutils_x11.h \ $(NULL) +libgstvaapi_glx_source_c = \ + gstvaapidisplay_glx.c \ + gstvaapiutils.c \ + gstvaapiutils_glx.c \ + gstvaapiutils_x11.c \ + gstvaapiwindow_glx.c \ + $(NULL) + +libgstvaapi_glx_source_h = \ + gstvaapicompat.h \ + gstvaapidisplay_glx.h \ + gstvaapiwindow_glx.h \ + $(NULL) + +libgstvaapi_glx_source_priv_h = \ + gstvaapiutils.h \ + gstvaapiutils_glx.h \ + gstvaapiutils_x11.h \ + $(NULL) + libgstvaapi_@GST_MAJORMINOR@_la_SOURCES = \ $(libgstvaapi_source_c) \ $(libgstvaapi_source_priv_h) \ @@ -118,6 +142,31 @@ libgstvaapi_x11_@GST_MAJORMINOR@_la_LIBADD = \ libgstvaapi-@GST_MAJORMINOR@.la \ $(NULL) +libgstvaapi_glx_@GST_MAJORMINOR@_la_SOURCES = \ + $(libgstvaapi_glx_source_c) \ + $(libgstvaapi_glx_source_priv_h) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@include_HEADERS = \ + $(libgstvaapi_glx_source_h) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@includedir = \ + $(libgstvaapi_includedir) + +libgstvaapi_glx_@GST_MAJORMINOR@_la_CFLAGS = \ + -I$(top_srcdir)/gst-libs \ + $(GLIB_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(LIBVA_GLX_CFLAGS) \ + $(NULL) + +libgstvaapi_glx_@GST_MAJORMINOR@_la_LIBADD = \ + $(GLIB_LIBS) \ + $(LIBVA_GLX_LIBS) \ + libgstvaapi-x11-@GST_MAJORMINOR@.la \ + $(NULL) + # Extra clean files so that maintainer-clean removes *everything* MAINTAINERCLEANFILES = Makefile.in diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx.c b/gst-libs/gst/vaapi/gstvaapidisplay_glx.c new file mode 100644 index 0000000..7a078cf --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx.c @@ -0,0 +1,99 @@ +/* + * gstvaapidisplay_glx.c - VA/GLX display 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 + */ + +/** + * SECTION:gstvaapidisplay_glx + * @short_description: VA/GLX display abstraction + */ + +#include "config.h" +#include "gstvaapiutils.h" +#include "gstvaapidisplay_glx.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiDisplayGLX, + gst_vaapi_display_glx, + GST_VAAPI_TYPE_DISPLAY_X11); + +static void +gst_vaapi_display_glx_finalize(GObject *object) +{ + G_OBJECT_CLASS(gst_vaapi_display_glx_parent_class)->finalize(object); +} + +static VADisplay +gst_vaapi_display_glx_get_va_display(GstVaapiDisplay *display) +{ + return vaGetDisplayGLX(GST_VAAPI_DISPLAY_XDISPLAY(display)); +} + +static void +gst_vaapi_display_glx_class_init(GstVaapiDisplayGLXClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass); + + object_class->finalize = gst_vaapi_display_glx_finalize; + dpy_class->get_display = gst_vaapi_display_glx_get_va_display; +} + +static void +gst_vaapi_display_glx_init(GstVaapiDisplayGLX *display) +{ +} + +/** + * gst_vaapi_display_glx_new: + * @display_name: the X11 display name + * + * Opens an X11 #Display using @display_name and returns a newly + * allocated #GstVaapiDisplay object. The X11 display will be cloed + * when the reference count of the object reaches zero. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_glx_new(const gchar *display_name) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_GLX, + "display-name", display_name, + NULL); +} + +/** + * gst_vaapi_display_glx_new_with_display: + * @x11_display: an X11 #Display + * + * Creates a #GstVaapiDisplay based on the X11 @x11_display + * display. The caller still owns the display and must call + * XCloseDisplay() when all #GstVaapiDisplay references are + * released. Doing so too early can yield undefined behaviour. + * + * Return value: a newly allocated #GstVaapiDisplay object + */ +GstVaapiDisplay * +gst_vaapi_display_glx_new_with_display(Display *x11_display) +{ + return g_object_new(GST_VAAPI_TYPE_DISPLAY_GLX, + "x11-display", x11_display, + NULL); +} diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_glx.h b/gst-libs/gst/vaapi/gstvaapidisplay_glx.h new file mode 100644 index 0000000..6206f1e --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapidisplay_glx.h @@ -0,0 +1,90 @@ +/* + * gstvaapidisplay_glx.h - VA/GLX display 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_DISPLAY_GLX_H +#define GST_VAAPI_DISPLAY_GLX_H + +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_DISPLAY_GLX \ + (gst_vaapi_display_glx_get_type()) + +#define GST_VAAPI_DISPLAY_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_DISPLAY_GLX, \ + GstVaapiDisplayGLX)) + +#define GST_VAAPI_DISPLAY_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_DISPLAY_GLX, \ + GstVaapiDisplayGLXClass)) + +#define GST_VAAPI_IS_DISPLAY_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_DISPLAY_GLX)) + +#define GST_VAAPI_IS_DISPLAY_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_DISPLAY_GLX)) + +#define GST_VAAPI_DISPLAY_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_DISPLAY_GLX, \ + GstVaapiDisplayGLXClass)) + +typedef struct _GstVaapiDisplayGLX GstVaapiDisplayGLX; +typedef struct _GstVaapiDisplayGLXClass GstVaapiDisplayGLXClass; + +/** + * GstVaapiDisplayGLX: + * + * VA/GLX display wrapper. + */ +struct _GstVaapiDisplayGLX { + /*< private >*/ + GstVaapiDisplayX11 parent_instance; +}; + + +/** + * GstVaapiDisplayGLXClass: + * + * VA/GLX display wrapper clas. + */ +struct _GstVaapiDisplayGLXClass { + /*< private >*/ + GstVaapiDisplayX11Class parent_class; +}; + +GType +gst_vaapi_display_glx_get_type(void); + +GstVaapiDisplay * +gst_vaapi_display_glx_new(const gchar *display_name); + +GstVaapiDisplay * +gst_vaapi_display_glx_new_with_display(Display *x11_display); + +G_END_DECLS + +#endif /* GST_VAAPI_DISPLAY_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.c b/gst-libs/gst/vaapi/gstvaapiutils_glx.c new file mode 100644 index 0000000..8053a54 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.c @@ -0,0 +1,183 @@ +/* + * gstvaapiutils_glx.c - GLX utilties + * + * 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 "gstvaapiutils_glx.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +/** + * gl_get_error_string: + * @error: an OpenGL error enumeration + * + * Retrieves the string representation the OpenGL @error. + * + * Return error: the static string representing the OpenGL @error + */ +const char * +gl_get_error_string(GLenum error) +{ + static const struct { + GLenum val; + const char *str; + } + gl_errors[] = { + { GL_NO_ERROR, "no error" }, + { GL_INVALID_ENUM, "invalid enumerant" }, + { GL_INVALID_VALUE, "invalid value" }, + { GL_INVALID_OPERATION, "invalid operation" }, + { GL_STACK_OVERFLOW, "stack overflow" }, + { GL_STACK_UNDERFLOW, "stack underflow" }, + { GL_OUT_OF_MEMORY, "out of memory" }, +#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT + { GL_INVALID_FRAMEBUFFER_OPERATION_EXT, "invalid framebuffer operation" }, +#endif + { ~0, NULL } + }; + + guint i; + for (i = 0; gl_errors[i].str; i++) { + if (gl_errors[i].val == error) + return gl_errors[i].str; + } + return "unknown"; +} + +/** + * gl_purge_errors: + * + * Purges all OpenGL errors. This function is generally useful to + * clear up the pending errors prior to calling gl_check_error(). + */ +void +gl_purge_errors(void) +{ + while (glGetError() != GL_NO_ERROR) + ; /* nothing */ +} + +/** + * gl_check_error: + * + * Checks whether there is any OpenGL error pending. + * + * Return value: %TRUE if an error was encountered + */ +gboolean +gl_check_error(void) +{ + GLenum error; + gboolean has_errors = FALSE; + + while ((error = glGetError()) != GL_NO_ERROR) { + GST_DEBUG("glError: %s caught", gl_get_error_string(error)); + has_errors = TRUE; + } + return has_errors; +} + +/** + * gl_get_param: + * @param: the parameter name + * @pval: return location for the value + * + * This function is a wrapper around glGetIntegerv() that does extra + * error checking. + * + * Return value: %TRUE on success + */ +gboolean +gl_get_param(GLenum param, guint *pval) +{ + GLint val; + + gl_purge_errors(); + glGetIntegerv(param, &val); + if (gl_check_error()) + return FALSE; + + if (pval) + *pval = val; + return TRUE; +} + +/** + * gl_get_param: + * @param: the parameter name + * @pval: return location for the value + * + * This function is a wrapper around glGetTexLevelParameteriv() that + * does extra error checking. + * + * Return value: %TRUE on success + */ +gboolean +gl_get_texture_param(GLenum param, guint *pval) +{ + GLint val; + + gl_purge_errors(); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, param, &val); + if (gl_check_error()) + return FALSE; + + if (pval) + *pval = val; + return TRUE; +} + +/** + * gl_set_bgcolor: + * @color: the requested RGB color + * + * Sets background color to the RGB @color. This basically is a + * wrapper around glClearColor(). + */ +void +gl_set_bgcolor(guint32 color) +{ + glClearColor( + ((color >> 16) & 0xff) / 255.0f, + ((color >> 8) & 0xff) / 255.0f, + ( color & 0xff) / 255.0f, + 1.0f + ); +} + +/** + * gl_resize: + * @width: the requested width, in pixels + * @height: the requested height, in pixels + * + * Resizes the OpenGL viewport to the specified dimensions, using an + * orthogonal projection. (0,0) represents the top-left corner of the + * window. + */ +void +gl_resize(guint width, guint height) +{ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, 0, -1, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} diff --git a/gst-libs/gst/vaapi/gstvaapiutils_glx.h b/gst-libs/gst/vaapi/gstvaapiutils_glx.h new file mode 100644 index 0000000..79328e7 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiutils_glx.h @@ -0,0 +1,57 @@ +/* + * gstvaapiutils_glx.h - GLX utilties + * + * 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_UTILS_GLX_H +#define GST_VAAPI_UTILS_GLX_H + +#include "config.h" +#include +#include +#include + +const char * +gl_get_error_string(GLenum error) + attribute_hidden; + +void +gl_purge_errors(void) + attribute_hidden; + +gboolean +gl_check_error(void) + attribute_hidden; + +gboolean +gl_get_param(GLenum param, guint *pval) + attribute_hidden; + +gboolean +gl_get_texture_param(GLenum param, guint *pval) + attribute_hidden; + +void +gl_set_bgcolor(guint32 color) + attribute_hidden; + +void +gl_resize(guint width, guint height) + attribute_hidden; + +#endif /* GST_VAAPI_UTILS_GLX_H */ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_glx.c b/gst-libs/gst/vaapi/gstvaapiwindow_glx.c new file mode 100644 index 0000000..5d91116 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_glx.c @@ -0,0 +1,488 @@ +/* + * gstvaapiwindow_glx.c - VA/GLX 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 + */ + +/** + * SECTION:gstvaapiwindow_glx + * @short_description: VA/GLX window abstraction + */ + +#include "config.h" +#include "gstvaapiwindow_glx.h" +#include "gstvaapidisplay_x11.h" +#include "gstvaapiutils_x11.h" +#include "gstvaapiutils_glx.h" +#include "gstvaapiobject_priv.h" + +#define DEBUG 1 +#include "gstvaapidebug.h" + +G_DEFINE_TYPE(GstVaapiWindowGLX, + gst_vaapi_window_glx, + GST_VAAPI_TYPE_WINDOW_X11); + +#define GST_VAAPI_WINDOW_GLX_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLXPrivate)) + +struct _GstVaapiWindowGLXPrivate { + XVisualInfo *vi; + XVisualInfo vi_static; + Colormap cmap; + GLXContext context; + guint foreign_context : 1; + guint foreign_window : 1; +}; + +enum { + PROP_0, + + PROP_GLX_CONTEXT +}; + +static XVisualInfo * +gst_vaapi_window_glx_create_visual(GstVaapiWindowGLX *window); + +static inline void +_gst_vaapi_window_glx_set_context( + GstVaapiWindowGLX *window, + GLXContext context, + gboolean is_foreign +) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + + priv->context = context; + priv->foreign_context = is_foreign; +} + +static void +gst_vaapi_window_glx_destroy_context(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + + if (priv->context) { + if (!priv->foreign_context) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + if (glXGetCurrentContext() == priv->context) + glXMakeCurrent(dpy, None, NULL); + glXDestroyContext(dpy, priv->context); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + priv->context = NULL; + priv->foreign_context = FALSE; + } +} + +static gboolean +gst_vaapi_window_glx_create_context(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + GLXContext ctx = NULL; + guint width, height; + gboolean has_errors = TRUE; + + if (!gst_vaapi_window_glx_create_visual(window)) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + ctx = glXCreateContext(dpy, priv->vi, NULL, True); + if (ctx && glXIsDirect(dpy, ctx)) { + _gst_vaapi_window_glx_set_context(window, ctx, FALSE); + if (glXMakeCurrent(dpy, GST_VAAPI_OBJECT_ID(window), ctx)) { + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + glDisable(GL_CULL_FACE); + glDrawBuffer(GL_BACK); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + gst_vaapi_window_get_size(GST_VAAPI_WINDOW(window), &width, &height); + gl_resize(width, height); + + gl_set_bgcolor(0); + glClear(GL_COLOR_BUFFER_BIT); + has_errors = FALSE; + } + } + else if (ctx) + glXDestroyContext(dpy, ctx); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + + return !has_errors; +} + +static inline void +gst_vaapi_window_glx_destroy_visual(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + + if (priv->vi) { + if (priv->vi != &priv->vi_static) + XFree(priv->vi); + priv->vi = NULL; + } +} + +static XVisualInfo * +gst_vaapi_window_glx_create_visual(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + XWindowAttributes wattr; + int screen; + gboolean has_errors; + + /* XXX: add and use a GstVaapiWindow:double-buffer property? */ + static GLint gl_visual_attr[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GL_NONE + }; + + if (!priv->vi) { + /* XXX: add and use a GstVaapiDisplayX11:x11-screen property? */ + screen = DefaultScreen(dpy); + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + if (!priv->foreign_window) + priv->vi = glXChooseVisual(dpy, screen, gl_visual_attr); + else { + XGetWindowAttributes(dpy, GST_VAAPI_OBJECT_ID(window), &wattr); + if (XMatchVisualInfo(dpy, screen, wattr.depth, wattr.visual->class, + &priv->vi_static)) + priv->vi = &priv->vi_static; + } + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + + if (has_errors) + return NULL; + } + return priv->vi; +} + +static Visual * +gst_vaapi_window_glx_get_visual(GstVaapiWindow *window) +{ + XVisualInfo *vi; + + vi = gst_vaapi_window_glx_create_visual(GST_VAAPI_WINDOW_GLX(window)); + if (!vi) + return NULL; + return vi->visual; +} + +static void +gst_vaapi_window_glx_destroy_colormap(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + + if (priv->cmap) { + if (!priv->foreign_window) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XFreeColormap(dpy, priv->cmap); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + } + priv->cmap = None; + } +} + +static Colormap +gst_vaapi_window_glx_create_colormap(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate * const priv = window->priv; + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + int screen; + XWindowAttributes wattr; + XVisualInfo *vi; + gboolean has_errors; + + if (!priv->cmap) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + x11_trap_errors(); + if (!priv->foreign_window) { + vi = gst_vaapi_window_glx_create_visual(window); + if (vi) { + /* XXX: add a GstVaapiDisplayX11:x11-screen property? */ + screen = DefaultScreen(dpy); + priv->cmap = XCreateColormap( + dpy, + RootWindow(dpy, screen), + vi->visual, + AllocNone + ); + } + } + else { + XGetWindowAttributes(dpy, GST_VAAPI_OBJECT_ID(window), &wattr); + priv->cmap = wattr.colormap; + } + has_errors = x11_untrap_errors() != 0; + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + + if (has_errors) + return None; + } + return priv->cmap; +} + +static Colormap +gst_vaapi_window_glx_get_colormap(GstVaapiWindow *window) +{ + return gst_vaapi_window_glx_create_colormap(GST_VAAPI_WINDOW_GLX(window)); +} + +static void +gst_vaapi_window_glx_finalize(GObject *object) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object); + + gst_vaapi_window_glx_destroy_context(window); + gst_vaapi_window_glx_destroy_visual(window); + gst_vaapi_window_glx_destroy_colormap(window); + + G_OBJECT_CLASS(gst_vaapi_window_glx_parent_class)->finalize(object); +} + +static void +gst_vaapi_window_glx_set_property( + GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec +) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object); + + switch (prop_id) { + case PROP_GLX_CONTEXT: + gst_vaapi_window_glx_set_context(window, g_value_get_pointer(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_window_glx_get_property( + GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec +) +{ + GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object); + + switch (prop_id) { + case PROP_GLX_CONTEXT: + g_value_set_pointer(value, gst_vaapi_window_glx_get_context(window)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +gst_vaapi_window_glx_constructed(GObject *object) +{ + GstVaapiWindowGLXPrivate * const priv = GST_VAAPI_WINDOW_GLX(object)->priv; + GObjectClass *parent_class; + + priv->foreign_context = priv->context != NULL; + + parent_class = G_OBJECT_CLASS(gst_vaapi_window_glx_parent_class); + if (parent_class->constructed) + parent_class->constructed(object); + + priv->foreign_window = + gst_vaapi_window_x11_is_foreign_xid(GST_VAAPI_WINDOW_X11(object)); + + if (!priv->foreign_context) + gst_vaapi_window_glx_create_context(GST_VAAPI_WINDOW_GLX(object)); +} + +static void +gst_vaapi_window_glx_class_init(GstVaapiWindowGLXClass *klass) +{ + GObjectClass * const object_class = G_OBJECT_CLASS(klass); + GstVaapiWindowX11Class * const xwin_class = GST_VAAPI_WINDOW_X11_CLASS(klass); + + g_type_class_add_private(klass, sizeof(GstVaapiWindowGLXPrivate)); + + object_class->finalize = gst_vaapi_window_glx_finalize; + object_class->set_property = gst_vaapi_window_glx_set_property; + object_class->get_property = gst_vaapi_window_glx_get_property; + object_class->constructed = gst_vaapi_window_glx_constructed; + + xwin_class->get_visual = gst_vaapi_window_glx_get_visual; + xwin_class->get_colormap = gst_vaapi_window_glx_get_colormap; + + /** + * GstVaapiDisplayGLX:glx-context: + * + * The GLX context that was created by gst_vaapi_window_glx_new() + * or that was bound from gst_vaapi_window_glx_set_context(). + */ + g_object_class_install_property + (object_class, + PROP_GLX_CONTEXT, + g_param_spec_pointer("glx-context", + "GLX context", + "GLX context", + G_PARAM_READWRITE)); +} + +static void +gst_vaapi_window_glx_init(GstVaapiWindowGLX *window) +{ + GstVaapiWindowGLXPrivate *priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE(window); + + window->priv = priv; + priv->vi = NULL; + priv->cmap = None; + priv->context = NULL; + priv->foreign_context = FALSE; +} + +/** + * gst_vaapi_window_glx_new: + * @display: a #GstVaapiDisplay + * @width: the requested window width, in pixels + * @height: the requested windo height, in pixels + * + * Creates a window with the specified @width and @height. The window + * will be attached to the @display and remains invisible to the user + * until gst_vaapi_window_show() is called. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_glx_new(GstVaapiDisplay *display, guint width, guint 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_GLX, + "display", display, + "id", GST_VAAPI_ID(None), + "width", width, + "height", height, + NULL); +} + +/** + * gst_vaapi_window_glx_new_with_xid: + * @display: a #GstVaapiDisplay + * @xid: an X11 #Window id + * + * Creates a #GstVaapiWindow using the X11 #Window @xid. The caller + * still owns the window and must call XDestroyWindow() when all + * #GstVaapiWindow references are released. Doing so too early can + * yield undefined behaviour. + * + * Return value: the newly allocated #GstVaapiWindow object + */ +GstVaapiWindow * +gst_vaapi_window_glx_new_with_xid(GstVaapiDisplay *display, Window xid) +{ + GST_DEBUG("new window from xid 0x%08x", xid); + + g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL); + g_return_val_if_fail(xid != None, NULL); + + return g_object_new(GST_VAAPI_TYPE_WINDOW_GLX, + "display", display, + "id", GST_VAAPI_ID(xid), + NULL); +} + +/** + * gst_vaapi_window_glx_get_context: + * @window: a #GstVaapiWindow + * + * Returns the #GLXContext bound to the @window. + * + * Return value: the #GLXContext bound to the @window + */ +GLXContext +gst_vaapi_window_glx_get_context(GstVaapiWindowGLX *window) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), NULL); + + return window->priv->context; +} + +/** + * gst_vaapi_window_glx_set_context: + * @window: a #GstVaapiWindow + * @ctx: a GLX context + * + * Binds GLX context @ctx to @window. If @ctx is non %NULL, the caller + * is responsible to making sure it has compatible visual with that of + * the underlying X window. If @ctx is %NULL, a new context is created + * and the @window owns it. + * + * Return value: %TRUE on success + */ +gboolean +gst_vaapi_window_glx_set_context(GstVaapiWindowGLX *window, GLXContext ctx) +{ + g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), FALSE); + + gst_vaapi_window_glx_destroy_context(window); + + if (ctx) { + _gst_vaapi_window_glx_set_context(window, ctx, TRUE); + return TRUE; + } + return gst_vaapi_window_glx_create_context(window); +} + +/** + * gst_vaapi_window_glx_swap_buffers: + * @window: a #GstVaapiWindowGLX + * + * Promotes the contents of the back buffer of @window to become the + * contents of the front buffer of @window. This simply is wrapper + * around glXSwapBuffers(). + */ +void +gst_vaapi_window_glx_swap_buffers(GstVaapiWindowGLX *window) +{ + g_return_if_fail(GST_VAAPI_IS_WINDOW_GLX(window)); + + glXSwapBuffers( + GST_VAAPI_OBJECT_XDISPLAY(window), + GST_VAAPI_OBJECT_ID(window) + ); + glClear(GL_COLOR_BUFFER_BIT); +} diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_glx.h b/gst-libs/gst/vaapi/gstvaapiwindow_glx.h new file mode 100644 index 0000000..b10fcd4 --- /dev/null +++ b/gst-libs/gst/vaapi/gstvaapiwindow_glx.h @@ -0,0 +1,100 @@ +/* + * gstvaapiwindow_glx.h - VA/GLX 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_GLX_H +#define GST_VAAPI_WINDOW_GLX_H + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_VAAPI_TYPE_WINDOW_GLX \ + (gst_vaapi_window_glx_get_type()) + +#define GST_VAAPI_WINDOW_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLX)) + +#define GST_VAAPI_WINDOW_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLXClass)) + +#define GST_VAAPI_IS_WINDOW_GLX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_VAAPI_TYPE_WINDOW_GLX)) + +#define GST_VAAPI_IS_WINDOW_GLX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), GST_VAAPI_TYPE_WINDOW_GLX)) + +#define GST_VAAPI_WINDOW_GLX_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + GST_VAAPI_TYPE_WINDOW_GLX, \ + GstVaapiWindowGLXClass)) + +typedef struct _GstVaapiWindowGLX GstVaapiWindowGLX; +typedef struct _GstVaapiWindowGLXPrivate GstVaapiWindowGLXPrivate; +typedef struct _GstVaapiWindowGLXClass GstVaapiWindowGLXClass; + +/** + * GstVaapiWindowGLX: + * + * An X11 #Window suitable for GLX rendering. + */ +struct _GstVaapiWindowGLX { + /*< private >*/ + GstVaapiWindowX11 parent_instance; + + GstVaapiWindowGLXPrivate *priv; +}; + +/** + * GstVaapiWindowGLXClass: + * + * An X11 #Window suitable for GLX rendering. + */ +struct _GstVaapiWindowGLXClass { + /*< private >*/ + GstVaapiWindowX11Class parent_class; +}; + +GType +gst_vaapi_window_glx_get_type(void); + +GstVaapiWindow * +gst_vaapi_window_glx_new(GstVaapiDisplay *display, guint width, guint height); + +GstVaapiWindow * +gst_vaapi_window_glx_new_with_xid(GstVaapiDisplay *display, Window xid); + +GLXContext +gst_vaapi_window_glx_get_context(GstVaapiWindowGLX *window); + +gboolean +gst_vaapi_window_glx_set_context(GstVaapiWindowGLX *window, GLXContext ctx); + +void +gst_vaapi_window_glx_swap_buffers(GstVaapiWindowGLX *window); + +G_END_DECLS + +#endif /* GST_VAAPI_WINDOW_GLX_H */ diff --git a/pkgconfig/Makefile.am b/pkgconfig/Makefile.am index 1e772a6..b98888c 100644 --- a/pkgconfig/Makefile.am +++ b/pkgconfig/Makefile.am @@ -1,21 +1,21 @@ -AUTOMAKE_OPTIONS = -Wno-portability +pcfiles_in = gstreamer-vaapi.pc.in +pcfiles_in += gstreamer-vaapi-x11.pc.in +if USE_GLX +pcfiles_in += gstreamer-vaapi-glx.pc.in +endif -pcfiles = gstreamer-vaapi-@GST_MAJORMINOR@.pc -pcfiles += gstreamer-vaapi-x11-@GST_MAJORMINOR@.pc +pcfiles = $(pcfiles_in:%.pc.in=%-@GST_MAJORMINOR@.pc) pkgconfigdir = @pkgconfigdir@ pkgconfig_DATA = $(pcfiles) EXTRA_DIST = \ gstreamer-vaapi.pc.in \ + gstreamer-vaapi-glx.pc.in \ gstreamer-vaapi-x11.pc.in \ $(NULL) -CLEANFILES = $(pcfiles) - -# XXX: this is a GNU make extension -%-@GST_MAJORMINOR@.pc: %.pc - cp $< $@ +DISTCLEANFILES = $(pcfiles) # Extra clean files so that maintainer-clean removes *everything* MAINTAINERCLEANFILES = Makefile.in diff --git a/pkgconfig/gstreamer-vaapi-glx.pc.in b/pkgconfig/gstreamer-vaapi-glx.pc.in new file mode 100644 index 0000000..73b4c1b --- /dev/null +++ b/pkgconfig/gstreamer-vaapi-glx.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/gstreamer-@GST_MAJORMINOR@ +pluginsdir=@libdir@/gstreamer-@GST_MAJORMINOR@ + +Name: GStreamer VA-API (glx) Plugins Libraries +Description: Streaming media framework, VA-API (glx) plugins libraries +Requires: gstreamer-vaapi-@GST_MAJORMINOR@ @LIBVA_GLX_PKGNAME@ +Version: @VERSION@ +Libs: -L${libdir} -lgstvaapi-glx-@GST_MAJORMINOR@ @LIBVA_EXTRA_LIBS@ +Cflags: -I${includedir} @LIBVA_EXTRA_CFLAGS@ diff --git a/tests/Makefile.am b/tests/Makefile.am index de69c18..ed9ca0a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -4,26 +4,39 @@ noinst_PROGRAMS = \ test-windows \ $(NULL) +noinst_PROGRAMS += \ + test-textures \ + $(NULL) + TEST_CFLAGS = \ $(GST_CFLAGS) \ -I$(top_srcdir)/gst-libs \ $(X11_CFLAGS) TEST_LIBS = \ - $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-x11-@GST_MAJORMINOR@.la \ $(X11_LIBS) +TEST_GLX_LIBS = \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-glx-@GST_MAJORMINOR@.la + +TEST_X11_LIBS = \ + $(top_builddir)/gst-libs/gst/vaapi/libgstvaapi-x11-@GST_MAJORMINOR@.la + test_display_SOURCES = test-display.c test_display_CFLAGS = $(TEST_CFLAGS) -test_display_LDADD = $(TEST_LIBS) +test_display_LDADD = $(TEST_LIBS) $(TEST_X11_LIBS) test_surfaces_SOURCES = test-surfaces.c test_surfaces_CFLAGS = $(TEST_CFLAGS) -test_surfaces_LDADD = $(TEST_LIBS) +test_surfaces_LDADD = $(TEST_LIBS) $(TEST_X11_LIBS) test_windows_SOURCES = test-windows.c test_windows_CFLAGS = $(TEST_CFLAGS) -test_windows_LDADD = $(TEST_LIBS) +test_windows_LDADD = $(TEST_LIBS) $(TEST_X11_LIBS) + +test_textures_SOURCES = test-textures.c +test_textures_CFLAGS = $(TEST_CFLAGS) +test_textures_LDADD = $(TEST_LIBS) $(TEST_GLX_LIBS) # Extra clean files so that maintainer-clean removes *everything* MAINTAINERCLEANFILES = Makefile.in diff --git a/tests/test-textures.c b/tests/test-textures.c new file mode 100644 index 0000000..493faa2 --- /dev/null +++ b/tests/test-textures.c @@ -0,0 +1,141 @@ +/* + * test-textures.c - Test GstVaapiTexture + * + * 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 + +static inline void pause(void) +{ + g_print("Press any key to continue...\n"); + getchar(); +} + +static void +print_caps(GstCaps *caps, const gchar *name) +{ + guint i, n_caps = gst_caps_get_size(caps); + + g_print("%u %s caps\n", n_caps, name); + + for (i = 0; i < gst_caps_get_size(caps); i++) { + GstStructure * const structure = gst_caps_get_structure(caps, i); + if (!structure) + g_error("could not get caps structure %d", i); + + g_print(" %s:", gst_structure_get_name(structure)); + + if (gst_structure_has_name(structure, "video/x-raw-yuv")) { + guint32 fourcc; + + gst_structure_get_fourcc(structure, "format", &fourcc); + + g_print(" fourcc '%c%c%c%c'", + fourcc & 0xff, + (fourcc >> 8) & 0xff, + (fourcc >> 16) & 0xff, + (fourcc >> 24) & 0xff); + } + else { + gint bpp, endian, rmask, gmask, bmask, amask; + gboolean has_alpha; + + gst_structure_get_int(structure, "bpp", &bpp); + gst_structure_get_int(structure, "endianness", &endian); + gst_structure_get_int(structure, "red_mask", &rmask); + gst_structure_get_int(structure, "blue_mask", &bmask); + gst_structure_get_int(structure, "green_mask", &gmask); + has_alpha = gst_structure_get_int(structure, "alpha_mask", &amask); + + g_print(" %d bits per pixel, %s endian,", + bpp, endian == G_BIG_ENDIAN ? "big" : "little"); + g_print(" %s masks", has_alpha ? "rgba" : "rgb"); + g_print(" 0x%08x 0x%08x 0x%08x", rmask, gmask, bmask); + if (has_alpha) + g_print(" 0x%08x", amask); + } + g_print("\n"); + } +} + +static void +dump_caps(GstVaapiDisplay *display) +{ + GstCaps *caps; + + caps = gst_vaapi_display_get_image_caps(display); + if (!caps) + g_error("could not get VA image caps"); + + print_caps(caps, "image"); + gst_caps_unref(caps); + + caps = gst_vaapi_display_get_subpicture_caps(display); + if (!caps) + g_error("could not get VA subpicture caps"); + + print_caps(caps, "subpicture"); + gst_caps_unref(caps); +} + +int +main(int argc, char *argv[]) +{ + GstVaapiDisplay *display; + GstVaapiWindow *window; + GstVaapiWindowGLX *glx_window; + GLXContext glx_context; + Display *x11_display; + Window x11_window; + + 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_glx_new(NULL); + if (!display) + g_error("could not create Gst/VA display"); + + dump_caps(display); + + window = gst_vaapi_window_glx_new(display, win_width, win_height); + if (!window) + g_error("could not create window"); + + gst_vaapi_window_show(window); + + glx_window = GST_VAAPI_WINDOW_GLX(window); + glx_context = gst_vaapi_window_glx_get_context(glx_window); + x11_display = gst_vaapi_display_x11_get_display(GST_VAAPI_DISPLAY_X11(display)); + x11_window = gst_vaapi_object_get_id(GST_VAAPI_OBJECT(window)); + + if (!glXMakeCurrent(x11_display, x11_window, glx_context)) + g_error("could not make VA/GLX window context current"); + + pause(); + + g_object_unref(window); + g_object_unref(display); + gst_deinit(); + return 0; +} -- 2.7.4