GStreamer总线发送None消息

5 投票
4 回答
4204 浏览
提问于 2025-04-16 23:15

我在一个项目中使用了pygst,一切运行得挺好。现在我想把它迁移到新的 introspection 系统(GI),但遇到了不同的情况。

在旧的 pygst 中,我有这样的代码:

... # other imports
import pygst
pygst.require('0.10')
import gst
... # other imports

gobjects.threads_init()

...

def my_handler(bus, message):
    # handle the message

...

player = gst.element_factory_make('playbin2', 'my_player')
bus = player.get_bus()
bus.connect('message', my_handler)
bus.add_signal_watch()
...
player.set_state(gst.STATE_PLAYING)
# start the main Glib loop

这里的 message 参数有一个属性 .type,可以用来选择性处理信息(我只关心流结束(EOS)和错误)。在新的系统中,我的代码是:

... # other imports
from gi.repository import Gst
import glib
import gobject
.... # other imports

gobject.threads_init()

loop = glib.MainLoop(None, False)

def bus_handler(bus, message):
    print message
    # handle the message
...

Gst.init_check(None)
player = Gst.ElementFactory.make('playbin2', 'my_player')
player.set_property('uri', 'file:///home/kenji/button.ogg')
bus = player.get_bus()
bus.connect('message', bus_handler)
bus.add_signal_watch()
player.set_state(Gst.State.PLAYING)
# start the main loop

但是,处理函数总是把 message 参数当作 None 来接收。我尝试过滤这些信息,但仍然什么都得不到(也就是说,所有的消息都是 None)。

我阅读了很多 GStreamer 的文档(特别是关于 GstBus、add_signal_watch() 和 playbin2 的部分),但没有找到与这种情况相关的内容。我查看了 Gst 的 gir 文件,发现 add_watch() 不能被 introspected,所以这条路走不通。上面例子中的 glib 主循环只是为了让代码更简洁,没有完整的 GTK 示例,但实际上用的是 Gtk.main()(效果是一样的)。

我在 Arch Linux 64 上使用的是 GStreamer 0.10.35.0(通过 Gst.version() 得到的),但我在 Ubuntu 11.04 32 位上测试了 GStreamer 0.10.32.0,结果也是一样。

有没有其他方法可以替代 bus.connect()? 我是不是用错了?我花了不少时间在找这个 bug,真的很希望能得到一些帮助。谢谢!=)

4 个回答

0

如果你不打算在程序中使用GTK,那么你需要运行一个 gobject.Mainloop() 来接收来自总线的信息。这个主循环就像其他的主循环一样,如果程序没有使用多线程的话,它会让整个程序停住。所以我通常会在不需要图形界面的程序最后加上类似下面的代码:

g_loop = threading.Thread(target=gobject.MainLoop().run)
g_loop.daemon = True
g_loop.start()

这样做是为了在需要使用Gstreamer的情况下,程序还能正常运行。

3

我觉得之前的回答是错的。add_signal_watch_fulladd_signal_watch之间唯一的区别是,前者可以让你设置事件源的优先级,而后者只是用G_PRIORITY_DEFAULT来调用前者。你可以在C语言的源代码中验证这一点,具体在第940行。优先级只影响事件触发的顺序,并不会影响事件是否被触发,更不会影响信号消息的内容,这才是问题所在。我还用不同的优先级值进行了测试,如果有办法能让它工作,我愿意吃掉我的帽子。:-)

真正的答案是,它根本不工作。PyGObject和GStreamer 0.10配合得不好。你可以看看:

后者提到:“请注意,虽然你可以勉强用PyGI使用GStreamer 0.10,但关键功能根本就坏了,并且在GStreamer 0.10中永远不会修复(因为这会需要破坏API)。”

那么,你的选择有:

  • 要求使用GStreamer 1.0。
  • 使用旧版的PyGST绑定。
  • 使用PyGObject和GStreamer 0.10,但不能检查像EOS这样的消息。只有非常基本的功能可以工作。
1

我最后使用了 add_signal_watch_full() 这个方法,虽然它的写法比较复杂,但效果很好。我可以在我的处理器上接收到消息。

撰写回答