1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD 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 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module gstinterfaces.VideoOverlay; 26 27 private import gobject.ObjectClass; 28 private import gobject.ObjectG; 29 private import gobject.Value; 30 private import gstinterfaces.c.functions; 31 public import gstinterfaces.c.types; 32 private import gstreamer.Element; 33 public import gstreamerc.gstinterfacestypes; 34 35 36 /** 37 * The #GstVideoOverlay interface is used for 2 main purposes : 38 * 39 * * To get a grab on the Window where the video sink element is going to render. 40 * This is achieved by either being informed about the Window identifier that 41 * the video sink element generated, or by forcing the video sink element to use 42 * a specific Window identifier for rendering. 43 * * To force a redrawing of the latest video frame the video sink element 44 * displayed on the Window. Indeed if the #GstPipeline is in #GST_STATE_PAUSED 45 * state, moving the Window around will damage its content. Application 46 * developers will want to handle the Expose events themselves and force the 47 * video sink element to refresh the Window's content. 48 * 49 * Using the Window created by the video sink is probably the simplest scenario, 50 * in some cases, though, it might not be flexible enough for application 51 * developers if they need to catch events such as mouse moves and button 52 * clicks. 53 * 54 * Setting a specific Window identifier on the video sink element is the most 55 * flexible solution but it has some issues. Indeed the application needs to set 56 * its Window identifier at the right time to avoid internal Window creation 57 * from the video sink element. To solve this issue a #GstMessage is posted on 58 * the bus to inform the application that it should set the Window identifier 59 * immediately. Here is an example on how to do that correctly: 60 * |[ 61 * static GstBusSyncReply 62 * create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline) 63 * { 64 * // ignore anything but 'prepare-window-handle' element messages 65 * if (!gst_is_video_overlay_prepare_window_handle_message (message)) 66 * return GST_BUS_PASS; 67 * 68 * win = XCreateSimpleWindow (disp, root, 0, 0, 320, 240, 0, 0, 0); 69 * 70 * XSetWindowBackgroundPixmap (disp, win, None); 71 * 72 * XMapRaised (disp, win); 73 * 74 * XSync (disp, FALSE); 75 * 76 * gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)), 77 * win); 78 * 79 * gst_message_unref (message); 80 * 81 * return GST_BUS_DROP; 82 * } 83 * ... 84 * int 85 * main (int argc, char **argv) 86 * { 87 * ... 88 * bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 89 * gst_bus_set_sync_handler (bus, (GstBusSyncHandler) create_window, pipeline, 90 * NULL); 91 * ... 92 * } 93 * ]| 94 * 95 * ## Two basic usage scenarios 96 * 97 * There are two basic usage scenarios: in the simplest case, the application 98 * uses #playbin or #plasink or knows exactly what particular element is used 99 * for video output, which is usually the case when the application creates 100 * the videosink to use (e.g. #xvimagesink, #ximagesink, etc.) itself; in this 101 * case, the application can just create the videosink element, create and 102 * realize the window to render the video on and then 103 * call gst_video_overlay_set_window_handle() directly with the XID or native 104 * window handle, before starting up the pipeline. 105 * As #playbin and #playsink implement the video overlay interface and proxy 106 * it transparently to the actual video sink even if it is created later, this 107 * case also applies when using these elements. 108 * 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 is used. 112 * 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 * 121 * As response to the prepare-window-handle element message in the bus sync 122 * handler, the application may use gst_video_overlay_set_window_handle() to tell 123 * the video sink to render onto an existing window surface. At this point the 124 * application should already have obtained the window handle / XID, so it 125 * just needs to set it. It is generally not advisable to call any GUI toolkit 126 * functions or window system functions from the streaming thread in which the 127 * prepare-window-handle message is handled, because most GUI toolkits and 128 * windowing systems are not thread-safe at all and a lot of care would be 129 * required to co-ordinate the toolkit and window system calls of the 130 * different threads (Gtk+ users please note: prior to Gtk+ 2.18 131 * GDK_WINDOW_XID() was just a simple structure access, so generally fine to do 132 * within the bus sync handler; this macro was changed to a function call in 133 * Gtk+ 2.18 and later, which is likely to cause problems when called from a 134 * sync handler; see below for a better approach without GDK_WINDOW_XID() 135 * used in the callback). 136 * 137 * ## GstVideoOverlay and Gtk+ 138 * 139 * |[ 140 * #include <gst/video/videooverlay.h> 141 * #include <gtk/gtk.h> 142 * #ifdef GDK_WINDOWING_X11 143 * #include <gdk/gdkx.h> // for GDK_WINDOW_XID 144 * #endif 145 * #ifdef GDK_WINDOWING_WIN32 146 * #include <gdk/gdkwin32.h> // for GDK_WINDOW_HWND 147 * #endif 148 * ... 149 * static guintptr video_window_handle = 0; 150 * ... 151 * static GstBusSyncReply 152 * bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data) 153 * { 154 * // ignore anything but 'prepare-window-handle' element messages 155 * if (!gst_is_video_overlay_prepare_window_handle_message (message)) 156 * return GST_BUS_PASS; 157 * 158 * if (video_window_handle != 0) { 159 * GstVideoOverlay *overlay; 160 * 161 * // GST_MESSAGE_SRC (message) will be the video sink element 162 * overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)); 163 * gst_video_overlay_set_window_handle (overlay, video_window_handle); 164 * } else { 165 * g_warning ("Should have obtained video_window_handle by now!"); 166 * } 167 * 168 * gst_message_unref (message); 169 * return GST_BUS_DROP; 170 * } 171 * ... 172 * static void 173 * video_widget_realize_cb (GtkWidget * widget, gpointer data) 174 * { 175 * #if GTK_CHECK_VERSION(2,18,0) 176 * // Tell Gtk+/Gdk to create a native window for this widget instead of 177 * // drawing onto the parent widget. 178 * // This is here just for pedagogical purposes, GDK_WINDOW_XID will call 179 * // it as well in newer Gtk versions 180 * if (!gdk_window_ensure_native (widget->window)) 181 * g_error ("Couldn't create native window needed for GstVideoOverlay!"); 182 * #endif 183 * 184 * #ifdef GDK_WINDOWING_X11 185 * { 186 * gulong xid = GDK_WINDOW_XID (gtk_widget_get_window (video_window)); 187 * video_window_handle = xid; 188 * } 189 * #endif 190 * #ifdef GDK_WINDOWING_WIN32 191 * { 192 * HWND wnd = GDK_WINDOW_HWND (gtk_widget_get_window (video_window)); 193 * video_window_handle = (guintptr) wnd; 194 * } 195 * #endif 196 * } 197 * ... 198 * int 199 * main (int argc, char **argv) 200 * { 201 * GtkWidget *video_window; 202 * GtkWidget *app_window; 203 * ... 204 * app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 205 * ... 206 * video_window = gtk_drawing_area_new (); 207 * g_signal_connect (video_window, "realize", 208 * G_CALLBACK (video_widget_realize_cb), NULL); 209 * gtk_widget_set_double_buffered (video_window, FALSE); 210 * ... 211 * // usually the video_window will not be directly embedded into the 212 * // application window like this, but there will be many other widgets 213 * // and the video window will be embedded in one of them instead 214 * gtk_container_add (GTK_CONTAINER (ap_window), video_window); 215 * ... 216 * // show the GUI 217 * gtk_widget_show_all (app_window); 218 * 219 * // realize window now so that the video window gets created and we can 220 * // obtain its XID/HWND before the pipeline is started up and the videosink 221 * // asks for the XID/HWND of the window to render onto 222 * gtk_widget_realize (video_window); 223 * 224 * // we should have the XID/HWND now 225 * g_assert (video_window_handle != 0); 226 * ... 227 * // set up sync handler for setting the xid once the pipeline is started 228 * bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); 229 * gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, NULL, 230 * NULL); 231 * gst_object_unref (bus); 232 * ... 233 * gst_element_set_state (pipeline, GST_STATE_PLAYING); 234 * ... 235 * } 236 * ]| 237 * 238 * ## GstVideoOverlay and Qt 239 * 240 * |[ 241 * #include <glib.h> 242 * #include <gst/gst.h> 243 * #include <gst/video/videooverlay.h> 244 * 245 * #include <QApplication> 246 * #include <QTimer> 247 * #include <QWidget> 248 * 249 * int main(int argc, char *argv[]) 250 * { 251 * if (!g_thread_supported ()) 252 * g_thread_init (NULL); 253 * 254 * gst_init (&argc, &argv); 255 * QApplication app(argc, argv); 256 * app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ())); 257 * 258 * // prepare the pipeline 259 * 260 * GstElement *pipeline = gst_pipeline_new ("xvoverlay"); 261 * GstElement *src = gst_element_factory_make ("videotestsrc", NULL); 262 * GstElement *sink = gst_element_factory_make ("xvimagesink", NULL); 263 * gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); 264 * gst_element_link (src, sink); 265 * 266 * // prepare the ui 267 * 268 * QWidget window; 269 * window.resize(320, 240); 270 * window.show(); 271 * 272 * WId xwinid = window.winId(); 273 * gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), xwinid); 274 * 275 * // run the pipeline 276 * 277 * GstStateChangeReturn sret = gst_element_set_state (pipeline, 278 * GST_STATE_PLAYING); 279 * if (sret == GST_STATE_CHANGE_FAILURE) { 280 * gst_element_set_state (pipeline, GST_STATE_NULL); 281 * gst_object_unref (pipeline); 282 * // Exit application 283 * QTimer::singleShot(0, QApplication::activeWindow(), SLOT(quit())); 284 * } 285 * 286 * int ret = app.exec(); 287 * 288 * window.hide(); 289 * gst_element_set_state (pipeline, GST_STATE_NULL); 290 * gst_object_unref (pipeline); 291 * 292 * return ret; 293 * } 294 * ]| 295 */ 296 public class VideoOverlay 297 { 298 /** the main Gtk struct */ 299 protected GstVideoOverlay* gstVideoOverlay; 300 protected bool ownedRef; 301 302 /** Get the main Gtk struct */ 303 public GstVideoOverlay* getVideoOverlayStruct(bool transferOwnership = false) 304 { 305 if (transferOwnership) 306 ownedRef = false; 307 return gstVideoOverlay; 308 } 309 310 /** the main Gtk struct as a void* */ 311 protected void* getStruct() 312 { 313 return cast(void*)gstVideoOverlay; 314 } 315 316 /** 317 * Sets our main struct and passes it to the parent class. 318 */ 319 public this (GstVideoOverlay* gstVideoOverlay, bool ownedRef = false) 320 { 321 this.gstVideoOverlay = gstVideoOverlay; 322 this.ownedRef = ownedRef; 323 } 324 325 /** 326 * The Element parameter should usually be 327 * your videosink that you want to create your 328 * XOverlay with. 329 */ 330 public this(Element elem) 331 { 332 this( cast(GstVideoOverlay*)elem.getElementStruct() ); 333 } 334 335 /** 336 */ 337 338 /** */ 339 public static GType getType() 340 { 341 return gst_video_overlay_get_type(); 342 } 343 344 /** 345 * This helper shall be used by classes implementing the #GstVideoOverlay 346 * interface that want the render rectangle to be controllable using 347 * properties. This helper will install "render-rectangle" property into the 348 * class. 349 * 350 * Since 1.14 351 * 352 * Params: 353 * oclass = The class on which the properties will be installed 354 * lastPropId = The first free property ID to use 355 */ 356 public static void installProperties(ObjectClass oclass, int lastPropId) 357 { 358 gst_video_overlay_install_properties((oclass is null) ? null : oclass.getObjectClassStruct(), lastPropId); 359 } 360 361 /** 362 * This helper shall be used by classes implementing the #GstVideoOverlay 363 * interface that want the render rectangle to be controllable using 364 * properties. This helper will parse and set the render rectangle calling 365 * gst_video_overlay_set_render_rectangle(). 366 * 367 * Params: 368 * object = The instance on which the property is set 369 * lastPropId = The highest property ID. 370 * propertyId = The property ID 371 * value = The #GValue to be set 372 * 373 * Returns: %TRUE if the @property_id matches the GstVideoOverlay property 374 * 375 * Since 1.14 376 */ 377 public static bool setProperty(ObjectG object, int lastPropId, uint propertyId, Value value) 378 { 379 return gst_video_overlay_set_property((object is null) ? null : object.getObjectGStruct(), lastPropId, propertyId, (value is null) ? null : value.getValueStruct()) != 0; 380 } 381 382 /** 383 * Tell an overlay that it has been exposed. This will redraw the current frame 384 * in the drawable even if the pipeline is PAUSED. 385 */ 386 public void expose() 387 { 388 gst_video_overlay_expose(getVideoOverlayStruct()); 389 } 390 391 /** 392 * This will post a "have-window-handle" element message on the bus. 393 * 394 * This function should only be used by video overlay plugin developers. 395 * 396 * Params: 397 * handle = a platform-specific handle referencing the window 398 */ 399 public void gotWindowHandle(size_t handle) 400 { 401 gst_video_overlay_got_window_handle(getVideoOverlayStruct(), handle); 402 } 403 404 /** 405 * Tell an overlay that it should handle events from the window system. These 406 * events are forwarded upstream as navigation events. In some window system, 407 * events are not propagated in the window hierarchy if a client is listening 408 * for them. This method allows you to disable events handling completely 409 * from the #GstVideoOverlay. 410 * 411 * Params: 412 * handleEvents = a #gboolean indicating if events should be handled or not. 413 */ 414 public void handleEvents(bool handleEvents) 415 { 416 gst_video_overlay_handle_events(getVideoOverlayStruct(), handleEvents); 417 } 418 419 /** 420 * This will post a "prepare-window-handle" element message on the bus 421 * to give applications an opportunity to call 422 * gst_video_overlay_set_window_handle() before a plugin creates its own 423 * window. 424 * 425 * This function should only be used by video overlay plugin developers. 426 */ 427 public void prepareWindowHandle() 428 { 429 gst_video_overlay_prepare_window_handle(getVideoOverlayStruct()); 430 } 431 432 /** 433 * Configure a subregion as a video target within the window set by 434 * gst_video_overlay_set_window_handle(). If this is not used or not supported 435 * the video will fill the area of the window set as the overlay to 100%. 436 * By specifying the rectangle, the video can be overlayed to a specific region 437 * of that window only. After setting the new rectangle one should call 438 * gst_video_overlay_expose() to force a redraw. To unset the region pass -1 for 439 * the @width and @height parameters. 440 * 441 * This method is needed for non fullscreen video overlay in UI toolkits that 442 * do not support subwindows. 443 * 444 * Params: 445 * x = the horizontal offset of the render area inside the window 446 * y = the vertical offset of the render area inside the window 447 * width = the width of the render area inside the window 448 * height = the height of the render area inside the window 449 * 450 * Returns: %FALSE if not supported by the sink. 451 */ 452 public bool setRenderRectangle(int x, int y, int width, int height) 453 { 454 return gst_video_overlay_set_render_rectangle(getVideoOverlayStruct(), x, y, width, height) != 0; 455 } 456 457 /** 458 * This will call the video overlay's set_window_handle method. You 459 * should use this method to tell to an overlay to display video output to a 460 * specific window (e.g. an XWindow on X11). Passing 0 as the @handle will 461 * tell the overlay to stop using that window and create an internal one. 462 * 463 * Params: 464 * handle = a handle referencing the window. 465 */ 466 public void setWindowHandle(size_t handle) 467 { 468 gst_video_overlay_set_window_handle(getVideoOverlayStruct(), handle); 469 } 470 }