GStreamer总线发送None消息
我在一个项目中使用了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 个回答
如果你不打算在程序中使用GTK,那么你需要运行一个 gobject.Mainloop()
来接收来自总线的信息。这个主循环就像其他的主循环一样,如果程序没有使用多线程的话,它会让整个程序停住。所以我通常会在不需要图形界面的程序最后加上类似下面的代码:
g_loop = threading.Thread(target=gobject.MainLoop().run)
g_loop.daemon = True
g_loop.start()
这样做是为了在需要使用Gstreamer的情况下,程序还能正常运行。
我觉得之前的回答是错的。add_signal_watch_full
和add_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这样的消息。只有非常基本的功能可以工作。
我最后使用了 add_signal_watch_full()
这个方法,虽然它的写法比较复杂,但效果很好。我可以在我的处理器上接收到消息。