Merge branch 'move_subdir_editing-services' into tizen_gst_1.19.2_mono
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst-libs / gst / vaapi / gstvaapidisplay_x11.c
1 /*
2  *  gstvaapidisplay_x11.c - VA/X11 display abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2013 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SECTION:gstvaapidisplay_x11
27  * @short_description: VA/X11 display abstraction
28  */
29
30 #include "sysdeps.h"
31 #include "gstvaapiutils.h"
32 #include "gstvaapidisplay_priv.h"
33 #include "gstvaapidisplay_x11.h"
34 #include "gstvaapidisplay_x11_priv.h"
35 #include "gstvaapiwindow_x11.h"
36
37 #if HAVE_XRANDR
38 # include <X11/extensions/Xrandr.h>
39 #endif
40
41 #define DEBUG_VAAPI_DISPLAY 1
42 #include "gstvaapidebug.h"
43
44 G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayX11, gst_vaapi_display_x11,
45     GST_TYPE_VAAPI_DISPLAY);
46
47 static inline const gchar *
48 get_default_display_name (void)
49 {
50   static const gchar *g_display_name;
51
52   if (!g_display_name)
53     g_display_name = getenv ("DISPLAY");
54   return g_display_name;
55 }
56
57 /* Reconstruct a display name without our prefix */
58 static const gchar *
59 get_display_name (GstVaapiDisplayX11 * display)
60 {
61   GstVaapiDisplayX11Private *const priv = display->priv;
62   const gchar *display_name = priv->display_name;
63
64   if (!display_name || *display_name == '\0')
65     return NULL;
66   return display_name;
67 }
68
69 /* Mangle display name with our prefix */
70 static gboolean
71 set_display_name (GstVaapiDisplayX11 * display, const gchar * display_name)
72 {
73   GstVaapiDisplayX11Private *const priv = display->priv;
74
75   g_free (priv->display_name);
76
77   if (!display_name) {
78     display_name = get_default_display_name ();
79     if (!display_name)
80       display_name = "";
81   }
82   priv->display_name = g_strdup (display_name);
83   return priv->display_name != NULL;
84 }
85
86 /* Set synchronous behavious on the underlying X11 display */
87 static void
88 set_synchronous (GstVaapiDisplayX11 * display, gboolean synchronous)
89 {
90   GstVaapiDisplayX11Private *const priv = display->priv;
91
92   if (priv->synchronous != synchronous) {
93     priv->synchronous = synchronous;
94     if (priv->x11_display) {
95       GST_VAAPI_DISPLAY_LOCK (display);
96       XSynchronize (priv->x11_display, synchronous);
97       GST_VAAPI_DISPLAY_UNLOCK (display);
98     }
99   }
100 }
101
102 /* Check for display server extensions */
103 static void
104 check_extensions (GstVaapiDisplayX11 * display)
105 {
106   GstVaapiDisplayX11Private *const priv = display->priv;
107   int evt_base, err_base;
108
109 #if HAVE_XRANDR
110   priv->use_xrandr = XRRQueryExtension (priv->x11_display,
111       &evt_base, &err_base);
112 #endif
113 }
114
115 static gboolean
116 gst_vaapi_display_x11_bind_display (GstVaapiDisplay * base_display,
117     gpointer native_display)
118 {
119   GstVaapiDisplayX11 *const display = GST_VAAPI_DISPLAY_X11_CAST (base_display);
120   GstVaapiDisplayX11Private *const priv = display->priv;
121
122   priv->x11_display = native_display;
123   priv->x11_screen = DefaultScreen (native_display);
124   priv->use_foreign_display = TRUE;
125
126   check_extensions (display);
127   if (!set_display_name (display, XDisplayString (priv->x11_display)))
128     return FALSE;
129   return TRUE;
130 }
131
132 static gboolean
133 gst_vaapi_display_x11_open_display (GstVaapiDisplay * base_display,
134     const gchar * name)
135 {
136   GstVaapiDisplayX11 *const display = GST_VAAPI_DISPLAY_X11_CAST (base_display);
137   GstVaapiDisplayX11Private *const priv = display->priv;
138
139   if (!set_display_name (display, name))
140     return FALSE;
141
142   priv->x11_display = XOpenDisplay (get_display_name (display));
143   if (!priv->x11_display)
144     return FALSE;
145   priv->use_foreign_display = FALSE;
146
147   priv->x11_screen = DefaultScreen (priv->x11_display);
148
149   check_extensions (display);
150   return TRUE;
151 }
152
153 static void
154 gst_vaapi_display_x11_close_display (GstVaapiDisplay * display)
155 {
156   GstVaapiDisplayX11Private *const priv =
157       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
158
159   g_clear_pointer (&priv->pixmap_formats, g_array_unref);
160
161   if (priv->x11_display) {
162     if (!priv->use_foreign_display)
163       XCloseDisplay (priv->x11_display);
164     priv->x11_display = NULL;
165   }
166
167   g_clear_pointer (&priv->display_name, g_free);
168 }
169
170 static void
171 gst_vaapi_display_x11_sync (GstVaapiDisplay * display)
172 {
173   GstVaapiDisplayX11Private *const priv =
174       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
175
176   if (priv->x11_display) {
177     GST_VAAPI_DISPLAY_LOCK (display);
178     XSync (priv->x11_display, False);
179     GST_VAAPI_DISPLAY_UNLOCK (display);
180   }
181 }
182
183 static void
184 gst_vaapi_display_x11_flush (GstVaapiDisplay * display)
185 {
186   GstVaapiDisplayX11Private *const priv =
187       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
188
189   if (priv->x11_display) {
190     GST_VAAPI_DISPLAY_LOCK (display);
191     XFlush (priv->x11_display);
192     GST_VAAPI_DISPLAY_UNLOCK (display);
193   }
194 }
195
196 static gboolean
197 gst_vaapi_display_x11_get_display_info (GstVaapiDisplay * display,
198     GstVaapiDisplayInfo * info)
199 {
200   GstVaapiDisplayX11Private *const priv =
201       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
202
203   info->native_display = priv->x11_display;
204   info->display_name = priv->display_name;
205   if (!info->va_display) {
206     info->va_display = vaGetDisplay (priv->x11_display);
207     if (!info->va_display)
208       return FALSE;
209   }
210   return TRUE;
211 }
212
213 static void
214 gst_vaapi_display_x11_get_size (GstVaapiDisplay * display,
215     guint * pwidth, guint * pheight)
216 {
217   GstVaapiDisplayX11Private *const priv =
218       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
219
220   if (!priv->x11_display)
221     return;
222
223   if (pwidth)
224     *pwidth = DisplayWidth (priv->x11_display, priv->x11_screen);
225
226   if (pheight)
227     *pheight = DisplayHeight (priv->x11_display, priv->x11_screen);
228 }
229
230 static void
231 gst_vaapi_display_x11_get_size_mm (GstVaapiDisplay * display,
232     guint * pwidth, guint * pheight)
233 {
234   GstVaapiDisplayX11Private *const priv =
235       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
236   guint width_mm, height_mm;
237
238   if (!priv->x11_display)
239     return;
240
241   width_mm = DisplayWidthMM (priv->x11_display, priv->x11_screen);
242   height_mm = DisplayHeightMM (priv->x11_display, priv->x11_screen);
243
244 #if HAVE_XRANDR
245   /* XXX: fix up physical size if the display is rotated */
246   if (priv->use_xrandr) {
247     XRRScreenConfiguration *xrr_config = NULL;
248     XRRScreenSize *xrr_sizes;
249     Window win;
250     int num_xrr_sizes, size_id, screen;
251     Rotation rotation;
252
253     do {
254       win = DefaultRootWindow (priv->x11_display);
255       screen = XRRRootToScreen (priv->x11_display, win);
256
257       xrr_config = XRRGetScreenInfo (priv->x11_display, win);
258       if (!xrr_config)
259         break;
260
261       size_id = XRRConfigCurrentConfiguration (xrr_config, &rotation);
262       if (rotation == RR_Rotate_0 || rotation == RR_Rotate_180)
263         break;
264
265       xrr_sizes = XRRSizes (priv->x11_display, screen, &num_xrr_sizes);
266       if (!xrr_sizes || size_id >= num_xrr_sizes)
267         break;
268
269       width_mm = xrr_sizes[size_id].mheight;
270       height_mm = xrr_sizes[size_id].mwidth;
271     } while (0);
272     if (xrr_config)
273       XRRFreeScreenConfigInfo (xrr_config);
274   }
275 #endif
276
277   if (pwidth)
278     *pwidth = width_mm;
279
280   if (pheight)
281     *pheight = height_mm;
282 }
283
284 static GstVaapiWindow *
285 gst_vaapi_display_x11_create_window (GstVaapiDisplay * display, GstVaapiID id,
286     guint width, guint height)
287 {
288   return id != GST_VAAPI_ID_INVALID ?
289       gst_vaapi_window_x11_new_with_xid (display, id) :
290       gst_vaapi_window_x11_new (display, width, height);
291 }
292
293 void
294 gst_vaapi_display_x11_class_init (GstVaapiDisplayX11Class * klass)
295 {
296   GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
297
298   dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_X11;
299   dpy_class->bind_display = gst_vaapi_display_x11_bind_display;
300   dpy_class->open_display = gst_vaapi_display_x11_open_display;
301   dpy_class->close_display = gst_vaapi_display_x11_close_display;
302   dpy_class->sync = gst_vaapi_display_x11_sync;
303   dpy_class->flush = gst_vaapi_display_x11_flush;
304   dpy_class->get_display = gst_vaapi_display_x11_get_display_info;
305   dpy_class->get_size = gst_vaapi_display_x11_get_size;
306   dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm;
307   dpy_class->create_window = gst_vaapi_display_x11_create_window;
308 }
309
310 static void
311 gst_vaapi_display_x11_init (GstVaapiDisplayX11 * display)
312 {
313   GstVaapiDisplayX11Private *const priv =
314       gst_vaapi_display_x11_get_instance_private (display);
315
316   display->priv = priv;
317 }
318
319 /**
320  * gst_vaapi_display_x11_new:
321  * @display_name: the X11 display name
322  *
323  * Opens an X11 #Display using @display_name and returns a newly
324  * allocated #GstVaapiDisplay object. The X11 display will be cloed
325  * when the reference count of the object reaches zero.
326  *
327  * Return value: a newly allocated #GstVaapiDisplay object
328  */
329 GstVaapiDisplay *
330 gst_vaapi_display_x11_new (const gchar * display_name)
331 {
332   GstVaapiDisplay *display;
333
334   display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL);
335   return gst_vaapi_display_config (display,
336       GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name);
337 }
338
339 /**
340  * gst_vaapi_display_x11_new_with_display:
341  * @x11_display: an X11 #Display
342  *
343  * Creates a #GstVaapiDisplay based on the X11 @x11_display
344  * display. The caller still owns the display and must call
345  * XCloseDisplay() when all #GstVaapiDisplay references are
346  * released. Doing so too early can yield undefined behaviour.
347  *
348  * Return value: a newly allocated #GstVaapiDisplay object
349  */
350 GstVaapiDisplay *
351 gst_vaapi_display_x11_new_with_display (Display * x11_display)
352 {
353   GstVaapiDisplay *display;
354
355   g_return_val_if_fail (x11_display, NULL);
356
357   display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL);
358   return gst_vaapi_display_config (display,
359       GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display);
360 }
361
362 GstVaapiDisplay *
363 gst_vaapi_display_x11_new_with_va_display (VADisplay va_display,
364     Display * x11_display)
365 {
366   GstVaapiDisplay *display;
367   GstVaapiDisplayInfo info = {
368     .va_display = va_display,
369     .native_display = x11_display,
370   };
371
372   g_return_val_if_fail (x11_display, NULL);
373
374   display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL);
375   return gst_vaapi_display_config (display,
376       GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info);
377 }
378
379 /**
380  * gst_vaapi_display_x11_get_display:
381  * @display: a #GstVaapiDisplayX11
382  *
383  * Returns the underlying X11 #Display that was created by
384  * gst_vaapi_display_x11_new() or that was bound from
385  * gst_vaapi_display_x11_new_with_display().
386  *
387  * Return value: the X11 #Display attached to @display
388  */
389 Display *
390 gst_vaapi_display_x11_get_display (GstVaapiDisplayX11 * display)
391 {
392   g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL);
393
394   return GST_VAAPI_DISPLAY_XDISPLAY (display);
395 }
396
397 /**
398  * gst_vaapi_display_x11_get_screen:
399  * @display: a #GstVaapiDisplayX11
400  *
401  * Returns the default X11 screen that was created by
402  * gst_vaapi_display_x11_new() or that was bound from
403  * gst_vaapi_display_x11_new_with_display().
404  *
405  * Return value: the X11 #Display attached to @display
406  */
407 int
408 gst_vaapi_display_x11_get_screen (GstVaapiDisplayX11 * display)
409 {
410   g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), -1);
411
412   return GST_VAAPI_DISPLAY_XSCREEN (display);
413 }
414
415 /**
416  * gst_vaapi_display_x11_set_synchronous:
417  * @display: a #GstVaapiDisplayX11
418  * @synchronous: boolean value that indicates whether to enable or
419  *   disable synchronization
420  *
421  * If @synchronous is %TRUE, gst_vaapi_display_x11_set_synchronous()
422  * turns on synchronous behaviour on the underlying X11
423  * display. Otherwise, synchronous behaviour is disabled if
424  * @synchronous is %FALSE.
425  */
426 void
427 gst_vaapi_display_x11_set_synchronous (GstVaapiDisplayX11 * display,
428     gboolean synchronous)
429 {
430   g_return_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display));
431
432   set_synchronous (display, synchronous);
433 }
434
435 typedef struct _GstVaapiPixmapFormatX11 GstVaapiPixmapFormatX11;
436 struct _GstVaapiPixmapFormatX11
437 {
438   GstVideoFormat format;
439   gint depth;
440   gint bpp;
441 };
442
443 static GstVideoFormat
444 pix_fmt_to_video_format (gint depth, gint bpp)
445 {
446   GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
447
448   switch (bpp) {
449     case 16:
450       if (depth == 15)
451         format = GST_VIDEO_FORMAT_RGB15;
452       else if (depth == 16)
453         format = GST_VIDEO_FORMAT_RGB16;
454       break;
455     case 24:
456       if (depth == 24)
457         format = GST_VIDEO_FORMAT_RGB;
458       break;
459     case 32:
460       if (depth == 24 || depth == 32)
461         format = GST_VIDEO_FORMAT_xRGB;
462       break;
463   }
464   return format;
465 }
466
467 static gboolean
468 ensure_pix_fmts (GstVaapiDisplayX11 * display)
469 {
470   GstVaapiDisplayX11Private *const priv =
471       GST_VAAPI_DISPLAY_X11_PRIVATE (display);
472   XPixmapFormatValues *pix_fmts;
473   int i, n, num_pix_fmts;
474
475   if (priv->pixmap_formats)
476     return TRUE;
477
478   GST_VAAPI_DISPLAY_LOCK (display);
479   pix_fmts = XListPixmapFormats (GST_VAAPI_DISPLAY_XDISPLAY (display),
480       &num_pix_fmts);
481   GST_VAAPI_DISPLAY_UNLOCK (display);
482   if (!pix_fmts)
483     return FALSE;
484
485   priv->pixmap_formats = g_array_sized_new (FALSE, FALSE,
486       sizeof (GstVaapiPixmapFormatX11), num_pix_fmts);
487   if (!priv->pixmap_formats) {
488     XFree (pix_fmts);
489     return FALSE;
490   }
491
492   for (i = 0, n = 0; i < num_pix_fmts; i++) {
493     GstVaapiPixmapFormatX11 *const pix_fmt =
494         &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, n);
495
496     pix_fmt->depth = pix_fmts[i].depth;
497     pix_fmt->bpp = pix_fmts[i].bits_per_pixel;
498     pix_fmt->format = pix_fmt_to_video_format (pix_fmt->depth, pix_fmt->bpp);
499     if (pix_fmt->format != GST_VIDEO_FORMAT_UNKNOWN)
500       n++;
501   }
502   priv->pixmap_formats->len = n;
503   XFree (pix_fmts);
504   return TRUE;
505 }
506
507 /* Determine the GstVideoFormat based on a supported Pixmap depth */
508 GstVideoFormat
509 gst_vaapi_display_x11_get_pixmap_format (GstVaapiDisplayX11 * display,
510     guint depth)
511 {
512   if (ensure_pix_fmts (display)) {
513     GstVaapiDisplayX11Private *const priv =
514         GST_VAAPI_DISPLAY_X11_PRIVATE (display);
515     guint i;
516
517     for (i = 0; i < priv->pixmap_formats->len; i++) {
518       GstVaapiPixmapFormatX11 *const pix_fmt =
519           &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
520       if (pix_fmt->depth == depth)
521         return pix_fmt->format;
522     }
523   }
524   return GST_VIDEO_FORMAT_UNKNOWN;
525 }
526
527 /* Determine the Pixmap depth based on a GstVideoFormat */
528 guint
529 gst_vaapi_display_x11_get_pixmap_depth (GstVaapiDisplayX11 * display,
530     GstVideoFormat format)
531 {
532   if (ensure_pix_fmts (display)) {
533     GstVaapiDisplayX11Private *const priv =
534         GST_VAAPI_DISPLAY_X11_PRIVATE (display);
535     guint i;
536
537     for (i = 0; i < priv->pixmap_formats->len; i++) {
538       GstVaapiPixmapFormatX11 *const pix_fmt =
539           &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
540       if (pix_fmt->format == format)
541         return pix_fmt->depth;
542     }
543   }
544   return 0;
545 }