tizen 2.3 release
[framework/multimedia/gst-plugins-base0.10.git] / gst-libs / gst / interfaces / xoverlay.c
1 /* GStreamer X-based Overlay
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * x-overlay.c: X-based overlay interface design
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /**
22  * SECTION:gstxoverlay
23  * @short_description: Interface for setting/getting a Window on elements
24  * supporting it
25  *
26  * <refsect2>
27  * <para>
28  * The XOverlay interface is used for 2 main purposes :
29  * <itemizedlist>
30  * <listitem>
31  * <para>
32  * To get a grab on the Window where the video sink element is going to render.
33  * This is achieved by either being informed about the Window identifier that
34  * the video sink element generated, or by forcing the video sink element to use
35  * a specific Window identifier for rendering.
36  * </para>
37  * </listitem>
38  * <listitem>
39  * <para>
40  * To force a redrawing of the latest video frame the video sink element
41  * displayed on the Window. Indeed if the #GstPipeline is in #GST_STATE_PAUSED
42  * state, moving the Window around will damage its content. Application
43  * developers will want to handle the Expose events themselves and force the
44  * video sink element to refresh the Window's content.
45  * </para>
46  * </listitem>
47  * </itemizedlist>
48  * </para>
49  * <para>
50  * Using the Window created by the video sink is probably the simplest scenario,
51  * in some cases, though, it might not be flexible enough for application
52  * developers if they need to catch events such as mouse moves and button
53  * clicks.
54  * </para>
55  * <para>
56  * Setting a specific Window identifier on the video sink element is the most
57  * flexible solution but it has some issues. Indeed the application needs to set
58  * its Window identifier at the right time to avoid internal Window creation
59  * from the video sink element. To solve this issue a #GstMessage is posted on
60  * the bus to inform the application that it should set the Window identifier
61  * immediately. Here is an example on how to do that correctly:
62  * |[
63  * static GstBusSyncReply
64  * create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
65  * {
66  *  // ignore anything but 'prepare-xwindow-id' element messages
67  *  if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
68  *    return GST_BUS_PASS;
69  *
70  *  if (!gst_structure_has_name (message-&gt;structure, "prepare-xwindow-id"))
71  *    return GST_BUS_PASS;
72  *
73  *  win = XCreateSimpleWindow (disp, root, 0, 0, 320, 240, 0, 0, 0);
74  *
75  *  XSetWindowBackgroundPixmap (disp, win, None);
76  *
77  *  XMapRaised (disp, win);
78  *
79  *  XSync (disp, FALSE);
80  *
81  *  gst_x_overlay_set_window_handle (GST_X_OVERLAY (GST_MESSAGE_SRC (message)),
82  *      win);
83  *
84  *  gst_message_unref (message);
85  *
86  *  return GST_BUS_DROP;
87  * }
88  * ...
89  * int
90  * main (int argc, char **argv)
91  * {
92  * ...
93  *  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
94  *  gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, pipeline);
95  * ...
96  * }
97  * ]|
98  * </para>
99  * </refsect2>
100  * <refsect2>
101  * <title>Two basic usage scenarios</title>
102  * <para>
103  * There are two basic usage scenarios: in the simplest case, the application
104  * knows exactly what particular element is used for video output, which is
105  * usually the case when the application creates the videosink to use
106  * (e.g. #xvimagesink, #ximagesink, etc.) itself; in this case, the application
107  * can just create the videosink element, create and realize the window to
108  * render the video on and then call gst_x_overlay_set_window_handle() directly
109  * with the XID or native window handle, before starting up the pipeline.
110  * </para>
111  * <para>
112  * In the other and more common case, the application does not know in advance
113  * what GStreamer video sink element will be used for video output. This is
114  * usually the case when an element such as #autovideosink or #gconfvideosink
115  * is used. In this case, the video sink element itself is created
116  * asynchronously from a GStreamer streaming thread some time after the
117  * pipeline has been started up. When that happens, however, the video sink
118  * will need to know right then whether to render onto an already existing
119  * application window or whether to create its own window. This is when it
120  * posts a prepare-xwindow-id message, and that is also why this message needs
121  * to be handled in a sync bus handler which will be called from the streaming
122  * thread directly (because the video sink will need an answer right then).
123  * </para>
124  * <para>
125  * As response to the prepare-xwindow-id element message in the bus sync
126  * handler, the application may use gst_x_overlay_set_window_handle() to tell
127  * the video sink to render onto an existing window surface. At this point the
128  * application should already have obtained the window handle / XID, so it
129  * just needs to set it. It is generally not advisable to call any GUI toolkit
130  * functions or window system functions from the streaming thread in which the
131  * prepare-xwindow-id message is handled, because most GUI toolkits and
132  * windowing systems are not thread-safe at all and a lot of care would be
133  * required to co-ordinate the toolkit and window system calls of the
134  * different threads (Gtk+ users please note: prior to Gtk+ 2.18
135  * GDK_WINDOW_XID() was just a simple structure access, so generally fine to do
136  * within the bus sync handler; this macro was changed to a function call in
137  * Gtk+ 2.18 and later, which is likely to cause problems when called from a
138  * sync handler; see below for a better approach without GDK_WINDOW_XID()
139  * used in the callback).
140  * </para>
141  * </refsect2>
142  * <refsect2>
143  * <title>GstXOverlay and Gtk+</title>
144  * <para>
145  * |[
146  * #include &lt;gst/interfaces/xoverlay.h&gt;
147  * #include &lt;gtk/gtk.h&gt;
148  * #ifdef GDK_WINDOWING_X11
149  * #include &lt;gdk/gdkx.h&gt;  // for GDK_WINDOW_XID
150  * #endif
151  * ...
152  * static gulong video_window_xid = 0;
153  * ...
154  * static GstBusSyncReply
155  * bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
156  * {
157  *  // ignore anything but 'prepare-xwindow-id' element messages
158  *  if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
159  *    return GST_BUS_PASS;
160  *  if (!gst_structure_has_name (message-&gt;structure, "prepare-xwindow-id"))
161  *    return GST_BUS_PASS;
162  *
163  *  if (video_window_xid != 0) {
164  *    GstXOverlay *xoverlay;
165  *
166  *    // GST_MESSAGE_SRC (message) will be the video sink element
167  *    xoverlay = GST_X_OVERLAY (GST_MESSAGE_SRC (message));
168  *    gst_x_overlay_set_window_handle (xoverlay, video_window_xid);
169  *  } else {
170  *    g_warning ("Should have obtained video_window_xid by now!");
171  *  }
172  *
173  *  gst_message_unref (message);
174  *  return GST_BUS_DROP;
175  * }
176  * ...
177  * static void
178  * video_widget_realize_cb (GtkWidget * widget, gpointer data)
179  * {
180  * #if GTK_CHECK_VERSION(2,18,0)
181  *   // This is here just for pedagogical purposes, GDK_WINDOW_XID will call
182  *   // it as well in newer Gtk versions
183  *   if (!gdk_window_ensure_native (widget->window))
184  *     g_error ("Couldn't create native window needed for GstXOverlay!");
185  * #endif
186  *
187  * #ifdef GDK_WINDOWING_X11
188  *   video_window_xid = GDK_WINDOW_XID (gtk_widget_get_window (video_window));
189  * #endif
190  * }
191  * ...
192  * int
193  * main (int argc, char **argv)
194  * {
195  *   GtkWidget *video_window;
196  *   GtkWidget *app_window;
197  *   ...
198  *   app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
199  *   ...
200  *   video_window = gtk_drawing_area_new ();
201  *   g_signal_connect (video_window, "realize",
202  *       G_CALLBACK (video_widget_realize_cb), NULL);
203  *   gtk_widget_set_double_buffered (video_window, FALSE);
204  *   ...
205  *   // usually the video_window will not be directly embedded into the
206  *   // application window like this, but there will be many other widgets
207  *   // and the video window will be embedded in one of them instead
208  *   gtk_container_add (GTK_CONTAINER (ap_window), video_window);
209  *   ...
210  *   // show the GUI
211  *   gtk_widget_show_all (app_window);
212  *
213  *   // realize window now so that the video window gets created and we can
214  *   // obtain its XID before the pipeline is started up and the videosink
215  *   // asks for the XID of the window to render onto
216  *   gtk_widget_realize (video_window);
217  *
218  *   // we should have the XID now
219  *   g_assert (video_window_xid != 0);
220  *   ...
221  *   // set up sync handler for setting the xid once the pipeline is started
222  *   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
223  *   gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, NULL);
224  *   gst_object_unref (bus);
225  *   ...
226  *   gst_element_set_state (pipeline, GST_STATE_PLAYING);
227  *   ...
228  * }
229  * ]|
230  * </para>
231  * </refsect2>
232  * <refsect2>
233  * <title>GstXOverlay and Qt</title>
234  * <para>
235  * |[
236  * #include &lt;glib.h&gt;
237  * #include &lt;gst/gst.h&gt;
238  * #include &lt;gst/interfaces/xoverlay.h&gt;
239  *
240  * #include &lt;QApplication&gt;
241  * #include &lt;QTimer&gt;
242  * #include &lt;QWidget&gt;
243  *
244  * int main(int argc, char *argv[])
245  * {
246  *   if (!g_thread_supported ())
247  *     g_thread_init (NULL);
248  *
249  *   gst_init (&argc, &argv);
250  *   QApplication app(argc, argv);
251  *   app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ()));
252  *
253  *   // prepare the pipeline
254  *
255  *   GstElement *pipeline = gst_pipeline_new ("xvoverlay");
256  *   GstElement *src = gst_element_factory_make ("videotestsrc", NULL);
257  *   GstElement *sink = gst_element_factory_make ("xvimagesink", NULL);
258  *   gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
259  *   gst_element_link (src, sink);
260  *
261  *   // prepare the ui
262  *
263  *   QWidget window;
264  *   window.resize(320, 240);
265  *   window.show();
266  *
267  *   WId xwinid = window.winId();
268  *   gst_x_overlay_set_window_handle (GST_X_OVERLAY (sink), xwinid);
269  *
270  *   // run the pipeline
271  *
272  *   GstStateChangeReturn sret = gst_element_set_state (pipeline,
273  *       GST_STATE_PLAYING);
274  *   if (sret == GST_STATE_CHANGE_FAILURE) {
275  *     gst_element_set_state (pipeline, GST_STATE_NULL);
276  *     gst_object_unref (pipeline);
277  *     // Exit application
278  *     QTimer::singleShot(0, QApplication::activeWindow(), SLOT(quit()));
279  *   }
280  *
281  *   int ret = app.exec();
282  *
283  *   window.hide();
284  *   gst_element_set_state (pipeline, GST_STATE_NULL);
285  *   gst_object_unref (pipeline);
286  *
287  *   return ret;
288  * }
289  * ]|
290  * </para>
291  * </refsect2>
292  */
293
294 #ifdef HAVE_CONFIG_H
295 #include "config.h"
296 #endif
297
298 #include "xoverlay.h"
299
300 static void gst_x_overlay_base_init (gpointer g_class);
301
302 GType
303 gst_x_overlay_get_type (void)
304 {
305   static GType gst_x_overlay_type = 0;
306
307   if (!gst_x_overlay_type) {
308     static const GTypeInfo gst_x_overlay_info = {
309       sizeof (GstXOverlayClass),
310       gst_x_overlay_base_init,
311       NULL,
312       NULL,
313       NULL,
314       NULL,
315       0,
316       0,
317       NULL,
318     };
319
320     gst_x_overlay_type = g_type_register_static (G_TYPE_INTERFACE,
321         "GstXOverlay", &gst_x_overlay_info, 0);
322     g_type_interface_add_prerequisite (gst_x_overlay_type,
323         GST_TYPE_IMPLEMENTS_INTERFACE);
324   }
325
326   return gst_x_overlay_type;
327 }
328
329 static void
330 gst_x_overlay_base_init (gpointer g_class)
331 {
332
333 }
334
335 /**
336  * gst_x_overlay_set_xwindow_id:
337  * @overlay: a #GstXOverlay to set the window on.
338  * @xwindow_id: a XID referencing the XWindow.
339  *
340  * This will call the video overlay's set_xwindow_id method. You should
341  * use this method to tell to a XOverlay to display video output to a
342  * specific XWindow. Passing 0 as the @xwindow_id will tell the overlay to
343  * stop using that window and create an internal one.
344  *
345  * Deprecated: Use gst_x_overlay_set_window_handle() instead.
346  */
347 #ifndef GST_REMOVE_DEPRECATED
348 #ifdef GST_DISABLE_DEPRECATED
349 void gst_x_overlay_set_xwindow_id (GstXOverlay * overlay, gulong xwindow_id);
350 #endif
351 void
352 gst_x_overlay_set_xwindow_id (GstXOverlay * overlay, gulong xwindow_id)
353 {
354   GST_WARNING_OBJECT (overlay,
355       "Using deprecated gst_x_overlay_set_xwindow_id()");
356   gst_x_overlay_set_window_handle (overlay, xwindow_id);
357 }
358 #endif
359
360 /**
361  * gst_x_overlay_set_window_handle:
362  * @overlay: a #GstXOverlay to set the window on.
363  * @handle: a handle referencing the window.
364  *
365  * This will call the video overlay's set_window_handle method. You
366  * should use this method to tell to a XOverlay to display video output to a
367  * specific window (e.g. an XWindow on X11). Passing 0 as the  @handle will
368  * tell the overlay to stop using that window and create an internal one.
369  *
370  * Since: 0.10.31
371  */
372 void
373 gst_x_overlay_set_window_handle (GstXOverlay * overlay, guintptr handle)
374 {
375   GstXOverlayClass *klass;
376
377   g_return_if_fail (overlay != NULL);
378   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
379
380   klass = GST_X_OVERLAY_GET_CLASS (overlay);
381
382   if (klass->set_window_handle) {
383     klass->set_window_handle (overlay, handle);
384   } else {
385 #ifndef GST_REMOVE_DEPRECATED
386 #ifdef GST_DISABLE_DEPRECATED
387 #define set_xwindow_id set_xwindow_id_disabled
388 #endif
389     if (sizeof (guintptr) <= sizeof (gulong) && klass->set_xwindow_id) {
390       GST_WARNING_OBJECT (overlay,
391           "Calling deprecated set_xwindow_id() method");
392       klass->set_xwindow_id (overlay, handle);
393     } else {
394       g_warning ("Refusing to cast guintptr to smaller gulong");
395     }
396 #endif
397   }
398 }
399
400 /**
401  * gst_x_overlay_got_xwindow_id:
402  * @overlay: a #GstXOverlay which got a XWindow.
403  * @xwindow_id: a XID referencing the XWindow.
404  *
405  * This will post a "have-xwindow-id" element message on the bus.
406  *
407  * This function should only be used by video overlay plugin developers.
408  *
409  * Deprecated: Use gst_x_overlay_got_window_handle() instead.
410  */
411 #ifndef GST_REMOVE_DEPRECATED
412 #ifdef GST_DISABLE_DEPRECATED
413 void gst_x_overlay_got_xwindow_id (GstXOverlay * overlay, gulong xwindow_id);
414 #endif
415 void
416 gst_x_overlay_got_xwindow_id (GstXOverlay * overlay, gulong xwindow_id)
417 {
418   GST_WARNING_OBJECT (overlay,
419       "Using deprecated gst_x_overlay_got_xwindow_id()");
420   gst_x_overlay_got_window_handle (overlay, xwindow_id);
421 }
422 #endif
423
424 /**
425  * gst_x_overlay_got_window_handle:
426  * @overlay: a #GstXOverlay which got a window
427  * @handle: a platform-specific handle referencing the window
428  *
429  * This will post a "have-xwindow-id" element message on the bus.
430  *
431  * This function should only be used by video overlay plugin developers.
432  */
433 void
434 gst_x_overlay_got_window_handle (GstXOverlay * overlay, guintptr handle)
435 {
436   GstStructure *s;
437   GstMessage *msg;
438
439   g_return_if_fail (overlay != NULL);
440   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
441
442   GST_LOG_OBJECT (GST_OBJECT (overlay), "xwindow_id = %p", (gpointer)
443       handle);
444   s = gst_structure_new ("have-xwindow-id",
445       "xwindow-id", G_TYPE_ULONG, (unsigned long) handle,
446       "window-handle", G_TYPE_UINT64, (guint64) handle, NULL);
447   msg = gst_message_new_element (GST_OBJECT (overlay), s);
448   gst_element_post_message (GST_ELEMENT (overlay), msg);
449 }
450
451 /**
452  * gst_x_overlay_prepare_xwindow_id:
453  * @overlay: a #GstXOverlay which does not yet have an XWindow.
454  *
455  * This will post a "prepare-xwindow-id" element message on the bus
456  * to give applications an opportunity to call
457  * gst_x_overlay_set_xwindow_id() before a plugin creates its own
458  * window.
459  *
460  * This function should only be used by video overlay plugin developers.
461  */
462 void
463 gst_x_overlay_prepare_xwindow_id (GstXOverlay * overlay)
464 {
465   GstStructure *s;
466   GstMessage *msg;
467
468   g_return_if_fail (overlay != NULL);
469   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
470
471   GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xwindow_id");
472   s = gst_structure_new ("prepare-xwindow-id", NULL);
473   msg = gst_message_new_element (GST_OBJECT (overlay), s);
474   gst_element_post_message (GST_ELEMENT (overlay), msg);
475 }
476
477 /**
478  * gst_x_overlay_expose:
479  * @overlay: a #GstXOverlay to expose.
480  *
481  * Tell an overlay that it has been exposed. This will redraw the current frame
482  * in the drawable even if the pipeline is PAUSED.
483  */
484 void
485 gst_x_overlay_expose (GstXOverlay * overlay)
486 {
487   GstXOverlayClass *klass;
488
489   g_return_if_fail (overlay != NULL);
490   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
491
492   klass = GST_X_OVERLAY_GET_CLASS (overlay);
493
494   if (klass->expose) {
495     klass->expose (overlay);
496   }
497 }
498
499 /**
500  * gst_x_overlay_handle_events:
501  * @overlay: a #GstXOverlay to expose.
502  * @handle_events: a #gboolean indicating if events should be handled or not.
503  *
504  * Tell an overlay that it should handle events from the window system. These
505  * events are forwarded upstream as navigation events. In some window system,
506  * events are not propagated in the window hierarchy if a client is listening
507  * for them. This method allows you to disable events handling completely
508  * from the XOverlay.
509  *
510  * Since: 0.10.12
511  */
512 void
513 gst_x_overlay_handle_events (GstXOverlay * overlay, gboolean handle_events)
514 {
515   GstXOverlayClass *klass;
516
517   g_return_if_fail (overlay != NULL);
518   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
519
520   klass = GST_X_OVERLAY_GET_CLASS (overlay);
521
522   if (klass->handle_events) {
523     klass->handle_events (overlay, handle_events);
524   }
525 }
526
527 /**
528  * gst_x_overlay_set_render_rectangle:
529  * @overlay: a #GstXOverlay
530  * @x: the horizontal offset of the render area inside the window
531  * @y: the vertical offset of the render area inside the window
532  * @width: the width of the render area inside the window
533  * @height: the height of the render area inside the window
534  *
535  * Configure a subregion as a video target within the window set by
536  * gst_x_overlay_set_window_handle(). If this is not used or not supported
537  * the video will fill the area of the window set as the overlay to 100%.
538  * By specifying the rectangle, the video can be overlayed to a specific region
539  * of that window only. After setting the new rectangle one should call
540  * gst_x_overlay_expose() to force a redraw. To unset the region pass -1 for
541  * the @width and @height parameters.
542  *
543  * This method is needed for non fullscreen video overlay in UI toolkits that
544  * do not support subwindows.
545  *
546  * Returns: %FALSE if not supported by the sink.
547  *
548  * Since: 0.10.29
549  */
550 gboolean
551 gst_x_overlay_set_render_rectangle (GstXOverlay * overlay,
552     gint x, gint y, gint width, gint height)
553 {
554   GstXOverlayClass *klass;
555
556   g_return_val_if_fail (overlay != NULL, FALSE);
557   g_return_val_if_fail (GST_IS_X_OVERLAY (overlay), FALSE);
558   g_return_val_if_fail ((width == -1 && height == -1) ||
559       (width > 0 && height > 0), FALSE);
560
561   klass = GST_X_OVERLAY_GET_CLASS (overlay);
562
563   if (klass->set_render_rectangle) {
564     klass->set_render_rectangle (overlay, x, y, width, height);
565     return TRUE;
566   }
567   return FALSE;
568 }