某些 GStreamer 管道不被视为箱

本文关键字:GStreamer 管道 某些 | 更新日期: 2023-09-27 18:36:42

我可以从命令行运行一个非常简单的启动管道,因此:

gst-launch-1.0 videotestsrc ! ximagesink

并且,从gst-inspect-1.0ximagesink似乎支持 GstVideoOverlay 接口,以便我可以将其绑定到特定的 Gtk 小部件。

但是,当我尝试从我碰巧在网上发现的一些代码中执行此操作时,似乎管道不被视为垃圾箱(因此,没有给它小部件 ID)。

执行此操作的代码如下,首先创建管道并将其设置为捕获总线消息:

Gst.Element playbin = Gst.Parse.Launch("videotestsrc ! ximagesink");
Gst.Bus bus = playbin.Bus;
bus.AddSignalWatch();
bus.Message += MsgCallback;

然后实际处理总线消息:

private void MsgCallback(object o, MessageArgs args) {
    // Only care about window ID binding requests.
    Gst.Message msg = args.Message;
    if (! Gst.Video.Global.IsVideoOverlayPrepareWindowHandleMessage(msg))
        return;
    // Get source of message.
    Gst.Element src = msg.Src as Gst.Element;
    if (src == null)
        return;
    // Find element supporting interface and notify it to bind.
    Gst.Element ov = null;
    if (src is Gst.Bin) {
        ov = ((Gst.Bin) src).GetByInterface(VideoOverlayAdapter.GType);
        VideoOverlayAdapter ad = new VideoOverlayAdapter(ov.Handle);
        ad.WindowHandle = windowXId;
    }
}

现在,由于某种原因,src is Gst.Bin是假的,这意味着windowXId(我之前设置的小部件 ID)永远不会传达给 GStreamer。

但是,如果我提供一个playbin管道(如果您有兴趣,playbin uri=XYZZY videosink='videoconvert ! videoflip method=none ! videoconvert ! autovideosink'),它可以正常工作。

据我从Gst.Parse.Launch()文档中可以看出,它应该给我一个管道,这是一个垃圾箱的特殊情况,如这里(在修复了残酷的语法之后):

成功

时返回一个新元素,失败时返回NULL新元素。如果流水线描述指定了多个顶级元素,则所有元素都放入一个GstPipeline中,然后返回。

我很确定videotestsrcximagesink是两个独立的顶级元素,但是当我添加以下代码时,在检查src是否null之后:

Console.WriteLine("is bin      " + (src is Gst.Bin));
Console.WriteLine("is element  " + (src is Gst.Element));
Console.WriteLine("is pipeline " + (src is Gst.Pipeline));
Console.WriteLine(type is      " + src.GetType());

明白了:

is bin      False
is element  True
is pipeline False
type is     Gst.Element

对于有问题的videotestsrc管道和以下好的playbin管道:

is bin      True
is element  True
is pipeline False
type is     Gst.Bin

因此,尽管文档指出了什么,但一切都指向有问题的元素而不是垃圾箱。

我在这里错过了什么?两个管道之间有什么区别会导致不同的行为?

某些 GStreamer 管道不被视为箱

好的,事实证明Gst.Parse.Launch函数实际上返回了一个管道。如果您在创建 bin 后立即复制这些检查语句,则可以看到这一点:

Gst.Element playbin = Gst.Parse.Launch("videotestsrc ! ximagesink");
Console.WriteLine("is bin      " + (playbin is Gst.Bin));
Console.WriteLine("is element  " + (playbin is Gst.Element));
Console.WriteLine("is pipeline " + (playbin is Gst.Pipeline));
Console.WriteLine(type is      " + playbin.GetType());

你看:

is bin      True
is element  True
is pipeline True
type is     Gst.Pipeline

只是,当我们在回调中收到消息时,源似乎被设置为一个元素。我实际上还没有弄清楚为什么消息源作为一个元素(甚至它是哪个元素)出现,但我至少有一个解决方法,部分归功于我的高级智能,但主要是偷偷摸摸地看一下女妖的方式:-)

事实证明,回调可以简单地直接访问 bin,而不是尝试将其从源代码中取出。这适用于我的情况,因为我每个实例只有一个视频流(bin)。如果您有多个,则可能会更困难一些。

为此,您首先playbin一个成员变量(如果还没有),然后可以这样修改回调:

private void MsgCallback(object o, MessageArgs args) {
    // Only care about window ID binding requests.
    Gst.Message msg = args.Message;
    if (! Gst.Video.Global.IsVideoOverlayPrepareWindowHandleMessage(msg))
        return;
    // Get instance bin, interface element, then notify it to bind.
    Gst.Bin src = (Gst.Bin)(this.playbin);
    if (src == null) return;
    Gst.Element ov = src.GetByInterface(VideoOverlayAdapter.GType);
    if (ov == null) return;
    VideoOverlayAdapter ad = new VideoOverlayAdapter(ov.Handle);
    if (ad == null) return;
    ad.WindowHandle = windowXId;
}