diff --git a/configure.ac b/configure.ac index 6e033e82f8..837ea1066c 100644 --- a/configure.ac +++ b/configure.ac @@ -470,6 +470,23 @@ if test $HAVE_XRANDR -eq 1; then [Defined to 1 if the XRandR extension exists.]) fi +dnl Check for XRender +HAVE_XRENDER=0 +if test $USE_X11 -eq 1; then + HAVE_XRENDER=1 + PKG_CHECK_MODULES([XRENDER], [xrender], [:], [HAVE_XRENDER=0]) + if test $HAVE_XRENDER -eq 1; then + saved_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $XRENDER_CFLAGS" + AC_CHECK_HEADERS([X11/extensions/Xrender.h], [:], [HAVE_XRENDER=0]) + CPPFLAGS="$saved_CPPFLAGS" + fi +fi +if test $HAVE_XRENDER -eq 1; then + AC_DEFINE_UNQUOTED([HAVE_XRENDER], [1], + [Defined to 1 if the XRender extension exists.]) +fi + dnl OpenGL enable_opengl="no" if test "$enable_glx" = "yes"; then diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am index b2a5df56f8..d4fa2485ae 100644 --- a/gst-libs/gst/vaapi/Makefile.am +++ b/gst-libs/gst/vaapi/Makefile.am @@ -289,6 +289,7 @@ libgstvaapi_x11_@GST_API_VERSION@_la_CFLAGS = \ $(GST_BASE_CFLAGS) \ $(X11_CFLAGS) \ $(XRANDR_CFLAGS) \ + $(XRENDER_CFLAGS) \ $(LIBVA_X11_CFLAGS) \ $(NULL) @@ -296,6 +297,7 @@ libgstvaapi_x11_@GST_API_VERSION@_la_LIBADD = \ $(GLIB_LIBS) \ $(X11_LIBS) \ $(XRANDR_LIBS) \ + $(XRENDER_LIBS) \ $(LIBVA_X11_LIBS) \ libgstvaapi-$(GST_API_VERSION).la \ $(NULL) diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11.c b/gst-libs/gst/vaapi/gstvaapidisplay_x11.c index 5fb0cba265..b633b1a6cb 100644 --- a/gst-libs/gst/vaapi/gstvaapidisplay_x11.c +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11.c @@ -36,6 +36,10 @@ # include #endif +#ifdef HAVE_XRENDER +# include +#endif + #define DEBUG 1 #include "gstvaapidebug.h" @@ -130,18 +134,22 @@ set_synchronous(GstVaapiDisplayX11 *display, gboolean synchronous) } } -/* Check whether XRANDR extension is available */ +/* Check for display server extensions */ static void -check_xrandr(GstVaapiDisplayX11 *display) +check_extensions(GstVaapiDisplayX11 *display) { -#ifdef HAVE_XRANDR GstVaapiDisplayX11Private * const priv = GST_VAAPI_DISPLAY_X11_PRIVATE(display); int evt_base, err_base; +#ifdef HAVE_XRANDR priv->use_xrandr = XRRQueryExtension(priv->x11_display, &evt_base, &err_base); #endif +#ifdef HAVE_XRENDER + priv->has_xrender = XRenderQueryExtension(priv->x11_display, + &evt_base, &err_base); +#endif } static gboolean @@ -156,7 +164,7 @@ gst_vaapi_display_x11_bind_display(GstVaapiDisplay *base_display, priv->x11_screen = DefaultScreen(native_display); priv->use_foreign_display = TRUE; - check_xrandr(display); + check_extensions(display); if (!set_display_name(display, XDisplayString(priv->x11_display))) return FALSE; @@ -193,7 +201,7 @@ gst_vaapi_display_x11_open_display(GstVaapiDisplay *base_display, } priv->x11_screen = DefaultScreen(priv->x11_display); - check_xrandr(display); + check_extensions(display); return TRUE; } diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h index 0593317080..45494bc8aa 100644 --- a/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h +++ b/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h @@ -63,6 +63,17 @@ typedef struct _GstVaapiDisplayX11Class GstVaapiDisplayX11Class; #define GST_VAAPI_DISPLAY_XSCREEN(display) \ GST_VAAPI_DISPLAY_X11_PRIVATE(display)->x11_screen +/** + * GST_VAAPI_DISPLAY_HAS_XRENDER: + * @display: a #GstVaapiDisplay + * + * Macro that evaluates to the existence of the XRender extension on + * @display server. + */ +#undef GST_VAAPI_DISPLAY_HAS_XRENDER +#define GST_VAAPI_DISPLAY_HAS_XRENDER(display) \ + (GST_VAAPI_DISPLAY_X11_PRIVATE(display)->has_xrender) + struct _GstVaapiDisplayX11Private { gchar *display_name; Display *x11_display; @@ -70,6 +81,7 @@ struct _GstVaapiDisplayX11Private { GArray *pixmap_formats; guint use_foreign_display : 1; // Foreign native_display? guint use_xrandr : 1; + guint has_xrender : 1; // Has XRender extension? guint synchronous : 1; }; diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11.c b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c index a5ea27752e..df58ef20cf 100644 --- a/gst-libs/gst/vaapi/gstvaapiwindow_x11.c +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11.c @@ -31,6 +31,8 @@ #include "gstvaapicompat.h" #include "gstvaapiwindow_x11.h" #include "gstvaapiwindow_x11_priv.h" +#include "gstvaapipixmap_x11.h" +#include "gstvaapipixmap_priv.h" #include "gstvaapidisplay_x11.h" #include "gstvaapidisplay_x11_priv.h" #include "gstvaapiutils.h" @@ -223,6 +225,9 @@ gst_vaapi_window_x11_create(GstVaapiWindow *window, guint *width, guint *height) "_NET_WM_STATE_FULLSCREEN", }; + priv->has_xrender = GST_VAAPI_DISPLAY_HAS_XRENDER( + GST_VAAPI_OBJECT_DISPLAY(window)); + if (window->use_foreign_window && xid) { GST_VAAPI_OBJECT_LOCK_DISPLAY(window); XGetWindowAttributes(dpy, xid, &wattr); @@ -266,6 +271,17 @@ gst_vaapi_window_x11_destroy(GstVaapiWindow *window) Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); const Window xid = GST_VAAPI_OBJECT_ID(window); +#ifdef HAVE_XRENDER + GstVaapiWindowX11Private * const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE(window); + if (priv->picture) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XRenderFreePicture(dpy, priv->picture); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + priv->picture = None; + } +#endif + if (xid) { if (!window->use_foreign_window) { GST_VAAPI_OBJECT_LOCK_DISPLAY(window); @@ -434,6 +450,113 @@ gst_vaapi_window_x11_render( return TRUE; } +static gboolean +gst_vaapi_window_x11_render_pixmap_xrender( + GstVaapiWindow *window, + GstVaapiPixmap *pixmap, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +) +{ +#ifdef HAVE_XRENDER + GstVaapiWindowX11Private * const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE(window); + Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window); + const Window win = GST_VAAPI_OBJECT_ID(window); + const Pixmap pix = GST_VAAPI_OBJECT_ID(pixmap); + Picture picture; + XRenderPictFormat *pic_fmt; + XWindowAttributes wattr; + int fmt, op; + gboolean success = FALSE; + + /* Ensure Picture for window is created */ + if (!priv->picture) { + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + XGetWindowAttributes(dpy, win, &wattr); + pic_fmt = XRenderFindVisualFormat(dpy, wattr.visual); + if (pic_fmt) + priv->picture = XRenderCreatePicture(dpy, win, pic_fmt, 0, NULL); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + if (!priv->picture) + return FALSE; + } + + /* Check pixmap format */ + switch (GST_VAAPI_PIXMAP_FORMAT(pixmap)) { + case GST_VIDEO_FORMAT_xRGB: + fmt = PictStandardRGB24; + op = PictOpSrc; + goto get_pic_fmt; + case GST_VIDEO_FORMAT_ARGB: + fmt = PictStandardARGB32; + op = PictOpOver; + get_pic_fmt: + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + pic_fmt = XRenderFindStandardFormat(dpy, fmt); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + break; + default: + pic_fmt = NULL; + break; + } + if (!pic_fmt) + return FALSE; + + GST_VAAPI_OBJECT_LOCK_DISPLAY(window); + do { + const double sx = (double)src_rect->width / dst_rect->width; + const double sy = (double)src_rect->height / dst_rect->height; + XTransform xform; + + picture = XRenderCreatePicture(dpy, pix, pic_fmt, 0, NULL); + if (!picture) + break; + + xform.matrix[0][0] = XDoubleToFixed(sx); + xform.matrix[0][1] = XDoubleToFixed(0.0); + xform.matrix[0][2] = XDoubleToFixed(src_rect->x); + xform.matrix[1][0] = XDoubleToFixed(0.0); + xform.matrix[1][1] = XDoubleToFixed(sy); + xform.matrix[1][2] = XDoubleToFixed(src_rect->y); + xform.matrix[2][0] = XDoubleToFixed(0.0); + xform.matrix[2][1] = XDoubleToFixed(0.0); + xform.matrix[2][2] = XDoubleToFixed(1.0); + XRenderSetPictureTransform(dpy, picture, &xform); + + XRenderComposite(dpy, op, picture, None, priv->picture, + 0, 0, 0, 0, dst_rect->x, dst_rect->y, + dst_rect->width, dst_rect->height); + XSync(dpy, False); + success = TRUE; + } while (0); + if (picture) + XRenderFreePicture(dpy, picture); + GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); + return success; +#endif + return FALSE; +} + +static gboolean +gst_vaapi_window_x11_render_pixmap( + GstVaapiWindow *window, + GstVaapiPixmap *pixmap, + const GstVaapiRectangle *src_rect, + const GstVaapiRectangle *dst_rect +) +{ + GstVaapiWindowX11Private * const priv = + GST_VAAPI_WINDOW_X11_GET_PRIVATE(window); + + if (priv->has_xrender) + return gst_vaapi_window_x11_render_pixmap_xrender(window, pixmap, + src_rect, dst_rect); + + /* XXX: only X RENDER extension is supported for now */ + return FALSE; +} + void gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass) { @@ -452,6 +575,7 @@ gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass) window_class->set_fullscreen = gst_vaapi_window_x11_set_fullscreen; window_class->resize = gst_vaapi_window_x11_resize; window_class->render = gst_vaapi_window_x11_render; + window_class->render_pixmap = gst_vaapi_window_x11_render_pixmap; } #define gst_vaapi_window_x11_finalize \ diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h b/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h index 2622ac8147..c5bebb64ce 100644 --- a/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h +++ b/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h @@ -25,6 +25,10 @@ #include "gstvaapiwindow_priv.h" +#ifdef HAVE_XRENDER +# include +#endif + G_BEGIN_DECLS #define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj) \ @@ -42,8 +46,12 @@ typedef struct _GstVaapiWindowX11Class GstVaapiWindowX11Class; struct _GstVaapiWindowX11Private { Atom atom_NET_WM_STATE; Atom atom_NET_WM_STATE_FULLSCREEN; +#ifdef HAVE_XRENDER + Picture picture; +#endif guint is_mapped : 1; guint fullscreen_on_map : 1; + guint has_xrender : 1; }; /**