I have a C#/Mono application for rendering video streams and, until recently, I've been using my own in-house developed InterOp bindings.
I'm now moving from that method to use those of GStreamer#, since that's likely to be much less maintenance effort, at least for me :-)
Since I need to bind independent video streams to a specific DrawableArea
widgets, my method captured the GStreamer messages then checked them with the function gst_is_video_overlay_prepare_window_handle_message(msg)
(a).
If that returned true, I then responded with a call to gst_video_overlay_set_window_handle(xid)
, where xid
was the handle for the widget obtained earlier with gdk_x11_window_get_xid()
.
My problem is this: searching through the GStreamer# code, I cannot find an equivalent function for doing the binding so I was wondering how this is meant to be done.
Anyone have any advice or information to offer?
The source code for those two functions are in gst-plugins-base-1.4.4/gst-libs/gst/video/videooverlay.c
so, in a pinch, I could dummy up my own functions to do the job (or just stick with our bindings for that one little bit) but it seems to me this would have been included in GStreamer# since rendering to specific widgets seems like a very handy facility.
(a) Those GStreamer wags. They must replace their keyboards quite a bit with all that unnecessary typing :-)
Turns out those functions are available, but in a separate library and sub-namespace to the baseline GStreamer stuff.
The getting of the Xid is still done with a self-made InterOp binding, to wit:
[DllImport("libgdk-3", EntryPoint = "gdk_x11_window_get_xid")]
private extern static IntPtr GdkX11WindowGetXid(IntPtr window);
You also have instance-level variables for the playbin, bus and X11 window ID:
private IntPtr windowXid;
private Gst.Element playBin;
private Gst.Bus bus;
Then, when instantiating the class, you capture the Realized
signal and ensure that all messages on the GStreamer bus go to your callback function:
this.Realized += OnRealized;
playBin = Gst.ElementFactory.Make('playbin', 'playbin');
bus = playBin.Bus;
bus.AddSignalWatch();
bus.Message += MessageCallback;
In that realisation function, you save the Xid for later use (in an instance variable):
void OnRealized(object o, EventArgs args) {
windowXid = GdkX11WindowGetXid(this.Window.Handle);
}
and, when asked by GStreamer, provide this handle in response to the request:
private void MessageCallback(object o, MessageArgs args) {
Gst.Message msg = args.Message;
if (! Gst.Video.Global.IsVideoOverlayPrepareWindowHandleMessage(msg))
return;
Gst.Element src = msg.Src as Gst.Element;
if (src == null)
return;
Gst.Element overlay = null;
if (src is Gst.Bin)
overlay = ((Gst.Bin)src).GetByInterface
Gst.Video.VideoOverlayAdapter = new Gst.Video.VideoOverlayAdapter(overlay.Handle);
adapter.WindowHandle = windowXid;
}
Note that I've fully qualified all the GStreamer objects so it's absolutely clear where they can be found. The code would probably be a lot cleaner without them (and with using var
for the variables) but I wanted to ensure all information was available.