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->x11_display) {
207 if (!priv->use_foreign_display)
208 XCloseDisplay(priv->x11_display);
209 priv->x11_display = NULL;
212 if (priv->display_name) {
213 g_free(priv->display_name);
214 priv->display_name = NULL;
219 gst_vaapi_display_x11_sync(GstVaapiDisplay *display)
221 GstVaapiDisplayX11Private * const priv =
222 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
224 if (priv->x11_display) {
225 GST_VAAPI_DISPLAY_LOCK(display);
226 XSync(priv->x11_display, False);
227 GST_VAAPI_DISPLAY_UNLOCK(display);
232 gst_vaapi_display_x11_flush(GstVaapiDisplay *display)
234 GstVaapiDisplayX11Private * const priv =
235 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
237 if (priv->x11_display) {
238 GST_VAAPI_DISPLAY_LOCK(display);
239 XFlush(priv->x11_display);
240 GST_VAAPI_DISPLAY_UNLOCK(display);
245 gst_vaapi_display_x11_get_display_info(
246 GstVaapiDisplay *display,
247 GstVaapiDisplayInfo *info
250 GstVaapiDisplayX11Private * const priv =
251 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
252 GstVaapiDisplayCache *cache;
253 const GstVaapiDisplayInfo *cached_info;
255 /* Return any cached info even if child has its own VA display */
256 cache = gst_vaapi_display_get_cache();
259 cached_info = gst_vaapi_display_cache_lookup_by_native_display(
260 cache, priv->x11_display, GST_VAAPI_DISPLAY_TYPES(display));
262 *info = *cached_info;
266 /* Otherwise, create VA display if there is none already */
267 info->native_display = priv->x11_display;
268 info->display_name = priv->display_name;
269 if (!info->va_display) {
270 info->va_display = vaGetDisplay(priv->x11_display);
271 if (!info->va_display)
273 info->display_type = GST_VAAPI_DISPLAY_TYPE_X11;
279 gst_vaapi_display_x11_get_size(
280 GstVaapiDisplay *display,
285 GstVaapiDisplayX11Private * const priv =
286 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
288 if (!priv->x11_display)
292 *pwidth = DisplayWidth(priv->x11_display, priv->x11_screen);
295 *pheight = DisplayHeight(priv->x11_display, priv->x11_screen);
299 gst_vaapi_display_x11_get_size_mm(
300 GstVaapiDisplay *display,
305 GstVaapiDisplayX11Private * const priv =
306 GST_VAAPI_DISPLAY_X11_PRIVATE(display);
307 guint width_mm, height_mm;
309 if (!priv->x11_display)
312 width_mm = DisplayWidthMM(priv->x11_display, priv->x11_screen);
313 height_mm = DisplayHeightMM(priv->x11_display, priv->x11_screen);
316 /* XXX: fix up physical size if the display is rotated */
317 if (priv->use_xrandr) {
318 XRRScreenConfiguration *xrr_config = NULL;
319 XRRScreenSize *xrr_sizes;
321 int num_xrr_sizes, size_id, screen;
325 win = DefaultRootWindow(priv->x11_display);
326 screen = XRRRootToScreen(priv->x11_display, win);
328 xrr_config = XRRGetScreenInfo(priv->x11_display, win);
332 size_id = XRRConfigCurrentConfiguration(xrr_config, &rotation);
333 if (rotation == RR_Rotate_0 || rotation == RR_Rotate_180)
336 xrr_sizes = XRRSizes(priv->x11_display, screen, &num_xrr_sizes);
337 if (!xrr_sizes || size_id >= num_xrr_sizes)
340 width_mm = xrr_sizes[size_id].mheight;
341 height_mm = xrr_sizes[size_id].mwidth;
344 XRRFreeScreenConfigInfo(xrr_config);
352 *pheight = height_mm;
356 gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass)
358 GstVaapiMiniObjectClass * const object_class =
359 GST_VAAPI_MINI_OBJECT_CLASS(klass);
360 GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
362 gst_vaapi_display_class_init(&klass->parent_class);
364 object_class->size = sizeof(GstVaapiDisplayX11);
365 dpy_class->display_types = g_display_types;
366 dpy_class->bind_display = gst_vaapi_display_x11_bind_display;
367 dpy_class->open_display = gst_vaapi_display_x11_open_display;
368 dpy_class->close_display = gst_vaapi_display_x11_close_display;
369 dpy_class->sync = gst_vaapi_display_x11_sync;
370 dpy_class->flush = gst_vaapi_display_x11_flush;
371 dpy_class->get_display = gst_vaapi_display_x11_get_display_info;
372 dpy_class->get_size = gst_vaapi_display_x11_get_size;
373 dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm;
376 static inline const GstVaapiDisplayClass *
377 gst_vaapi_display_x11_class(void)
379 static GstVaapiDisplayX11Class g_class;
380 static gsize g_class_init = FALSE;
382 if (g_once_init_enter(&g_class_init)) {
383 gst_vaapi_display_x11_class_init(&g_class);
384 g_once_init_leave(&g_class_init, TRUE);
386 return GST_VAAPI_DISPLAY_CLASS(&g_class);
390 * gst_vaapi_display_x11_new:
391 * @display_name: the X11 display name
393 * Opens an X11 #Display using @display_name and returns a newly
394 * allocated #GstVaapiDisplay object. The X11 display will be cloed
395 * when the reference count of the object reaches zero.
397 * Return value: a newly allocated #GstVaapiDisplay object
400 gst_vaapi_display_x11_new(const gchar *display_name)
402 return gst_vaapi_display_new(gst_vaapi_display_x11_class(),
403 GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer)display_name);
407 * gst_vaapi_display_x11_new_with_display:
408 * @x11_display: an X11 #Display
410 * Creates a #GstVaapiDisplay based on the X11 @x11_display
411 * display. The caller still owns the display and must call
412 * XCloseDisplay() when all #GstVaapiDisplay references are
413 * released. Doing so too early can yield undefined behaviour.
415 * Return value: a newly allocated #GstVaapiDisplay object
418 gst_vaapi_display_x11_new_with_display(Display *x11_display)
420 g_return_val_if_fail(x11_display, NULL);
422 return gst_vaapi_display_new(gst_vaapi_display_x11_class(),
423 GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display);
427 * gst_vaapi_display_x11_get_display:
428 * @display: a #GstVaapiDisplayX11
430 * Returns the underlying X11 #Display that was created by
431 * gst_vaapi_display_x11_new() or that was bound from
432 * gst_vaapi_display_x11_new_with_display().
434 * Return value: the X11 #Display attached to @display
437 gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display)
439 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
441 return GST_VAAPI_DISPLAY_XDISPLAY(display);
445 * gst_vaapi_display_x11_get_screen:
446 * @display: a #GstVaapiDisplayX11
448 * Returns the default X11 screen that was created by
449 * gst_vaapi_display_x11_new() or that was bound from
450 * gst_vaapi_display_x11_new_with_display().
452 * Return value: the X11 #Display attached to @display
455 gst_vaapi_display_x11_get_screen(GstVaapiDisplayX11 *display)
457 g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), -1);
459 return GST_VAAPI_DISPLAY_XSCREEN(display);
463 * gst_vaapi_display_x11_set_synchronous:
464 * @display: a #GstVaapiDisplayX11
465 * @synchronous: boolean value that indicates whether to enable or
466 * disable synchronization
468 * If @synchronous is %TRUE, gst_vaapi_display_x11_set_synchronous()
469 * turns on synchronous behaviour on the underlying X11
470 * display. Otherwise, synchronous behaviour is disabled if
471 * @synchronous is %FALSE.
474 gst_vaapi_display_x11_set_synchronous(GstVaapiDisplayX11 *display,
475 gboolean synchronous)
477 g_return_if_fail(GST_VAAPI_IS_DISPLAY_X11(display));
479 set_synchronous(display, synchronous);