Add "synchronous" mode.
[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 VADisplay
196 gst_vaapi_display_x11_get_va_display(GstVaapiDisplay *display)
197 {
198     return vaGetDisplay(GST_VAAPI_DISPLAY_XDISPLAY(display));
199 }
200
201 static void
202 gst_vaapi_display_x11_get_size(
203     GstVaapiDisplay *display,
204     guint           *pwidth,
205     guint           *pheight
206 )
207 {
208     GstVaapiDisplayX11Private * const priv =
209         GST_VAAPI_DISPLAY_X11(display)->priv;
210
211     if (!priv->x11_display)
212         return;
213
214     if (pwidth)
215         *pwidth = DisplayWidth(priv->x11_display, priv->x11_screen);
216
217     if (pheight)
218         *pheight = DisplayHeight(priv->x11_display, priv->x11_screen);
219 }
220
221 static void
222 gst_vaapi_display_x11_get_size_mm(
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 = DisplayWidthMM(priv->x11_display, priv->x11_screen);
236
237     if (pheight)
238         *pheight = DisplayHeightMM(priv->x11_display, priv->x11_screen);
239 }
240
241 static void
242 gst_vaapi_display_x11_class_init(GstVaapiDisplayX11Class *klass)
243 {
244     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
245     GstVaapiDisplayClass * const dpy_class = GST_VAAPI_DISPLAY_CLASS(klass);
246
247     g_type_class_add_private(klass, sizeof(GstVaapiDisplayX11Private));
248
249     object_class->finalize      = gst_vaapi_display_x11_finalize;
250     object_class->set_property  = gst_vaapi_display_x11_set_property;
251     object_class->get_property  = gst_vaapi_display_x11_get_property;
252     object_class->constructed   = gst_vaapi_display_x11_constructed;
253
254     dpy_class->open_display     = gst_vaapi_display_x11_open_display;
255     dpy_class->close_display    = gst_vaapi_display_x11_close_display;
256     dpy_class->get_display      = gst_vaapi_display_x11_get_va_display;
257     dpy_class->get_size         = gst_vaapi_display_x11_get_size;
258     dpy_class->get_size_mm      = gst_vaapi_display_x11_get_size_mm;
259
260     /**
261      * GstVaapiDisplayX11:synchronous:
262      *
263      * When enabled, runs the X display in synchronous mode. Note that
264      * this is used only for debugging.
265      */
266     g_object_class_install_property
267         (object_class,
268          PROP_SYNCHRONOUS,
269          g_param_spec_boolean("synchronous",
270                               "Synchronous mode",
271                               "Toggles X display synchronous mode",
272                               FALSE,
273                               G_PARAM_READWRITE));
274
275     /**
276      * GstVaapiDisplayX11:x11-display:
277      *
278      * The X11 #Display that was created by gst_vaapi_display_x11_new()
279      * or that was bound from gst_vaapi_display_x11_new_with_display().
280      */
281     g_object_class_install_property
282         (object_class,
283          PROP_X11_DISPLAY,
284          g_param_spec_pointer("x11-display",
285                               "X11 display",
286                               "X11 display",
287                               G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
288
289     /**
290      * GstVaapiDisplayX11:display-name:
291      *
292      * The X11 display name.
293      */
294     g_object_class_install_property
295         (object_class,
296          PROP_DISPLAY_NAME,
297          g_param_spec_string("display-name",
298                              "X11 display name",
299                              "X11 display name",
300                              NULL,
301                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
302 }
303
304 static void
305 gst_vaapi_display_x11_init(GstVaapiDisplayX11 *display)
306 {
307     GstVaapiDisplayX11Private *priv = GST_VAAPI_DISPLAY_X11_GET_PRIVATE(display);
308
309     display->priv        = priv;
310     priv->create_display = TRUE;
311     priv->x11_display    = NULL;
312     priv->x11_screen     = 0;
313     priv->display_name   = NULL;
314 }
315
316 /**
317  * gst_vaapi_display_x11_new:
318  * @display_name: the X11 display name
319  *
320  * Opens an X11 #Display using @display_name and returns a newly
321  * allocated #GstVaapiDisplay object. The X11 display will be cloed
322  * when the reference count of the object reaches zero.
323  *
324  * Return value: a newly allocated #GstVaapiDisplay object
325  */
326 GstVaapiDisplay *
327 gst_vaapi_display_x11_new(const gchar *display_name)
328 {
329     return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11,
330                         "display-name", display_name,
331                         NULL);
332 }
333
334 /**
335  * gst_vaapi_display_x11_new_with_display:
336  * @x11_display: an X11 #Display
337  *
338  * Creates a #GstVaapiDisplay based on the X11 @x11_display
339  * display. The caller still owns the display and must call
340  * XCloseDisplay() when all #GstVaapiDisplay references are
341  * released. Doing so too early can yield undefined behaviour.
342  *
343  * Return value: a newly allocated #GstVaapiDisplay object
344  */
345 GstVaapiDisplay *
346 gst_vaapi_display_x11_new_with_display(Display *x11_display)
347 {
348     return g_object_new(GST_VAAPI_TYPE_DISPLAY_X11,
349                         "x11-display", x11_display,
350                         NULL);
351 }
352
353 /**
354  * gst_vaapi_display_x11_get_display:
355  * @display: a #GstVaapiDisplayX11
356  *
357  * Returns the underlying X11 #Display that was created by
358  * gst_vaapi_display_x11_new() or that was bound from
359  * gst_vaapi_display_x11_new_with_display().
360  *
361  * Return value: the X11 #Display attached to @display
362  */
363 Display *
364 gst_vaapi_display_x11_get_display(GstVaapiDisplayX11 *display)
365 {
366     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY_X11(display), NULL);
367
368     return display->priv->x11_display;
369 }