Python的Gstreamer gst.LinkError问题
我正在用Python编写一个gstreamer应用程序。然后我遇到了一个链接错误,代码如下:
import pygst
pygst.require('0.10')
import gst
import pygtk
pygtk.require('2.0')
import gtk
# this is very important, without this, callbacks from gstreamer thread
# will messed our program up
gtk.gdk.threads_init()
def main():
pipeline = gst.Pipeline('pipleline')
filesrc = gst.element_factory_make("filesrc", "filesrc")
filesrc.set_property('location', 'C:/a.mp3')
decode = gst.element_factory_make("decodebin", "decode")
convert = gst.element_factory_make('audioconvert', 'convert')
sink = gst.element_factory_make("autoaudiosink", "sink")
pipeline.add(filesrc, decode, convert, sink)
gst.element_link_many(filesrc, decode, convert, sink)
pipeline.set_state(gst.STATE_PLAYING)
gtk.main()
main()
错误信息是:
ImportError: could not import gio
Traceback (most recent call last):
File "H:\workspace\ggg\src\test2.py", line 37, in <module>
main()
File "H:\workspace\ggg\src\test2.py", line 31, in main
gst.element_link_many(filesrc, decode, convert, sink)
gst.LinkError: failed to link decode with convert
这很奇怪,使用相同的管道,但用parse_launch构建的代码却能正常工作。这里是代码:
import pygst
pygst.require('0.10')
import gst
import pygtk
pygtk.require('2.0')
import gtk
# this is very important, without this, callbacks from gstreamer thread
# will messed our program up
gtk.gdk.threads_init()
def main():
player = gst.parse_launch('filesrc location=C:/a.mp3 ! decodebin ! audioconvert ! autoaudiosink')
player.set_state(gst.STATE_PLAYING)
gtk.main()
main()
问题来了,为什么手动创建的管道失败了,而解析出来的却成功?到底哪里出了问题?我该怎么解决呢?
谢谢。
1 个回答
你的问题出在这里:
gst.element_link_many(filesrc, decode, convert, sink)
原因是并不是所有的元素都有简单、固定的输入和输出。在你程序的这个阶段,你的 decodebin 没有任何源端口(也就是说:没有输出)。
端口就像是一个小口子——它是元素的输入/输出。端口可以出现、消失,或者就静静地待着。端口有三种类型:静态端口(最简单的,符合你的预期)、请求端口(只有在你请求时才会出现)和 有时端口(只有当元素想要时才会出现)。decodebin 的输出是 有时端口。
如果你查看 gst-inspect decodebin
的输出,你就能自己看到这一点:
Pad Templates:
SINK template: 'sink'
Availability: Always
Capabilities:
ANY
SRC template: 'src%d'
Availability: Sometimes
Capabilities:
ANY
在你程序的第26行,你无法将 decode 连接到任何东西,因为它没有任何源端口可以连接。decodebin 的源端口只有在输入流被解码时才会出现:这并不是瞬间发生的。可能会出现任意数量的源端口(例如,一个用于音频流,两个用于带音频的视频流,或者对于无法解码的流则没有)。
你需要等到端口被创建后,再进行连接。decodebin 会发出一个信号,叫做 "new-decoded-pad",来告诉你这个事情发生了(这在 gst-inspect decodebin
中也有说明)。你必须将一个回调函数连接到这个信号,并在回调中将 decode 和 audioconvert 连接起来。以下是你修正后的代码:
#!/usr/bin/python
import pygst
pygst.require('0.10')
import gst
import pygtk
pygtk.require('2.0')
import gtk
# this is very important, without this, callbacks from gstreamer thread
# will messed our program up
gtk.gdk.threads_init()
def on_new_decoded_pad(dbin, pad, islast):
decode = pad.get_parent()
pipeline = decode.get_parent()
convert = pipeline.get_by_name('convert')
decode.link(convert)
pipeline.set_state(gst.STATE_PLAYING)
print "linked!"
def main():
pipeline = gst.Pipeline('pipleline')
filesrc = gst.element_factory_make("filesrc", "filesrc")
filesrc.set_property('location', 'C:/a.mp3')
decode = gst.element_factory_make("decodebin", "decode")
convert = gst.element_factory_make('audioconvert', 'convert')
sink = gst.element_factory_make("autoaudiosink", "sink")
pipeline.add(filesrc, decode, convert, sink)
gst.element_link_many(filesrc, decode)
gst.element_link_many(convert, sink)
decode.connect("new-decoded-pad", on_new_decoded_pad)
pipeline.set_state(gst.STATE_PAUSED)
gtk.main()
main()
gst.parse_launch
可以正常工作,因为它为你处理了所有这些麻烦的细节。还有一个高级元素 playbin
,它会自动创建并内部连接一个 decodebin。