2 * gstvaapidisplay_x11.c - VA/X11 display abstraction
4 * Copyright (C) 2010-2011 Splitted-Desktop Systems
5 * Copyright (C) 2011-2012 Intel Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1
10 * of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301 USA
24 * SECTION:gstvaapidisplay_x11
25 * @short_description: VA/X11 display abstraction
30 #include "gstvaapiutils.h"
31 #include "gstvaapidisplay_priv.h"
32 #include "gstvaapidisplay_x11.h"
33 #include "gstvaapidisplay_x11_priv.h"
36 # include <X11/extensions/Xrandr.h>
40 #include "gstvaapidebug.h"
42 static const guint g_display_types =
43 (1U << GST_VAAPI_DISPLAY_TYPE_X11) |
44 (1U << GST_VAAPI_DISPLAY_TYPE_GLX);
46 static inline const gchar *
47 get_default_display_name(void)
49 static const gchar *g_display_name;
52 g_display_name = getenv("DISPLAY");
53 return g_display_name;
57 compare_display_name(gconstpointer a, gconstpointer b)
59 const GstVaapiDisplayInfo * const info = a;
60 const gchar *cached_name = info->display_name, *cached_name_end;
61 const gchar *tested_name = b, *tested_name_end;
62 guint cached_name_length, tested_name_length;
64 g_return_val_if_fail(cached_name, FALSE);
65 g_return_val_if_fail(tested_name, FALSE);
67 cached_name_end = strchr(cached_name, ':');
69 cached_name_length = cached_name_end - cached_name;
71 cached_name_length = strlen(cached_name);
73 tested_name_end = strchr(tested_name, ':');
75 tested_name_length = tested_name_end - tested_name;
77 tested_name_length = strlen(tested_name);
79 if (cached_name_length != tested_name_length)
81 if (strncmp(cached_name, tested_name, cached_name_length) != 0)
84 /* XXX: handle screen number? */
88 /* Reconstruct a display name without our prefix */
90 get_display_name(GstVaapiDisplayX11 *display)
92 GstVaapiDisplayX11Private * const priv = &display->priv;
93 const gchar *display_name = priv->display_name;
95 if (!display_name || *display_name == '\0')
100 /* Mangle display name with our prefix */
102 set_display_name(GstVaapiDisplayX11 *display, const gchar *display_name)
104 GstVaapiDisplayX11Private * const priv = &display->priv;
106 g_free(priv->display_name);
109 display_name = get_default_display_name();
113 priv->display_name = g_strdup(display_name);
114 return priv->display_name != NULL;
117 /* Set synchronous behavious on the underlying X11 display */
119 set_synchronous(GstVaapiDisplayX11 *display, gboolean synchronous)
121 GstVaapiDisplayX11Private * const priv = &display->priv;
123 if (priv->synchronous != synchronous) {
124 priv->synchronous = synchronous;
125 if (priv->x11_display) {
126 GST_VAAPI_DISPLAY_LOCK(display);
127 XSynchronize(priv->x11_display, synchronous);
128 GST_VAAPI_DISPLAY_UNLOCK(display);
133 /* Check whether XRANDR extension is available */
135 check_xrandr(GstVaapiDisplayX11 *display)
138 GstVaapiDisplayX11Private * const priv =
139 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
140 int evt_base, err_base;
142 priv->use_xrandr = XRRQueryExtension(priv->x11_display,
143 &evt_base, &err_base);
148 gst_vaapi_display_x11_bind_display(GstVaapiDisplay *base_display,
149 gpointer native_display)
151 GstVaapiDisplayX11 * const display =
152 GST_VAAPI_DISPLAY_X11_CAST(base_display);
153 GstVaapiDisplayX11Private * const priv = &display->priv;
155 priv->x11_display = native_display;
156 priv->x11_screen = DefaultScreen(native_display);
157 priv->use_foreign_display = TRUE;
159 check_xrandr(display);
161 if (!set_display_name(display, XDisplayString(priv->x11_display)))
167 gst_vaapi_display_x11_open_display(GstVaapiDisplay *base_display,
170 GstVaapiDisplayX11 * const display =
171 GST_VAAPI_DISPLAY_X11_CAST(base_display);
172 GstVaapiDisplayX11Private * const priv = &display->priv;
173 GstVaapiDisplayCache *cache;
174 const GstVaapiDisplayInfo *info;
176 cache = gst_vaapi_display_get_cache();
177 g_return_val_if_fail(cache != NULL, FALSE);
179 if (!set_display_name(display, name))
182 info = gst_vaapi_display_cache_lookup_custom(cache, compare_display_name,
183 priv->display_name, GST_VAAPI_DISPLAY_TYPES(display));
185 priv->x11_display = info->native_display;
186 priv->use_foreign_display = TRUE;
189 priv->x11_display = XOpenDisplay(get_display_name(display));
190 if (!priv->x11_display)
192 priv->use_foreign_display = FALSE;
194 priv->x11_screen = DefaultScreen(priv->x11_display);
196 check_xrandr(display);
201 gst_vaapi_display_x11_close_display(GstVaapiDisplay *display)
203 GstVaapiDisplayX11Private * const priv =
204 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
206 if (priv->pixmap_formats) {
207 g_array_free(priv->pixmap_formats, TRUE);
208 priv->pixmap_formats = NULL;
211 if (priv->x11_display) {
212 if (!priv->use_foreign_display)
213 XCloseDisplay(priv->x11_display);
214 priv->x11_display = NULL;
217 if (priv->display_name) {
218 g_free(priv->display_name);
219 priv->display_name = NULL;
224 gst_vaapi_display_x11_sync(GstVaapiDisplay *display)
226 GstVaapiDisplayX11Private * const priv =
227 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
229 if (priv->x11_display) {
230 GST_VAAPI_DISPLAY_LOCK(display);
231 XSync(priv->x11_display, False);
232 GST_VAAPI_DISPLAY_UNLOCK(display);
237 gst_vaapi_display_x11_flush(GstVaapiDisplay *display)
239 GstVaapiDisplayX11Private * const priv =
240 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
242 if (priv->x11_display) {
243 GST_VAAPI_DISPLAY_LOCK(display);
244 XFlush(priv->x11_display);
245 GST_VAAPI_DISPLAY_UNLOCK(display);
250 gst_vaapi_display_x11_get_display_info(
251 GstVaapiDisplay *display,
252 GstVaapiDisplayInfo *info
255 GstVaapiDisplayX11Private * const priv =
256 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
257 GstVaapiDisplayCache *cache;
258 const GstVaapiDisplayInfo *cached_info;
260 /* Return any cached info even if child has its own VA display */
261 cache = gst_vaapi_display_get_cache();
264 cached_info = gst_vaapi_display_cache_lookup_by_native_display(
265 cache, priv->x11_display, GST_VAAPI_DISPLAY_TYPES(display));
267 *info = *cached_info;
271 /* Otherwise, create VA display if there is none already */
272 info->native_display = priv->x11_display;
273 info->display_name = priv->display_name;
274 if (!info->va_display) {
275 info->va_display = vaGetDisplay(priv->x11_display);
276 if (!info->va_display)
278 info->display_type = GST_VAAPI_DISPLAY_TYPE_X11;
284 gst_vaapi_display_x11_get_size(
285 GstVaapiDisplay *display,
290 GstVaapiDisplayX11Private * const priv =
291 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
293 if (!priv->x11_display)
297 *pwidth = DisplayWidth(priv->x11_display, priv->x11_screen);
300 *pheight = DisplayHeight(priv->x11_display, priv->x11_screen);
304 gst_vaapi_display_x11_get_size_mm(
305 GstVaapiDisplay *display,
310 GstVaapiDisplayX11Private * const priv =
311 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
312 guint width_mm, height_mm;
314 if (!priv->x11_display)
317 width_mm = DisplayWidthMM(priv->x11_display, priv->x11_screen);
318 height_mm = DisplayHeightMM(priv->x11_display, priv->x11_screen);
321 /* XXX: fix up physical size if the display is rotated */
322 if (priv->use_xrandr) {
323 XRRScreenConfiguration *xrr_config = NULL;
324 XRRScreenSize *xrr_sizes;
326 int num_xrr_sizes, size_id, screen;
330 win = DefaultRootWindow(priv->x11_display);
331 screen = XRRRootToScreen(priv->x11_display, win);
333 xrr_config = XRRGetScreenInfo(priv->x11_display, win);
337 size_id = XRRConfigCurrentConfiguration(xrr_config, &rotation);
338 if (rotation == RR_Rotate_0 || rotation == RR_Rotate_180)
341 xrr_sizes = XRRSizes(priv->x11_display, screen, &num_xrr_sizes);
342 if (!xrr_sizes || size_id >= num_xrr_sizes)
345 width_mm = xrr_sizes[size_id].mheight;
346 height_mm = xrr_sizes[size_id].mwidth;
349 XRRFreeScreenConfigInfo(xrr_config);
357 *pheight = height_mm;
361 gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass)
363 GstVaapiMiniObjectClass * const object_class =
364 GST_VAAPI_MINI_OBJECT_CLASS(klass);
365 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
367 gst_vaapi_display_class_init(&klass->parent_class);
369 object_class->size = sizeof(GstVaapiDisplayX11);
370 dpy_class->display_types = g_display_types;
371 dpy_class->bind_display = gst_vaapi_display_x11_bind_display;
372 dpy_class->open_display = gst_vaapi_display_x11_open_display;
373 dpy_class->close_display = gst_vaapi_display_x11_close_display;
374 dpy_class->sync = gst_vaapi_display_x11_sync;
375 dpy_class->flush = gst_vaapi_display_x11_flush;
376 dpy_class->get_display = gst_vaapi_display_x11_get_display_info;
377 dpy_class->get_size = gst_vaapi_display_x11_get_size;
378 dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm;
381 static inline const GstVaapiDisplayClass *
382 gst_vaapi_display_x11_class(void)
384 static GstVaapiDisplayX11Class g_class;
385 static gsize g_class_init = FALSE;
387 if (g_once_init_enter(&g_class_init)) {
388 gst_vaapi_display_x11_class_init(&g_class);
389 g_once_init_leave(&g_class_init, TRUE);
391 return GST_VAAPI_DISPLAY_CLASS(&g_class);
395 * gst_vaapi_display_x11_new:
396 * @display_name: the X11 display name
398 * Opens an X11 #Display using @display_name and returns a newly
399 * allocated #GstVaapiDisplay object. The X11 display will be cloed
400 * when the reference count of the object reaches zero.
402 * Return value: a newly allocated #GstVaapiDisplay object
405 gst_vaapi_display_x11_new(const gchar *display_name)
407 return gst_vaapi_display_new(gst_vaapi_display_x11_class(),
408 GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer)display_name);
412 * gst_vaapi_display_x11_new_with_display:
413 * @x11_display: an X11 #Display
415 * Creates a #GstVaapiDisplay based on the X11 @x11_display
416 * display. The caller still owns the display and must call
417 * XCloseDisplay() when all #GstVaapiDisplay references are
418 * released. Doing so too early can yield undefined behaviour.
420 * Return value: a newly allocated #GstVaapiDisplay object
423 gst_vaapi_display_x11_new_with_display(Display *x11_display)
425 g_return_val_if_fail(x11_display, NULL);
427 return gst_vaapi_display_new(gst_vaapi_display_x11_class(),
428 GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display);
432 * gst_vaapi_display_x11_get_display:
433 * @display: a #GstVaapiDisplayX11
435 * Returns the underlying X11 #Display that was created by
436 * gst_vaapi_display_x11_new() or that was bound from
437 * gst_vaapi_display_x11_new_with_display().
439 * Return value: the X11 #Display attached to @display
442 gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display)
444 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
446 return GST_VAAPI_DISPLAY_XDISPLAY(display);
450 * gst_vaapi_display_x11_get_screen:
451 * @display: a #GstVaapiDisplayX11
453 * Returns the default X11 screen that was created by
454 * gst_vaapi_display_x11_new() or that was bound from
455 * gst_vaapi_display_x11_new_with_display().
457 * Return value: the X11 #Display attached to @display
460 gst_vaapi_display_x11_get_screen(GstVaapiDisplayX11 *display)
462 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), -1);
464 return GST_VAAPI_DISPLAY_XSCREEN(display);
468 * gst_vaapi_display_x11_set_synchronous:
469 * @display: a #GstVaapiDisplayX11
470 * @synchronous: boolean value that indicates whether to enable or
471 * disable synchronization
473 * If @synchronous is %TRUE, gst_vaapi_display_x11_set_synchronous()
474 * turns on synchronous behaviour on the underlying X11
475 * display. Otherwise, synchronous behaviour is disabled if
476 * @synchronous is %FALSE.
479 gst_vaapi_display_x11_set_synchronous(GstVaapiDisplayX11 *display,
480 gboolean synchronous)
482 g_return_if_fail(GST_VAAPI_IS_DISPLAY_X11(display));
484 set_synchronous(display, synchronous);
487 typedef struct _GstVaapiPixmapFormatX11 GstVaapiPixmapFormatX11;
488 struct _GstVaapiPixmapFormatX11 {
489 GstVideoFormat format;
494 static GstVideoFormat
495 pix_fmt_to_video_format(gint depth, gint bpp)
497 GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
502 format = GST_VIDEO_FORMAT_RGB15;
503 else if (depth == 16)
504 format = GST_VIDEO_FORMAT_RGB16;
508 format = GST_VIDEO_FORMAT_RGB;
511 if (depth == 24 || depth == 32)
512 format = GST_VIDEO_FORMAT_xRGB;
519 ensure_pix_fmts(GstVaapiDisplayX11 *display)
521 GstVaapiDisplayX11Private * const priv =
522 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
523 XPixmapFormatValues *pix_fmts;
524 int i, n, num_pix_fmts;
526 if (priv->pixmap_formats)
529 GST_VAAPI_DISPLAY_LOCK(display);
530 pix_fmts = XListPixmapFormats(GST_VAAPI_DISPLAY_XDISPLAY(display),
532 GST_VAAPI_DISPLAY_UNLOCK(display);
536 priv->pixmap_formats = g_array_sized_new(FALSE, FALSE,
537 sizeof(GstVaapiPixmapFormatX11), num_pix_fmts);
538 if (!priv->pixmap_formats) {
543 for (i = 0, n = 0; i < num_pix_fmts; i++) {
544 GstVaapiPixmapFormatX11 * const pix_fmt =
545 &g_array_index(priv->pixmap_formats, GstVaapiPixmapFormatX11, n);
547 pix_fmt->depth = pix_fmts[i].depth;
548 pix_fmt->bpp = pix_fmts[i].bits_per_pixel;
549 pix_fmt->format = pix_fmt_to_video_format(pix_fmt->depth, pix_fmt->bpp);
550 if (pix_fmt->format != GST_VIDEO_FORMAT_UNKNOWN)
553 priv->pixmap_formats->len = n;
557 /* Determine the GstVideoFormat based on a supported Pixmap depth */
559 gst_vaapi_display_x11_get_pixmap_format(GstVaapiDisplayX11 *display,
562 if (ensure_pix_fmts(display)) {
563 GstVaapiDisplayX11Private * const priv =
564 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
567 for (i = 0; i < priv->pixmap_formats->len; i++) {
568 GstVaapiPixmapFormatX11 * const pix_fmt = &g_array_index(
569 priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
570 if (pix_fmt->depth == depth)
571 return pix_fmt->format;
574 return GST_VIDEO_FORMAT_UNKNOWN;
577 /* Determine the Pixmap depth based on a GstVideoFormat */
579 gst_vaapi_display_x11_get_pixmap_depth(GstVaapiDisplayX11 *display,
580 GstVideoFormat format)
582 if (ensure_pix_fmts(display)) {
583 GstVaapiDisplayX11Private * const priv =
584 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
587 for (i = 0; i < priv->pixmap_formats->len; i++) {
588 GstVaapiPixmapFormatX11 * const pix_fmt = &g_array_index(
589 priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
590 if (pix_fmt->format == format)
591 return pix_fmt->depth;