Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / 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;gtk/gtk.h&gt;
147  * #ifdef GDK_WINDOWING_X11
148  * #include &lt;gdk/gdkx.h&gt;  // for GDK_WINDOW_XID
149  * #endif
150  * ...
151  * static gulong video_window_xid = 0;
152  * ...
153  * static GstBusSyncReply
154  * bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
155  * {
156  *  // ignore anything but 'prepare-xwindow-id' element messages
157  *  if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT)
158  *    return GST_BUS_PASS;
159  *  if (!gst_structure_has_name (message-&gt;structure, "prepare-xwindow-id"))
160  *    return GST_BUS_PASS;
161  *  
162  *  if (video_window_xid != 0) {
163  *    GstXOverlay *xoverlay;
164  *    
165  *    // GST_MESSAGE_SRC (message) will be the video sink element
166  *    xoverlay = GST_X_OVERLAY (GST_MESSAGE_SRC (message));
167  *    gst_x_overlay_set_window_handle (xoverlay, video_window_xid);
168  *  } else {
169  *    g_warning ("Should have obtained video_window_xid by now!");
170  *  }
171  *  
172  *  gst_message_unref (message);
173  *  return GST_BUS_DROP;
174  * }
175  * ...
176  * static void
177  * video_widget_realize_cb (GtkWidget * widget, gpointer data)
178  * {
179  * #if GTK_CHECK_VERSION(2,18,0)
180  *   // This is here just for pedagogical purposes, GDK_WINDOW_XID will call
181  *   // it as well in newer Gtk versions
182  *   if (!gdk_window_ensure_native (widget->window))
183  *     g_error ("Couldn't create native window needed for GstXOverlay!");
184  * #endif
185  * 
186  * #ifdef GDK_WINDOWING_X11
187  *   video_window_xid = GDK_WINDOW_XID (video_window->window);
188  * #endif
189  * }
190  * ...
191  * int
192  * main (int argc, char **argv)
193  * {
194  *   GtkWidget *video_window;
195  *   GtkWidget *app_window;
196  *   ...
197  *   app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
198  *   ...
199  *   video_window = gtk_drawing_area_new ();
200  *   g_signal_connect (video_window, "realize",
201  *       G_CALLBACK (video_widget_realize_cb), NULL);
202  *   gtk_widget_set_double_buffered (video_window, FALSE);
203  *   ...
204  *   // usually the video_window will not be directly embedded into the
205  *   // application window like this, but there will be many other widgets
206  *   // and the video window will be embedded in one of them instead
207  *   gtk_container_add (GTK_CONTAINER (ap_window), video_window);
208  *   ...
209  *   // show the GUI
210  *   gtk_widget_show_all (app_window);
211  * 
212  *   // realize window now so that the video window gets created and we can
213  *   // obtain its XID before the pipeline is started up and the videosink
214  *   // asks for the XID of the window to render onto
215  *   gtk_widget_realize (window);
216  * 
217  *   // we should have the XID now
218  *   g_assert (video_window_xid != 0);
219  *   ...
220  *   // set up sync handler for setting the xid once the pipeline is started
221  *   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
222  *   gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, NULL);
223  *   gst_object_unref (bus);
224  *   ...
225  *   gst_element_set_state (pipeline, GST_STATE_PLAYING);
226  *   ...
227  * }
228  * ]|
229  * </para>
230  * </refsect2>
231  * <refsect2>
232  * <title>GstXOverlay and Qt</title>
233  * <para>
234  * |[
235  * #include &lt;glib.h&gt;
236  * #include &lt;gst/gst.h&gt;
237  * #include &lt;gst/interfaces/xoverlay.h&gt;
238  * 
239  * #include &lt;QApplication&gt;
240  * #include &lt;QTimer&gt;
241  * #include &lt;QWidget&gt;
242  * 
243  * int main(int argc, char *argv[])
244  * {
245  *   if (!g_thread_supported ())
246  *     g_thread_init (NULL);
247  * 
248  *   gst_init (&argc, &argv);
249  *   QApplication app(argc, argv);
250  *   app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ()));
251  * 
252  *   // prepare the pipeline
253  * 
254  *   GstElement *pipeline = gst_pipeline_new ("xvoverlay");
255  *   GstElement *src = gst_element_factory_make ("videotestsrc", NULL);
256  *   GstElement *sink = gst_element_factory_make ("xvimagesink", NULL);
257  *   gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
258  *   gst_element_link (src, sink);
259  *   
260  *   // prepare the ui
261  * 
262  *   QWidget window;
263  *   window.resize(320, 240);
264  *   window.show();
265  *   
266  *   WId xwinid = window.winId();
267  *   gst_x_overlay_set_window_handle (GST_X_OVERLAY (sink), xwinid);
268  * 
269  *   // run the pipeline
270  * 
271  *   GstStateChangeReturn sret = gst_element_set_state (pipeline,
272  *       GST_STATE_PLAYING);
273  *   if (sret == GST_STATE_CHANGE_FAILURE) {
274  *     gst_element_set_state (pipeline, GST_STATE_NULL);
275  *     gst_object_unref (pipeline);
276  *     // Exit application
277  *     QTimer::singleShot(0, QApplication::activeWindow(), SLOT(quit()));
278  *   }
279  * 
280  *   int ret = app.exec();
281  *   
282  *   window.hide();
283  *   gst_element_set_state (pipeline, GST_STATE_NULL);
284  *   gst_object_unref (pipeline);
285  * 
286  *   return ret;
287  * }
288  * ]|
289  * </para>
290  * </refsect2>
291  */
292
293 #ifdef HAVE_CONFIG_H
294 #include "config.h"
295 #endif
296
297 #include "xoverlay.h"
298
299 static void gst_x_overlay_base_init (gpointer g_class);
300
301 GType
302 gst_x_overlay_get_type (void)
303 {
304   static GType gst_x_overlay_type = 0;
305
306   if (!gst_x_overlay_type) {
307     static const GTypeInfo gst_x_overlay_info = {
308       sizeof (GstXOverlayClass),
309       gst_x_overlay_base_init,
310       NULL,
311       NULL,
312       NULL,
313       NULL,
314       0,
315       0,
316       NULL,
317     };
318
319     gst_x_overlay_type = g_type_register_static (G_TYPE_INTERFACE,
320         "GstXOverlay", &gst_x_overlay_info, 0);
321     g_type_interface_add_prerequisite (gst_x_overlay_type,
322         GST_TYPE_IMPLEMENTS_INTERFACE);
323   }
324
325   return gst_x_overlay_type;
326 }
327
328 static void
329 gst_x_overlay_base_init (gpointer g_class)
330 {
331
332 }
333
334 /**
335  * gst_x_overlay_set_xwindow_id:
336  * @overlay: a #GstXOverlay to set the XWindow on.
337  * @xwindow_id: a #XID referencing the XWindow.
338  *
339  * This will call the video overlay's set_xwindow_id method. You should
340  * use this method to tell to a XOverlay to display video output to a
341  * specific XWindow. Passing 0 as the xwindow_id will tell the overlay to
342  * stop using that window and create an internal one.
343  *
344  * Deprecated: Use gst_x_overlay_set_window_handle() instead.
345  */
346 #ifndef GST_REMOVE_DEPRECATED
347 #ifdef GST_DISABLE_DEPRECATED
348 void gst_x_overlay_set_xwindow_id (GstXOverlay * overlay, gulong xwindow_id);
349 #endif
350 void
351 gst_x_overlay_set_xwindow_id (GstXOverlay * overlay, gulong xwindow_id)
352 {
353   GST_WARNING_OBJECT (overlay,
354       "Using deprecated gst_x_overlay_set_xwindow_id()");
355   gst_x_overlay_set_window_handle (overlay, xwindow_id);
356 }
357 #endif
358
359 /**
360  * gst_x_overlay_set_window_handle:
361  * @overlay: a #GstXOverlay to set the XWindow on.
362  * @xwindow_id: a #XID referencing the XWindow.
363  *
364  * This will call the video overlay's set_window_handle method. You
365  * should use this method to tell to a XOverlay to display video output to a
366  * specific XWindow. Passing 0 as the xwindow_id will tell the overlay to
367  * stop using that window and create an internal one.
368  *
369  * Since: 0.10.31
370  */
371 void
372 gst_x_overlay_set_window_handle (GstXOverlay * overlay, guintptr handle)
373 {
374   GstXOverlayClass *klass;
375
376   g_return_if_fail (overlay != NULL);
377   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
378
379   klass = GST_X_OVERLAY_GET_CLASS (overlay);
380
381   if (klass->set_window_handle) {
382     klass->set_window_handle (overlay, handle);
383   } else {
384 #ifndef GST_REMOVE_DEPRECATED
385 #ifdef GST_DISABLE_DEPRECATED
386 #define set_xwindow_id set_xwindow_id_disabled
387 #endif
388     if (sizeof (guintptr) <= sizeof (gulong) && klass->set_xwindow_id) {
389       GST_WARNING_OBJECT (overlay,
390           "Calling deprecated set_xwindow_id() method");
391       klass->set_xwindow_id (overlay, handle);
392     } else {
393       g_warning ("Refusing to cast guintptr to smaller gulong");
394     }
395 #endif
396   }
397 }
398
399 /**
400  * gst_x_overlay_got_xwindow_id:
401  * @overlay: a #GstXOverlay which got a XWindow.
402  * @xwindow_id: a #XID referencing the XWindow.
403  *
404  * This will post a "have-xwindow-id" element message on the bus.
405  *
406  * This function should only be used by video overlay plugin developers.
407  *
408  * Deprecated: Use gst_x_overlay_got_window_handle() instead.
409  */
410 #ifndef GST_REMOVE_DEPRECATED
411 #ifdef GST_DISABLE_DEPRECATED
412 void gst_x_overlay_got_xwindow_id (GstXOverlay * overlay, gulong xwindow_id);
413 #endif
414 void
415 gst_x_overlay_got_xwindow_id (GstXOverlay * overlay, gulong xwindow_id)
416 {
417   GST_WARNING_OBJECT (overlay,
418       "Using deprecated gst_x_overlay_got_xwindow_id()");
419   gst_x_overlay_got_window_handle (overlay, xwindow_id);
420 }
421 #endif
422
423 /**
424  * gst_x_overlay_got_window_handle:
425  * @overlay: a #GstXOverlay which got a window
426  * @handle: a platform-specific handle referencing the window
427  *
428  * This will post a "have-xwindow-id" element message on the bus.
429  *
430  * This function should only be used by video overlay plugin developers.
431  */
432 void
433 gst_x_overlay_got_window_handle (GstXOverlay * overlay, guintptr handle)
434 {
435   GstStructure *s;
436   GstMessage *msg;
437
438   g_return_if_fail (overlay != NULL);
439   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
440
441   GST_LOG_OBJECT (GST_OBJECT (overlay), "xwindow_id = %p", (gpointer)
442       handle);
443   s = gst_structure_new ("have-xwindow-id",
444       "xwindow-id", G_TYPE_ULONG, (unsigned long) handle,
445       "window-handle", G_TYPE_UINT64, (guint64) handle, NULL);
446   msg = gst_message_new_element (GST_OBJECT (overlay), s);
447   gst_element_post_message (GST_ELEMENT (overlay), msg);
448 }
449
450 /**
451  * gst_x_overlay_prepare_xwindow_id:
452  * @overlay: a #GstXOverlay which does not yet have an XWindow.
453  *
454  * This will post a "prepare-xwindow-id" element message on the bus
455  * to give applications an opportunity to call 
456  * gst_x_overlay_set_xwindow_id() before a plugin creates its own
457  * window.
458  *
459  * This function should only be used by video overlay plugin developers.
460  */
461 void
462 gst_x_overlay_prepare_xwindow_id (GstXOverlay * overlay)
463 {
464   GstStructure *s;
465   GstMessage *msg;
466
467   g_return_if_fail (overlay != NULL);
468   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
469
470   GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare xwindow_id");
471   s = gst_structure_new ("prepare-xwindow-id", NULL);
472   msg = gst_message_new_element (GST_OBJECT (overlay), s);
473   gst_element_post_message (GST_ELEMENT (overlay), msg);
474 }
475
476 /**
477  * gst_x_overlay_expose:
478  * @overlay: a #GstXOverlay to expose.
479  *
480  * Tell an overlay that it has been exposed. This will redraw the current frame
481  * in the drawable even if the pipeline is PAUSED.
482  */
483 void
484 gst_x_overlay_expose (GstXOverlay * overlay)
485 {
486   GstXOverlayClass *klass;
487
488   g_return_if_fail (overlay != NULL);
489   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
490
491   klass = GST_X_OVERLAY_GET_CLASS (overlay);
492
493   if (klass->expose) {
494     klass->expose (overlay);
495   }
496 }
497
498 /**
499  * gst_x_overlay_handle_events:
500  * @overlay: a #GstXOverlay to expose.
501  * @handle_events: a #gboolean indicating if events should be handled or not.
502  *
503  * Tell an overlay that it should handle events from the window system. These
504  * events are forwared upstream as navigation events. In some window system,
505  * events are not propagated in the window hierarchy if a client is listening
506  * for them. This method allows you to disable events handling completely
507  * from the XOverlay.
508  *
509  * Since: 0.10.12
510  */
511 void
512 gst_x_overlay_handle_events (GstXOverlay * overlay, gboolean handle_events)
513 {
514   GstXOverlayClass *klass;
515
516   g_return_if_fail (overlay != NULL);
517   g_return_if_fail (GST_IS_X_OVERLAY (overlay));
518
519   klass = GST_X_OVERLAY_GET_CLASS (overlay);
520
521   if (klass->handle_events) {
522     klass->handle_events (overlay, handle_events);
523   }
524 }
525
526 /**
527  * gst_x_overlay_set_render_rectangle:
528  * @overlay: a #GstXOverlay
529  * @x: the horizontal offset of the render area inside the window
530  * @y: the vertical offset of the render area inside the window
531  * @width: the width of the render area inside the window
532  * @height: the height of the render area inside the window
533  *
534  * Configure a subregion as a video target within the window set by
535  * gst_x_overlay_set_window_handle(). If this is not used or not supported
536  * the video will fill the area of the window set as the overlay to 100%.
537  * By specifying the rectangle, the video can be overlayed to a specific region
538  * of that window only. After setting the new rectangle one should call
539  * gst_x_overlay_expose() to force a redraw. To unset the region pass -1 for
540  * the @width and @height parameters.
541  *
542  * This method is needed for non fullscreen video overlay in UI toolkits that
543  * do not support subwindows.
544  *
545  * Returns: %FALSE if not supported by the sink.
546  *
547  * Since: 0.10.29
548  */
549 gboolean
550 gst_x_overlay_set_render_rectangle (GstXOverlay * overlay,
551     gint x, gint y, gint width, gint height)
552 {
553   GstXOverlayClass *klass;
554
555   g_return_val_if_fail (overlay != NULL, FALSE);
556   g_return_val_if_fail (GST_IS_X_OVERLAY (overlay), FALSE);
557   g_return_val_if_fail ((width == -1 && height == -1) ||
558       (width > 0 && height > 0), FALSE);
559
560   klass = GST_X_OVERLAY_GET_CLASS (overlay);
561
562   if (klass->set_render_rectangle) {
563     klass->set_render_rectangle (overlay, x, y, width, height);
564     return TRUE;
565   }
566   return FALSE;
567 }