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