68ddf347da514b89cbcbe126c3f9a0aed2f439a9
[profile/ivi/gstreamer-vaapi.git] / 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  *  Copyright (C) 2011 Intel Corporation
6  *
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.
11  *
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.
16  *
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
21  */
22
23 /**
24  * SECTION:gstvaapidisplay_x11
25  * @short_description: VA/X11 display abstraction
26  */
27
28 #include "config.h"
29 #include <string.h>
30 #include "gstvaapiutils.h"
31 #include "gstvaapidisplay_priv.h"
32 #include "gstvaapidisplay_x11.h"
33 #include "gstvaapidisplay_x11_priv.h"
34
35 #define DEBUG 1
36 #include "gstvaapidebug.h"
37
38 G_DEFINE_TYPE(GstVaapiDisplayX11,
39               gst_vaapi_display_x11,
40               GST_VAAPI_TYPE_DISPLAY);
41
42 enum {
43     PROP_0,
44
45     PROP_SYNCHRONOUS,
46     PROP_DISPLAY_NAME,
47     PROP_X11_DISPLAY,
48     PROP_X11_SCREEN
49 };
50
51 static inline const gchar *
52 get_default_display_name(void)
53 {
54     static const gchar *g_display_name;
55
56     if (!g_display_name)
57         g_display_name = getenv("DISPLAY");
58     return g_display_name;
59 }
60
61 static gboolean
62 compare_display_name(gconstpointer a, gconstpointer b, gpointer user_data)
63 {
64     const gchar *display_name;
65
66     /* XXX: handle screen number? */
67     if (a && b)
68         return strcmp(a, b) == 0;
69
70     /* Match "" or default display name */
71     if (a)
72         display_name = a;
73     else if (b)
74         display_name = b;
75     else
76         return TRUE;
77
78     if (*display_name == '\0')
79         return TRUE;
80     if (strcmp(display_name, get_default_display_name()) == 0)
81         return TRUE;
82     return FALSE;
83 }
84
85 static void
86 gst_vaapi_display_x11_finalize(GObject *object)
87 {
88     G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class)->finalize(object);
89 }
90
91 static void
92 set_display_name(GstVaapiDisplayX11 *display, const gchar *display_name)
93 {
94     GstVaapiDisplayX11Private * const priv = display->priv;
95
96     g_free(priv->display_name);
97
98     if (display_name)
99         priv->display_name = g_strdup(display_name);
100     else
101         priv->display_name = NULL;
102 }
103
104 static void
105 set_synchronous(GstVaapiDisplayX11 *display, gboolean synchronous)
106 {
107     GstVaapiDisplayX11Private * const priv = display->priv;
108
109     if (priv->synchronous != synchronous) {
110         priv->synchronous = synchronous;
111         if (priv->x11_display)
112             XSynchronize(priv->x11_display, synchronous);
113     }
114 }
115
116 static void
117 gst_vaapi_display_x11_set_property(
118     GObject      *object,
119     guint         prop_id,
120     const GValue *value,
121     GParamSpec   *pspec
122 )
123 {
124     GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
125
126     switch (prop_id) {
127     case PROP_SYNCHRONOUS:
128         set_synchronous(display, g_value_get_boolean(value));
129         break;
130     case PROP_DISPLAY_NAME:
131         set_display_name(display, g_value_get_string(value));
132         break;
133     case PROP_X11_DISPLAY:
134         display->priv->x11_display = g_value_get_pointer(value);
135         break;
136     case PROP_X11_SCREEN:
137         display->priv->x11_screen = g_value_get_int(value);
138         break;
139     default:
140         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
141         break;
142     }
143 }
144
145 static void
146 gst_vaapi_display_x11_get_property(
147     GObject    *object,
148     guint       prop_id,
149     GValue     *value,
150     GParamSpec *pspec
151 )
152 {
153     GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
154
155     switch (prop_id) {
156     case PROP_SYNCHRONOUS:
157         g_value_set_boolean(value, display->priv->synchronous);
158         break;
159     case PROP_DISPLAY_NAME:
160         g_value_set_string(value, display->priv->display_name);
161         break;
162     case PROP_X11_DISPLAY:
163         g_value_set_pointer(value, gst_vaapi_display_x11_get_display(display));
164         break;
165     case PROP_X11_SCREEN:
166         g_value_set_int(value, gst_vaapi_display_x11_get_screen(display));
167         break;
168     default:
169         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
170         break;
171     }
172 }
173
174 static void
175 gst_vaapi_display_x11_constructed(GObject *object)
176 {
177     GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
178     GstVaapiDisplayX11Private * const priv = display->priv;
179     GstVaapiDisplayCache * const cache = gst_vaapi_display_get_cache();
180     const GstVaapiDisplayInfo *info;
181     GObjectClass *parent_class;
182
183     priv->create_display = priv->x11_display == NULL;
184
185     /* Don't create X11 display if there is one in the cache already */
186     if (priv->create_display) {
187         info = gst_vaapi_display_cache_lookup_by_name(
188             cache,
189             priv->display_name,
190             compare_display_name, NULL
191         );
192         if (info) {
193             priv->x11_display    = info->native_display;
194             priv->create_display = FALSE;
195         }
196     }
197
198     /* Reset display-name if the user provided his own X11 display */
199     if (!priv->create_display)
200         set_display_name(display, XDisplayString(priv->x11_display));
201
202     parent_class = G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class);
203     if (parent_class->constructed)
204         parent_class->constructed(object);
205 }
206
207 static gboolean
208 gst_vaapi_display_x11_open_display(GstVaapiDisplay *display)
209 {
210     GstVaapiDisplayX11Private * const priv =
211         GST_VAAPI_DISPLAY_X11(display)->priv;
212
213     if (priv->create_display) {
214         priv->x11_display = XOpenDisplay(priv->display_name);
215         if (!priv->x11_display)
216             return FALSE;
217         priv->x11_screen = DefaultScreen(priv->x11_display);
218     }
219     if (!priv->x11_display)
220         return FALSE;
221
222     if (priv->synchronous)
223         XSynchronize(priv->x11_display, True);
224     return TRUE;
225 }
226
227 static void
228 gst_vaapi_display_x11_close_display(GstVaapiDisplay *display)
229 {
230     GstVaapiDisplayX11Private * const priv =
231         GST_VAAPI_DISPLAY_X11(display)->priv;
232
233     if (priv->x11_display) {
234         if (priv->create_display)
235             XCloseDisplay(priv->x11_display);
236         priv->x11_display = NULL;
237     }
238
239     if (priv->display_name) {
240         g_free(priv->display_name);
241         priv->display_name = NULL;
242     }
243 }
244
245 static void
246 gst_vaapi_display_x11_sync(GstVaapiDisplay *display)
247 {
248     GstVaapiDisplayX11Private * const priv =
249         GST_VAAPI_DISPLAY_X11(display)->priv;
250
251     if (priv->x11_display) {
252         GST_VAAPI_DISPLAY_LOCK(display);
253         XSync(priv->x11_display, False);
254         GST_VAAPI_DISPLAY_UNLOCK(display);
255     }
256 }
257
258 static void
259 gst_vaapi_display_x11_flush(GstVaapiDisplay *display)
260 {
261     GstVaapiDisplayX11Private * const priv =
262         GST_VAAPI_DISPLAY_X11(display)->priv;
263
264     if (priv->x11_display) {
265         GST_VAAPI_DISPLAY_LOCK(display);
266         XFlush(priv->x11_display);
267         GST_VAAPI_DISPLAY_UNLOCK(display);
268     }
269 }
270
271 static gboolean
272 gst_vaapi_display_x11_get_display_info(
273     GstVaapiDisplay     *display,
274     GstVaapiDisplayInfo *info
275 )
276 {
277     GstVaapiDisplayX11Private * const priv =
278         GST_VAAPI_DISPLAY_X11(display)->priv;
279     GstVaapiDisplayCache *cache;
280     const GstVaapiDisplayInfo *cached_info;
281
282     /* Return any cached info even if child has its own VA display */
283     cache = gst_vaapi_display_get_cache();
284     if (!cache)
285         return FALSE;
286     cached_info = gst_vaapi_display_cache_lookup_by_native_display(cache, priv->x11_display);
287     if (cached_info) {
288         *info = *cached_info;
289         return TRUE;
290     }
291
292     /* Otherwise, create VA display if there is none already */
293     info->native_display = priv->x11_display;
294     info->display_name   = priv->display_name;
295     if (!info->va_display) {
296         info->va_display = vaGetDisplay(priv->x11_display);
297         if (!info->va_display)
298             return FALSE;
299     }
300     return TRUE;
301 }
302
303 static void
304 gst_vaapi_display_x11_get_size(
305     GstVaapiDisplay *display,
306     guint           *pwidth,
307     guint           *pheight
308 )
309 {
310     GstVaapiDisplayX11Private * const priv =
311         GST_VAAPI_DISPLAY_X11(display)->priv;
312
313     if (!priv->x11_display)
314         return;
315
316     if (pwidth)
317         *pwidth = DisplayWidth(priv->x11_display, priv->x11_screen);
318
319     if (pheight)
320         *pheight = DisplayHeight(priv->x11_display, priv->x11_screen);
321 }
322
323 static void
324 gst_vaapi_display_x11_get_size_mm(
325     GstVaapiDisplay *display,
326     guint           *pwidth,
327     guint           *pheight
328 )
329 {
330     GstVaapiDisplayX11Private * const priv =
331         GST_VAAPI_DISPLAY_X11(display)->priv;
332
333     if (!priv->x11_display)
334         return;
335
336     if (pwidth)
337         *pwidth = DisplayWidthMM(priv->x11_display, priv->x11_screen);
338
339     if (pheight)
340         *pheight = DisplayHeightMM(priv->x11_display, priv->x11_screen);
341 }
342
343 static void
344 gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass)
345 {
346     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
347     GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
348
349     g_type_class_add_private(klass, sizeof(GstVaapiDisplayX11Private));
350
351     object_class->finalize      = gst_vaapi_display_x11_finalize;
352     object_class->set_property  = gst_vaapi_display_x11_set_property;
353     object_class->get_property  = gst_vaapi_display_x11_get_property;
354     object_class->constructed   = gst_vaapi_display_x11_constructed;
355
356     dpy_class->open_display     = gst_vaapi_display_x11_open_display;
357     dpy_class->close_display    = gst_vaapi_display_x11_close_display;
358     dpy_class->sync             = gst_vaapi_display_x11_sync;
359     dpy_class->flush            = gst_vaapi_display_x11_flush;
360     dpy_class->get_display      = gst_vaapi_display_x11_get_display_info;
361     dpy_class->get_size         = gst_vaapi_display_x11_get_size;
362     dpy_class->get_size_mm      = gst_vaapi_display_x11_get_size_mm;
363
364     /**
365      * GstVaapiDisplayX11:synchronous:
366      *
367      * When enabled, runs the X display in synchronous mode. Note that
368      * this is used only for debugging.
369      */
370     g_object_class_install_property
371         (object_class,
372          PROP_SYNCHRONOUS,
373          g_param_spec_boolean("synchronous",
374                               "Synchronous mode",
375                               "Toggles X display synchronous mode",
376                               FALSE,
377                               G_PARAM_READWRITE));
378
379     /**
380      * GstVaapiDisplayX11:x11-display:
381      *
382      * The X11 #Display that was created by gst_vaapi_display_x11_new()
383      * or that was bound from gst_vaapi_display_x11_new_with_display().
384      */
385     g_object_class_install_property
386         (object_class,
387          PROP_X11_DISPLAY,
388          g_param_spec_pointer("x11-display",
389                               "X11 display",
390                               "X11 display",
391                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
392
393     /**
394      * GstVaapiDisplayX11:x11-screen:
395      *
396      * The X11 screen that was created by gst_vaapi_display_x11_new()
397      * or that was bound from gst_vaapi_display_x11_new_with_display().
398      */
399     g_object_class_install_property
400         (object_class,
401          PROP_X11_SCREEN,
402          g_param_spec_int("x11-screen",
403                           "X11 screen",
404                           "X11 screen",
405                           0, G_MAXINT32, 0,
406                           G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
407
408     /**
409      * GstVaapiDisplayX11:display-name:
410      *
411      * The X11 display name.
412      */
413     g_object_class_install_property
414         (object_class,
415          PROP_DISPLAY_NAME,
416          g_param_spec_string("display-name",
417                              "X11 display name",
418                              "X11 display name",
419                              NULL,
420                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
421 }
422
423 static void
424 gst_vaapi_display_x11_init(GstVaapiDisplayX11 *display)
425 {
426     GstVaapiDisplayX11Private *priv = GST_VAAPI_DISPLAY_X11_GET_PRIVATE(display);
427
428     display->priv        = priv;
429     priv->create_display = TRUE;
430     priv->x11_display    = NULL;
431     priv->x11_screen     = 0;
432     priv->display_name   = NULL;
433 }
434
435 /**
436  * gst_vaapi_display_x11_new:
437  * @display_name: the X11 display name
438  *
439  * Opens an X11 #Display using @display_name and returns a newly
440  * allocated #GstVaapiDisplay object. The X11 display will be cloed
441  * when the reference count of the object reaches zero.
442  *
443  * Return value: a newly allocated #GstVaapiDisplay object
444  */
445 GstVaapiDisplay *
446 gst_vaapi_display_x11_new(const gchar *display_name)
447 {
448     return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11,
449                         "display-name", display_name,
450                         NULL);
451 }
452
453 /**
454  * gst_vaapi_display_x11_new_with_display:
455  * @x11_display: an X11 #Display
456  *
457  * Creates a #GstVaapiDisplay based on the X11 @x11_display
458  * display. The caller still owns the display and must call
459  * XCloseDisplay() when all #GstVaapiDisplay references are
460  * released. Doing so too early can yield undefined behaviour.
461  *
462  * Return value: a newly allocated #GstVaapiDisplay object
463  */
464 GstVaapiDisplay *
465 gst_vaapi_display_x11_new_with_display(Display *x11_display)
466 {
467     g_return_val_if_fail(x11_display, NULL);
468
469     return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11,
470                         "x11-display", x11_display,
471                         "x11-screen",  DefaultScreen(x11_display),
472                         NULL);
473 }
474
475 /**
476  * gst_vaapi_display_x11_get_display:
477  * @display: a #GstVaapiDisplayX11
478  *
479  * Returns the underlying X11 #Display that was created by
480  * gst_vaapi_display_x11_new() or that was bound from
481  * gst_vaapi_display_x11_new_with_display().
482  *
483  * Return value: the X11 #Display attached to @display
484  */
485 Display *
486 gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display)
487 {
488     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
489
490     return display->priv->x11_display;
491 }
492
493 /**
494  * gst_vaapi_display_x11_get_screen:
495  * @display: a #GstVaapiDisplayX11
496  *
497  * Returns the default X11 screen that was created by
498  * gst_vaapi_display_x11_new() or that was bound from
499  * gst_vaapi_display_x11_new_with_display().
500  *
501  * Return value: the X11 #Display attached to @display
502  */
503 int
504 gst_vaapi_display_x11_get_screen(GstVaapiDisplayX11 *display)
505 {
506     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), -1);
507
508     return display->priv->x11_screen;
509 }