Add gst_vaapi_display_{sync,flush}() helpers.
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapidisplay_x11.c
1 /*
2  *  gstvaapidisplay_x11.c - VA/X11 display abstraction
3  *
4  *  gstreamer-vaapi (C) 2010 Splitted-Desktop Systems
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
19  */
20
21 /**
22  * SECTION:gstvaapidisplay_x11
23  * @short_description: VA/X11 display abstraction
24  */
25
26 #include "config.h"
27 #include "gstvaapiutils.h"
28 #include "gstvaapidisplay_x11.h"
29
30 #define DEBUG 1
31 #include "gstvaapidebug.h"
32
33 G_DEFINE_TYPE(GstVaapiDisplayX11,
34               gst_vaapi_display_x11,
35               GST_VAAPI_TYPE_DISPLAY);
36
37 #define GST_VAAPI_DISPLAY_X11_GET_PRIVATE(obj)                  \
38     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
39                                  GST_VAAPI_TYPE_DISPLAY_X11,    \
40                                  GstVaapiDisplayX11Private))
41
42 struct _GstVaapiDisplayX11Private {
43     gchar      *display_name;
44     Display    *x11_display;
45     int         x11_screen;
46     guint       create_display  : 1;
47     guint       synchronous     : 1;
48 };
49
50 enum {
51     PROP_0,
52
53     PROP_SYNCHRONOUS,
54     PROP_DISPLAY_NAME,
55     PROP_X11_DISPLAY
56 };
57
58 static void
59 gst_vaapi_display_x11_finalize(GObject *object)
60 {
61     G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class)->finalize(object);
62 }
63
64 static void
65 set_display_name(GstVaapiDisplayX11 *display, const gchar *display_name)
66 {
67     GstVaapiDisplayX11Private * const priv = display->priv;
68
69     g_free(priv->display_name);
70
71     if (display_name)
72         priv->display_name = g_strdup(display_name);
73     else
74         priv->display_name = NULL;
75 }
76
77 static void
78 set_synchronous(GstVaapiDisplayX11 *display, gboolean synchronous)
79 {
80     GstVaapiDisplayX11Private * const priv = display->priv;
81
82     if (priv->synchronous != synchronous) {
83         priv->synchronous = synchronous;
84         if (priv->x11_display)
85             XSynchronize(priv->x11_display, synchronous);
86     }
87 }
88
89 static void
90 gst_vaapi_display_x11_set_property(
91     GObject      *object,
92     guint         prop_id,
93     const GValue *value,
94     GParamSpec   *pspec
95 )
96 {
97     GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
98
99     switch (prop_id) {
100     case PROP_SYNCHRONOUS:
101         set_synchronous(display, g_value_get_boolean(value));
102         break;
103     case PROP_DISPLAY_NAME:
104         set_display_name(display, g_value_get_string(value));
105         break;
106     case PROP_X11_DISPLAY:
107         display->priv->x11_display = g_value_get_pointer(value);
108         break;
109     default:
110         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
111         break;
112     }
113 }
114
115 static void
116 gst_vaapi_display_x11_get_property(
117     GObject    *object,
118     guint       prop_id,
119     GValue     *value,
120     GParamSpec *pspec
121 )
122 {
123     GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
124
125     switch (prop_id) {
126     case PROP_SYNCHRONOUS:
127         g_value_set_boolean(value, display->priv->synchronous);
128         break;
129     case PROP_DISPLAY_NAME:
130         g_value_set_string(value, display->priv->display_name);
131         break;
132     case PROP_X11_DISPLAY:
133         g_value_set_pointer(value, gst_vaapi_display_x11_get_display(display));
134         break;
135     default:
136         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
137         break;
138     }
139 }
140
141 static void
142 gst_vaapi_display_x11_constructed(GObject *object)
143 {
144     GstVaapiDisplayX11 * const display = GST_VAAPI_DISPLAY_X11(object);
145     GObjectClass *parent_class;
146
147     display->priv->create_display = display->priv->x11_display == NULL;
148
149     /* Reset display-name if the user provided his own X11 display */
150     if (!display->priv->create_display)
151         set_display_name(display, XDisplayString(display->priv->x11_display));
152
153     parent_class = G_OBJECT_CLASS(gst_vaapi_display_x11_parent_class);
154     if (parent_class->constructed)
155         parent_class->constructed(object);
156 }
157
158 static gboolean
159 gst_vaapi_display_x11_open_display(GstVaapiDisplay *display)
160 {
161     GstVaapiDisplayX11Private * const priv =
162         GST_VAAPI_DISPLAY_X11(display)->priv;
163
164     /* XXX: maintain an X11 display cache */
165     if (!priv->x11_display && priv->create_display)
166         priv->x11_display = XOpenDisplay(priv->display_name);
167     if (!priv->x11_display)
168         return FALSE;
169
170     if (priv->synchronous)
171         XSynchronize(priv->x11_display, True);
172
173     priv->x11_screen = DefaultScreen(priv->x11_display);
174     return TRUE;
175 }
176
177 static void
178 gst_vaapi_display_x11_close_display(GstVaapiDisplay *display)
179 {
180     GstVaapiDisplayX11Private * const priv =
181         GST_VAAPI_DISPLAY_X11(display)->priv;
182
183     if (priv->x11_display) {
184         if (priv->create_display)
185             XCloseDisplay(priv->x11_display);
186         priv->x11_display = NULL;
187     }
188
189     if (priv->display_name) {
190         g_free(priv->display_name);
191         priv->display_name = NULL;
192     }
193 }
194
195 static void
196 gst_vaapi_display_x11_sync(GstVaapiDisplay *display)
197 {
198     GstVaapiDisplayX11Private * const priv =
199         GST_VAAPI_DISPLAY_X11(display)->priv;
200
201     if (priv->x11_display)
202         XSync(priv->x11_display, False);
203 }
204
205 static void
206 gst_vaapi_display_x11_flush(GstVaapiDisplay *display)
207 {
208     GstVaapiDisplayX11Private * const priv =
209         GST_VAAPI_DISPLAY_X11(display)->priv;
210
211     if (priv->x11_display)
212         XFlush(priv->x11_display);
213 }
214
215 static VADisplay
216 gst_vaapi_display_x11_get_va_display(GstVaapiDisplay *display)
217 {
218     return vaGetDisplay(GST_VAAPI_DISPLAY_XDISPLAY(display));
219 }
220
221 static void
222 gst_vaapi_display_x11_get_size(
223     GstVaapiDisplay *display,
224     guint           *pwidth,
225     guint           *pheight
226 )
227 {
228     GstVaapiDisplayX11Private * const priv =
229         GST_VAAPI_DISPLAY_X11(display)->priv;
230
231     if (!priv->x11_display)
232         return;
233
234     if (pwidth)
235         *pwidth = DisplayWidth(priv->x11_display, priv->x11_screen);
236
237     if (pheight)
238         *pheight = DisplayHeight(priv->x11_display, priv->x11_screen);
239 }
240
241 static void
242 gst_vaapi_display_x11_get_size_mm(
243     GstVaapiDisplay *display,
244     guint           *pwidth,
245     guint           *pheight
246 )
247 {
248     GstVaapiDisplayX11Private * const priv =
249         GST_VAAPI_DISPLAY_X11(display)->priv;
250
251     if (!priv->x11_display)
252         return;
253
254     if (pwidth)
255         *pwidth = DisplayWidthMM(priv->x11_display, priv->x11_screen);
256
257     if (pheight)
258         *pheight = DisplayHeightMM(priv->x11_display, priv->x11_screen);
259 }
260
261 static void
262 gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass)
263 {
264     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
265     GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
266
267     g_type_class_add_private(klass, sizeof(GstVaapiDisplayX11Private));
268
269     object_class->finalize      = gst_vaapi_display_x11_finalize;
270     object_class->set_property  = gst_vaapi_display_x11_set_property;
271     object_class->get_property  = gst_vaapi_display_x11_get_property;
272     object_class->constructed   = gst_vaapi_display_x11_constructed;
273
274     dpy_class->open_display     = gst_vaapi_display_x11_open_display;
275     dpy_class->close_display    = gst_vaapi_display_x11_close_display;
276     dpy_class->sync             = gst_vaapi_display_x11_sync;
277     dpy_class->flush            = gst_vaapi_display_x11_flush;
278     dpy_class->get_display      = gst_vaapi_display_x11_get_va_display;
279     dpy_class->get_size         = gst_vaapi_display_x11_get_size;
280     dpy_class->get_size_mm      = gst_vaapi_display_x11_get_size_mm;
281
282     /**
283      * GstVaapiDisplayX11:synchronous:
284      *
285      * When enabled, runs the X display in synchronous mode. Note that
286      * this is used only for debugging.
287      */
288     g_object_class_install_property
289         (object_class,
290          PROP_SYNCHRONOUS,
291          g_param_spec_boolean("synchronous",
292                               "Synchronous mode",
293                               "Toggles X display synchronous mode",
294                               FALSE,
295                               G_PARAM_READWRITE));
296
297     /**
298      * GstVaapiDisplayX11:x11-display:
299      *
300      * The X11 #Display that was created by gst_vaapi_display_x11_new()
301      * or that was bound from gst_vaapi_display_x11_new_with_display().
302      */
303     g_object_class_install_property
304         (object_class,
305          PROP_X11_DISPLAY,
306          g_param_spec_pointer("x11-display",
307                               "X11 display",
308                               "X11 display",
309                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
310
311     /**
312      * GstVaapiDisplayX11:display-name:
313      *
314      * The X11 display name.
315      */
316     g_object_class_install_property
317         (object_class,
318          PROP_DISPLAY_NAME,
319          g_param_spec_string("display-name",
320                              "X11 display name",
321                              "X11 display name",
322                              NULL,
323                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
324 }
325
326 static void
327 gst_vaapi_display_x11_init(GstVaapiDisplayX11 *display)
328 {
329     GstVaapiDisplayX11Private *priv = GST_VAAPI_DISPLAY_X11_GET_PRIVATE(display);
330
331     display->priv        = priv;
332     priv->create_display = TRUE;
333     priv->x11_display    = NULL;
334     priv->x11_screen     = 0;
335     priv->display_name   = NULL;
336 }
337
338 /**
339  * gst_vaapi_display_x11_new:
340  * @display_name: the X11 display name
341  *
342  * Opens an X11 #Display using @display_name and returns a newly
343  * allocated #GstVaapiDisplay object. The X11 display will be cloed
344  * when the reference count of the object reaches zero.
345  *
346  * Return value: a newly allocated #GstVaapiDisplay object
347  */
348 GstVaapiDisplay *
349 gst_vaapi_display_x11_new(const gchar *display_name)
350 {
351     return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11,
352                         "display-name", display_name,
353                         NULL);
354 }
355
356 /**
357  * gst_vaapi_display_x11_new_with_display:
358  * @x11_display: an X11 #Display
359  *
360  * Creates a #GstVaapiDisplay based on the X11 @x11_display
361  * display. The caller still owns the display and must call
362  * XCloseDisplay() when all #GstVaapiDisplay references are
363  * released. Doing so too early can yield undefined behaviour.
364  *
365  * Return value: a newly allocated #GstVaapiDisplay object
366  */
367 GstVaapiDisplay *
368 gst_vaapi_display_x11_new_with_display(Display *x11_display)
369 {
370     return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11,
371                         "x11-display", x11_display,
372                         NULL);
373 }
374
375 /**
376  * gst_vaapi_display_x11_get_display:
377  * @display: a #GstVaapiDisplayX11
378  *
379  * Returns the underlying X11 #Display that was created by
380  * gst_vaapi_display_x11_new() or that was bound from
381  * gst_vaapi_display_x11_new_with_display().
382  *
383  * Return value: the X11 #Display attached to @display
384  */
385 Display *
386 gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display)
387 {
388     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
389
390     return display->priv->x11_display;
391 }