234ff72ade9cab21fca6be966609be8b89782a82
[platform/upstream/gstreamer.git] / gst-libs / gst / video / videooverlay.c
1 /* GStreamer Video Overlay interface
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * Copyright (C) 2011 Tim-Philipp Müller <tim@centricular.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 /**
21  * SECTION:gstvideooverlay
22  * @short_description: Interface for setting/getting a window system resource
23  *    on elements supporting it to configure a window into which to render a
24  *    video.
25  *
26  * <refsect2>
27  * <para>
28  * The #GstVideoOverlay 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-window-handle' element messages
67  *  if (!gst_is_video_overlay_prepare_window_handle_message (message))
68  *    return GST_BUS_PASS;
69  *
70  *  win = XCreateSimpleWindow (disp, root, 0, 0, 320, 240, 0, 0, 0);
71  *
72  *  XSetWindowBackgroundPixmap (disp, win, None);
73  *
74  *  XMapRaised (disp, win);
75  *
76  *  XSync (disp, FALSE);
77  *
78  *  gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)),
79  *      win);
80  *
81  *  gst_message_unref (message);
82  *
83  *  return GST_BUS_DROP;
84  * }
85  * ...
86  * int
87  * main (int argc, char **argv)
88  * {
89  * ...
90  *  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
91  *  gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, pipeline);
92  * ...
93  * }
94  * ]|
95  * </para>
96  * </refsect2>
97  * <refsect2>
98  * <title>Two basic usage scenarios</title>
99  * <para>
100  * There are two basic usage scenarios: in the simplest case, the application
101  * knows exactly what particular element is used for video output, which is
102  * usually the case when the application creates the videosink to use
103  * (e.g. #xvimagesink, #ximagesink, etc.) itself; in this case, the application
104  * can just create the videosink element, create and realize the window to
105  * render the video on and then call gst_video_overlay_set_window_handle() directly
106  * with the XID or native window handle, before starting up the pipeline.
107  * </para>
108  * <para>
109  * In the other and more common case, the application does not know in advance
110  * what GStreamer video sink element will be used for video output. This is
111  * usually the case when an element such as #autovideosink or #gconfvideosink
112  * is used. In this case, the video sink element itself is created
113  * asynchronously from a GStreamer streaming thread some time after the
114  * pipeline has been started up. When that happens, however, the video sink
115  * will need to know right then whether to render onto an already existing
116  * application window or whether to create its own window. This is when it
117  * posts a prepare-window-handle message, and that is also why this message needs
118  * to be handled in a sync bus handler which will be called from the streaming
119  * thread directly (because the video sink will need an answer right then).
120  * </para>
121  * <para>
122  * As response to the prepare-window-handle element message in the bus sync
123  * handler, the application may use gst_video_overlay_set_window_handle() to tell
124  * the video sink to render onto an existing window surface. At this point the
125  * application should already have obtained the window handle / XID, so it
126  * just needs to set it. It is generally not advisable to call any GUI toolkit
127  * functions or window system functions from the streaming thread in which the
128  * prepare-window-handle message is handled, because most GUI toolkits and
129  * windowing systems are not thread-safe at all and a lot of care would be
130  * required to co-ordinate the toolkit and window system calls of the
131  * different threads (Gtk+ users please note: prior to Gtk+ 2.18
132  * GDK_WINDOW_XID() was just a simple structure access, so generally fine to do
133  * within the bus sync handler; this macro was changed to a function call in
134  * Gtk+ 2.18 and later, which is likely to cause problems when called from a
135  * sync handler; see below for a better approach without GDK_WINDOW_XID()
136  * used in the callback).
137  * </para>
138  * </refsect2>
139  * <refsect2>
140  * <title>GstVideoOverlay and Gtk+</title>
141  * <para>
142  * |[
143  * #include &lt;gst/interfaces/xoverlay.h&gt;
144  * #include &lt;gtk/gtk.h&gt;
145  * #ifdef GDK_WINDOWING_X11
146  * #include &lt;gdk/gdkx.h&gt;  // for GDK_WINDOW_XID
147  * #endif
148  * #ifdef GDK_WINDOWING_WIN32
149  * #include &lt;gdk/gdkwin32.h&gt;  // for GDK_WINDOW_HWND
150  * #endif
151  * ...
152  * static guintptr video_window_handle = 0;
153  * ...
154  * static GstBusSyncReply
155  * bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data)
156  * {
157  *  // ignore anything but 'prepare-window-handle' element messages
158  *  if (!gst_is_video_overlay_prepare_window_handle_message (message))
159  *    return GST_BUS_PASS;
160  *
161  *  if (video_window_handle != 0) {
162  *    GstXOverlay *xoverlay;
163  *
164  *    // GST_MESSAGE_SRC (message) will be the video sink element
165  *    xoverlay = GST_X_OVERLAY (GST_MESSAGE_SRC (message));
166  *    gst_x_overlay_set_window_handle (xoverlay, video_window_handle);
167  *  } else {
168  *    g_warning ("Should have obtained video_window_handle by now!");
169  *  }
170  *
171  *  gst_message_unref (message);
172  *  return GST_BUS_DROP;
173  * }
174  * ...
175  * static void
176  * video_widget_realize_cb (GtkWidget * widget, gpointer data)
177  * {
178  * #if GTK_CHECK_VERSION(2,18,0)
179  *   // Tell Gtk+/Gdk to create a native window for this widget instead of
180  *   // drawing onto the parent widget.
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 GstVideoOverlay!");
185  * #endif
186  *
187  * #ifdef GDK_WINDOWING_X11
188  *   {
189  *     gulong xid = GDK_WINDOW_XID (gtk_widget_get_window (video_window));
190  *     video_window_handle = xid;
191  *   }
192  * #endif
193  * #ifdef GDK_WINDOWING_WIN32
194  *   {
195  *     HWND wnd = GDK_WINDOW_HWND (gtk_widget_get_window (video_window));
196  *     video_window_handle = (guintptr) wnd;
197  *   }
198  * #endif
199  * }
200  * ...
201  * int
202  * main (int argc, char **argv)
203  * {
204  *   GtkWidget *video_window;
205  *   GtkWidget *app_window;
206  *   ...
207  *   app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
208  *   ...
209  *   video_window = gtk_drawing_area_new ();
210  *   g_signal_connect (video_window, "realize",
211  *       G_CALLBACK (video_widget_realize_cb), NULL);
212  *   gtk_widget_set_double_buffered (video_window, FALSE);
213  *   ...
214  *   // usually the video_window will not be directly embedded into the
215  *   // application window like this, but there will be many other widgets
216  *   // and the video window will be embedded in one of them instead
217  *   gtk_container_add (GTK_CONTAINER (ap_window), video_window);
218  *   ...
219  *   // show the GUI
220  *   gtk_widget_show_all (app_window);
221  *
222  *   // realize window now so that the video window gets created and we can
223  *   // obtain its XID/HWND before the pipeline is started up and the videosink
224  *   // asks for the XID/HWND of the window to render onto
225  *   gtk_widget_realize (video_window);
226  *
227  *   // we should have the XID/HWND now
228  *   g_assert (video_window_handle != 0);
229  *   ...
230  *   // set up sync handler for setting the xid once the pipeline is started
231  *   bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
232  *   gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, NULL);
233  *   gst_object_unref (bus);
234  *   ...
235  *   gst_element_set_state (pipeline, GST_STATE_PLAYING);
236  *   ...
237  * }
238  * ]|
239  * </para>
240  * </refsect2>
241  * <refsect2>
242  * <title>GstVideoOverlay and Qt</title>
243  * <para>
244  * |[
245  * #include &lt;glib.h&gt;
246  * #include &lt;gst/gst.h&gt;
247  * #include &lt;gst/interfaces/videooverlay.h&gt;
248  *
249  * #include &lt;QApplication&gt;
250  * #include &lt;QTimer&gt;
251  * #include &lt;QWidget&gt;
252  *
253  * int main(int argc, char *argv[])
254  * {
255  *   if (!g_thread_supported ())
256  *     g_thread_init (NULL);
257  *
258  *   gst_init (&argc, &argv);
259  *   QApplication app(argc, argv);
260  *   app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ()));
261  *
262  *   // prepare the pipeline
263  *
264  *   GstElement *pipeline = gst_pipeline_new ("xvoverlay");
265  *   GstElement *src = gst_element_factory_make ("videotestsrc", NULL);
266  *   GstElement *sink = gst_element_factory_make ("xvimagesink", NULL);
267  *   gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
268  *   gst_element_link (src, sink);
269  *
270  *   // prepare the ui
271  *
272  *   QWidget window;
273  *   window.resize(320, 240);
274  *   window.show();
275  *
276  *   WId xwinid = window.winId();
277  *   gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), xwinid);
278  *
279  *   // run the pipeline
280  *
281  *   GstStateChangeReturn sret = gst_element_set_state (pipeline,
282  *       GST_STATE_PLAYING);
283  *   if (sret == GST_STATE_CHANGE_FAILURE) {
284  *     gst_element_set_state (pipeline, GST_STATE_NULL);
285  *     gst_object_unref (pipeline);
286  *     // Exit application
287  *     QTimer::singleShot(0, QApplication::activeWindow(), SLOT(quit()));
288  *   }
289  *
290  *   int ret = app.exec();
291  *
292  *   window.hide();
293  *   gst_element_set_state (pipeline, GST_STATE_NULL);
294  *   gst_object_unref (pipeline);
295  *
296  *   return ret;
297  * }
298  * ]|
299  * </para>
300  * </refsect2>
301  */
302
303 #ifdef HAVE_CONFIG_H
304 #include "config.h"
305 #endif
306
307 #include "videooverlay.h"
308
309 GType
310 gst_video_overlay_get_type (void)
311 {
312   static GType gst_video_overlay_type = 0;
313
314   if (!gst_video_overlay_type) {
315     static const GTypeInfo gst_video_overlay_info = {
316       sizeof (GstVideoOverlayInterface),
317       NULL,
318       NULL,
319       NULL,
320       NULL,
321       NULL,
322       0,
323       0,
324       NULL,
325     };
326
327     gst_video_overlay_type = g_type_register_static (G_TYPE_INTERFACE,
328         "GstVideoOverlay", &gst_video_overlay_info, 0);
329   }
330
331   return gst_video_overlay_type;
332 }
333
334 /**
335  * gst_video_overlay_set_window_handle:
336  * @overlay: a #GstVideoOverlay to set the window on.
337  * @handle: a handle referencing the window.
338  *
339  * This will call the video overlay's set_window_handle method. You
340  * should use this method to tell to a XOverlay to display video output to a
341  * specific window (e.g. an XWindow on X11). Passing 0 as the  @handle will
342  * tell the overlay to stop using that window and create an internal one.
343  *
344  * Since: 0.10.31
345  */
346 void
347 gst_video_overlay_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
348 {
349   GstVideoOverlayInterface *iface;
350
351   g_return_if_fail (overlay != NULL);
352   g_return_if_fail (GST_IS_VIDEO_OVERLAY (overlay));
353
354   iface = GST_VIDEO_OVERLAY_GET_INTERFACE (overlay);
355
356   if (iface->set_window_handle) {
357     iface->set_window_handle (overlay, handle);
358   }
359 }
360
361 /**
362  * gst_video_overlay_got_window_handle:
363  * @overlay: a #GstVideoOverlay which got a window
364  * @handle: a platform-specific handle referencing the window
365  *
366  * This will post a "have-window-handle" element message on the bus.
367  *
368  * This function should only be used by video overlay plugin developers.
369  */
370 void
371 gst_video_overlay_got_window_handle (GstVideoOverlay * overlay, guintptr handle)
372 {
373   GstStructure *s;
374   GstMessage *msg;
375
376   g_return_if_fail (overlay != NULL);
377   g_return_if_fail (GST_IS_VIDEO_OVERLAY (overlay));
378
379   GST_LOG_OBJECT (GST_OBJECT (overlay), "window_handle = %p", (gpointer)
380       handle);
381   s = gst_structure_new ("have-window-handle",
382       "window-handle", G_TYPE_UINT64, (guint64) handle, NULL);
383   msg = gst_message_new_element (GST_OBJECT (overlay), s);
384   gst_element_post_message (GST_ELEMENT (overlay), msg);
385 }
386
387 /**
388  * gst_video_overlay_prepare_window_handle:
389  * @overlay: a #GstVideoOverlay which does not yet have an Window handle set
390  *
391  * This will post a "prepare-window-handle" element message on the bus
392  * to give applications an opportunity to call
393  * gst_video_overlay_set_window_handle() before a plugin creates its own
394  * window.
395  *
396  * This function should only be used by video overlay plugin developers.
397  */
398 void
399 gst_video_overlay_prepare_window_handle (GstVideoOverlay * overlay)
400 {
401   GstStructure *s;
402   GstMessage *msg;
403
404   g_return_if_fail (overlay != NULL);
405   g_return_if_fail (GST_IS_VIDEO_OVERLAY (overlay));
406
407   GST_LOG_OBJECT (GST_OBJECT (overlay), "prepare window handle");
408   s = gst_structure_new_empty ("prepare-window-handle");
409   msg = gst_message_new_element (GST_OBJECT (overlay), s);
410   gst_element_post_message (GST_ELEMENT (overlay), msg);
411 }
412
413 /**
414  * gst_video_overlay_expose:
415  * @overlay: a #GstVideoOverlay to expose.
416  *
417  * Tell an overlay that it has been exposed. This will redraw the current frame
418  * in the drawable even if the pipeline is PAUSED.
419  */
420 void
421 gst_video_overlay_expose (GstVideoOverlay * overlay)
422 {
423   GstVideoOverlayInterface *iface;
424
425   g_return_if_fail (overlay != NULL);
426   g_return_if_fail (GST_IS_VIDEO_OVERLAY (overlay));
427
428   iface = GST_VIDEO_OVERLAY_GET_INTERFACE (overlay);
429
430   if (iface->expose) {
431     iface->expose (overlay);
432   }
433 }
434
435 /**
436  * gst_video_overlay_handle_events:
437  * @overlay: a #GstVideoOverlay to expose.
438  * @handle_events: a #gboolean indicating if events should be handled or not.
439  *
440  * Tell an overlay that it should handle events from the window system. These
441  * events are forwarded upstream as navigation events. In some window system,
442  * events are not propagated in the window hierarchy if a client is listening
443  * for them. This method allows you to disable events handling completely
444  * from the XOverlay.
445  *
446  * Since: 0.10.12
447  */
448 void
449 gst_video_overlay_handle_events (GstVideoOverlay * overlay,
450     gboolean handle_events)
451 {
452   GstVideoOverlayInterface *iface;
453
454   g_return_if_fail (overlay != NULL);
455   g_return_if_fail (GST_IS_VIDEO_OVERLAY (overlay));
456
457   iface = GST_VIDEO_OVERLAY_GET_INTERFACE (overlay);
458
459   if (iface->handle_events) {
460     iface->handle_events (overlay, handle_events);
461   }
462 }
463
464 /**
465  * gst_video_overlay_set_render_rectangle:
466  * @overlay: a #GstVideoOverlay
467  * @x: the horizontal offset of the render area inside the window
468  * @y: the vertical offset of the render area inside the window
469  * @width: the width of the render area inside the window
470  * @height: the height of the render area inside the window
471  *
472  * Configure a subregion as a video target within the window set by
473  * gst_video_overlay_set_window_handle(). If this is not used or not supported
474  * the video will fill the area of the window set as the overlay to 100%.
475  * By specifying the rectangle, the video can be overlayed to a specific region
476  * of that window only. After setting the new rectangle one should call
477  * gst_video_overlay_expose() to force a redraw. To unset the region pass -1 for
478  * the @width and @height parameters.
479  *
480  * This method is needed for non fullscreen video overlay in UI toolkits that
481  * do not support subwindows.
482  *
483  * Returns: %FALSE if not supported by the sink.
484  *
485  * Since: 0.10.29
486  */
487 gboolean
488 gst_video_overlay_set_render_rectangle (GstVideoOverlay * overlay,
489     gint x, gint y, gint width, gint height)
490 {
491   GstVideoOverlayInterface *iface;
492
493   g_return_val_if_fail (overlay != NULL, FALSE);
494   g_return_val_if_fail (GST_IS_VIDEO_OVERLAY (overlay), FALSE);
495   g_return_val_if_fail ((width == -1 && height == -1) ||
496       (width > 0 && height > 0), FALSE);
497
498   iface = GST_VIDEO_OVERLAY_GET_INTERFACE (overlay);
499
500   if (iface->set_render_rectangle) {
501     iface->set_render_rectangle (overlay, x, y, width, height);
502     return TRUE;
503   }
504   return FALSE;
505 }
506
507 /**
508  * gst_is_video_overlay_prepare_window_handle_message:
509  * @msg: a #GstMessage
510  *
511  * Convenience function to check if the given message is a
512  * "prepare-window-handle" message from a #GstVideoOverlay.
513  *
514  * Since: 0.11.2
515  *
516  * Returns: whether @msg is a "prepare-window-handle" message
517  */
518 gboolean
519 gst_is_video_overlay_prepare_window_handle_message (GstMessage * msg)
520 {
521   g_return_val_if_fail (msg != NULL, FALSE);
522
523   if (GST_MESSAGE_TYPE (msg) != GST_MESSAGE_ELEMENT)
524     return FALSE;
525
526   return gst_message_has_name (msg, "prepare-window-handle");
527 }