69058703a32292313c92d31498b78e4dfafbdd6f
[platform/upstream/gstreamer-vaapi.git] / gst-libs / gst / vaapi / gstvaapiwindow_x11.c
1 /*
2  *  gstvaapiwindow_x11.c - VA/X11 window 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:gst-vaapi-window-x11
23  * @short_description:
24  */
25
26 #include "config.h"
27 #include "gstvaapiwindow_x11.h"
28 #include "gstvaapidisplay_x11.h"
29 #include "gstvaapiutils_x11.h"
30
31 #define DEBUG 1
32 #include "gstvaapidebug.h"
33
34 G_DEFINE_TYPE(GstVaapiWindowX11, gst_vaapi_window_x11, GST_VAAPI_TYPE_WINDOW);
35
36 #define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj)                   \
37     (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
38                                  GST_VAAPI_TYPE_WINDOW_X11,     \
39                                  GstVaapiWindowX11Private))
40
41 struct _GstVaapiWindowX11Private {
42     GstVaapiDisplay    *display;
43     Window              xid;
44     guint               create_window   : 1;
45     guint               is_visible      : 1;
46 };
47
48 enum {
49     PROP_0,
50
51     PROP_DISPLAY,
52     PROP_XID,
53 };
54
55 static gboolean
56 gst_vaapi_window_x11_show(GstVaapiWindow *window)
57 {
58     GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
59     Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
60     gboolean has_errors;
61
62     if (priv->is_visible)
63         return TRUE;
64
65     GST_VAAPI_DISPLAY_LOCK(priv->display);
66     x11_trap_errors();
67     XMapWindow(dpy, priv->xid);
68     if (priv->create_window)
69         x11_wait_event(dpy, priv->xid, MapNotify);
70     has_errors = x11_untrap_errors() != 0;
71     GST_VAAPI_DISPLAY_UNLOCK(priv->display);
72     if (has_errors)
73         return FALSE;
74
75     priv->is_visible = TRUE;
76     return TRUE;
77 }
78
79 static gboolean
80 gst_vaapi_window_x11_hide(GstVaapiWindow *window)
81 {
82     GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
83     Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
84     gboolean has_errors;
85
86     if (!priv->is_visible)
87         return TRUE;
88
89     GST_VAAPI_DISPLAY_LOCK(priv->display);
90     x11_trap_errors();
91     XUnmapWindow(dpy, priv->xid);
92     if (priv->create_window)
93         x11_wait_event(dpy, priv->xid, UnmapNotify);
94     has_errors = x11_untrap_errors() != 0;
95     GST_VAAPI_DISPLAY_UNLOCK(priv->display);
96     if (has_errors)
97         return FALSE;
98
99     priv->is_visible = FALSE;
100     return TRUE;
101 }
102
103 static gboolean
104 gst_vaapi_window_x11_create(GstVaapiWindow *window, guint *width, guint *height)
105 {
106     GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
107     Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
108     gboolean ok;
109
110     if (!priv->create_window && priv->xid) {
111         GST_VAAPI_DISPLAY_LOCK(priv->display);
112         ok = x11_get_geometry(dpy, priv->xid, NULL, NULL, width, height);
113         GST_VAAPI_DISPLAY_UNLOCK(priv->display);
114         return ok;
115     }
116
117     GST_VAAPI_DISPLAY_LOCK(priv->display);
118     priv->xid = x11_create_window(dpy, *width, *height);
119     if (priv->xid)
120         XRaiseWindow(dpy, priv->xid);
121     GST_VAAPI_DISPLAY_UNLOCK(priv->display);
122     return priv->xid != None;
123 }
124
125 static void
126 gst_vaapi_window_x11_destroy(GstVaapiWindow *window)
127 {
128     GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
129     Display * const dpy = GST_VAAPI_DISPLAY_XDISPLAY(priv->display);
130
131     if (priv->xid) {
132         if (priv->create_window) {
133             GST_VAAPI_DISPLAY_LOCK(priv->display);
134             XDestroyWindow(dpy, priv->xid);
135             GST_VAAPI_DISPLAY_UNLOCK(priv->display);
136         }
137         priv->xid = None;
138     }
139
140     if (priv->display) {
141         g_object_unref(priv->display);
142         priv->display = NULL;
143     }
144 }
145
146 static gboolean
147 gst_vaapi_window_x11_resize(GstVaapiWindow *window, guint width, guint height)
148 {
149     GstVaapiWindowX11Private * const priv = GST_VAAPI_WINDOW_X11(window)->priv;
150     gboolean has_errors;
151
152     if (!priv->xid)
153         return FALSE;
154
155     GST_VAAPI_DISPLAY_LOCK(priv->display);
156     x11_trap_errors();
157     XResizeWindow(
158         GST_VAAPI_DISPLAY_XDISPLAY(priv->display),
159         priv->xid,
160         width,
161         height
162     );
163     has_errors = x11_untrap_errors() != 0;
164     GST_VAAPI_DISPLAY_UNLOCK(priv->display);
165     return !has_errors;
166 }
167
168 static gboolean
169 gst_vaapi_window_x11_render(
170     GstVaapiWindow          *window,
171     GstVaapiSurface         *surface,
172     const GstVideoRectangle *src_rect,
173     const GstVideoRectangle *dst_rect,
174     guint                    flags
175 )
176 {
177     GstVaapiDisplay *display;
178     VASurfaceID surface_id;
179     VAStatus status;
180
181     display = gst_vaapi_surface_get_display(surface);
182     if (!display)
183         return FALSE;
184
185     surface_id = gst_vaapi_surface_get_id(surface);
186     if (surface_id == VA_INVALID_ID)
187         return FALSE;
188
189     GST_VAAPI_DISPLAY_LOCK(display);
190     status = vaPutSurface(
191         GST_VAAPI_DISPLAY_VADISPLAY(display),
192         surface_id,
193         GST_VAAPI_WINDOW_X11(window)->priv->xid,
194         src_rect->x,
195         src_rect->y,
196         src_rect->w,
197         src_rect->h,
198         dst_rect->x,
199         dst_rect->y,
200         dst_rect->w,
201         dst_rect->h,
202         NULL, 0,
203         get_PutSurface_flags_from_GstVaapiSurfaceRenderFlags(flags)
204     );
205     GST_VAAPI_DISPLAY_UNLOCK(display);
206     if (!vaapi_check_status(status, "vaPutSurface()"))
207         return FALSE;
208
209     return TRUE;
210 }
211
212 static void
213 gst_vaapi_window_x11_finalize(GObject *object)
214 {
215     G_OBJECT_CLASS(gst_vaapi_window_x11_parent_class)->finalize(object);
216 }
217
218 static void
219 gst_vaapi_window_x11_set_property(
220     GObject      *object,
221     guint         prop_id,
222     const GValue *value,
223     GParamSpec   *pspec
224 )
225 {
226     GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object);
227
228     switch (prop_id) {
229     case PROP_DISPLAY:
230         window->priv->display = g_object_ref(g_value_get_object(value));
231         break;
232     case PROP_XID:
233         window->priv->xid = g_value_get_uint(value);
234         break;
235     default:
236         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
237         break;
238     }
239 }
240
241 static void
242 gst_vaapi_window_x11_get_property(
243     GObject    *object,
244     guint       prop_id,
245     GValue     *value,
246     GParamSpec *pspec
247 )
248 {
249     GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object);
250
251     switch (prop_id) {
252     case PROP_DISPLAY:
253         g_value_set_object(value, window->priv->display);
254         break;
255     case PROP_XID:
256         g_value_set_uint(value, gst_vaapi_window_x11_get_xid(window));
257         break;
258     default:
259         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
260         break;
261     }
262 }
263
264 static void
265 gst_vaapi_window_x11_constructed(GObject *object)
266 {
267     GstVaapiWindowX11 * const window = GST_VAAPI_WINDOW_X11(object);
268     GObjectClass *parent_class;
269
270     window->priv->create_window = window->priv->xid == None;
271
272     parent_class = G_OBJECT_CLASS(gst_vaapi_window_x11_parent_class);
273     if (parent_class->constructed)
274         parent_class->constructed(object);
275 }
276
277 static void
278 gst_vaapi_window_x11_class_init(GstVaapiWindowX11Class *klass)
279 {
280     GObjectClass * const object_class = G_OBJECT_CLASS(klass);
281     GstVaapiWindowClass * const window_class = GST_VAAPI_WINDOW_CLASS(klass);
282
283     g_type_class_add_private(klass, sizeof(GstVaapiWindowX11Private));
284
285     object_class->finalize      = gst_vaapi_window_x11_finalize;
286     object_class->set_property  = gst_vaapi_window_x11_set_property;
287     object_class->get_property  = gst_vaapi_window_x11_get_property;
288     object_class->constructed   = gst_vaapi_window_x11_constructed;
289
290     window_class->create        = gst_vaapi_window_x11_create;
291     window_class->destroy       = gst_vaapi_window_x11_destroy;
292     window_class->show          = gst_vaapi_window_x11_show;
293     window_class->hide          = gst_vaapi_window_x11_hide;
294     window_class->resize        = gst_vaapi_window_x11_resize;
295     window_class->render        = gst_vaapi_window_x11_render;
296
297     /**
298      * GstVaapiWindowX11:display:
299      *
300      * The #GstVaapiDisplay this window is bound to
301      */
302     g_object_class_install_property
303         (object_class,
304          PROP_DISPLAY,
305          g_param_spec_object("display",
306                              "Display",
307                              "The GstVaapiDisplay this window is bound to",
308                              GST_VAAPI_TYPE_DISPLAY,
309                              G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
310
311     /**
312      * GstVaapiWindowX11:xid:
313      *
314      * The underlying X11 #Window XID.
315      */
316     g_object_class_install_property
317         (object_class,
318          PROP_XID,
319          g_param_spec_uint("xid",
320                            "X window id",
321                            "The underlying X11 window id",
322                            0, G_MAXUINT32, 0,
323                            G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
324 }
325
326 static void
327 gst_vaapi_window_x11_init(GstVaapiWindowX11 *window)
328 {
329     GstVaapiWindowX11Private *priv = GST_VAAPI_WINDOW_X11_GET_PRIVATE(window);
330
331     window->priv        = priv;
332     priv->display       = NULL;
333     priv->xid           = None;
334     priv->create_window = TRUE;
335     priv->is_visible    = FALSE;
336 }
337
338 /**
339  * gst_vaapi_window_x11_new:
340  * @display: a #GstVaapiDisplay
341  * @width: the requested window width, in pixels
342  * @height: the requested windo height, in pixels
343  *
344  * Creates a window with the specified @width and @height. The window
345  * will be attached to the @display and remains invisible to the user
346  * until gst_vaapi_window_show() is called.
347  *
348  * Return value: the newly allocated #GstVaapiWindow object
349  */
350 GstVaapiWindow *
351 gst_vaapi_window_x11_new(GstVaapiDisplay *display, guint width, guint height)
352 {
353     GST_DEBUG("new window, size %ux%u", width, height);
354
355     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
356     g_return_val_if_fail(width > 0, NULL);
357     g_return_val_if_fail(height > 0, NULL);
358
359     return g_object_new(GST_VAAPI_TYPE_WINDOW_X11,
360                         "display", display,
361                         "width",   width,
362                         "height",  height,
363                         NULL);
364 }
365
366 /**
367  * gst_vaapi_window_x11_new_with_xid:
368  * @display: a #GstVaapiDisplay
369  * @xid: an X11 #Window id
370  *
371  * Creates a #GstVaapiWindow using the X11 #Window @xid. The caller
372  * still owns the window and must call XDestroyWindow() when all
373  * #GstVaapiWindow references are released. Doing so too early can
374  * yield undefined behaviour.
375  *
376  * Return value: the newly allocated #GstVaapiWindow object
377  */
378 GstVaapiWindow *
379 gst_vaapi_window_x11_new_with_xid(GstVaapiDisplay *display, Window xid)
380 {
381     GST_DEBUG("new window from xid 0x%08x", xid);
382
383     g_return_val_if_fail(GST_VAAPI_IS_DISPLAY(display), NULL);
384     g_return_val_if_fail(xid != None, NULL);
385
386     return g_object_new(GST_VAAPI_TYPE_WINDOW_X11,
387                         "display", display,
388                         "xid",     xid,
389                         NULL);
390 }
391
392 /**
393  * gst_vaapi_window_x11_get_xid:
394  * @window: a #GstVaapiWindowX11
395  *
396  * Returns the underlying X11 #Window that was created by
397  * gst_vaapi_window_x11_new() or that was bound with
398  * gst_vaapi_window_x11_new_with_xid().
399  *
400  * Return value: the underlying X11 #Window bound to @window.
401  */
402 Window
403 gst_vaapi_window_x11_get_xid(GstVaapiWindowX11 *window)
404 {
405     g_return_val_if_fail(GST_VAAPI_WINDOW_X11(window), None);
406
407     return window->priv->xid;
408 }