我目前正在尝试将MP3文件从磁盘流式传输到icecast2
Python中的gstreamer。我无法让它工作。我的初步测试
使用alsasink
来获得直接的本地音频输出。但是一旦我改变了
到shout2send
它停止工作。从日志中我可以搞清楚一些
元素没有正确链接。这在生成的中也是可见的
管道图。但我不明白为什么他们没有联系。我是怎么做的
应该这样做。
我的猜测是shout2send以某种方式不包括文件格式信息,然后无法正确反向传播,以便正确触发动态打击垫。但这是一个相当疯狂的猜测。
我有以下简单的gstreamer脚本:
import logging
import os
import gi
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GObject # NOQA
LOG = logging.getLogger(__name__)
def bus_call(bus, message, loop):
if message.type == Gst.MessageType.EOS:
LOG.debug('End of Stream')
loop.quit()
elif message.type == Gst.MessageType.ERROR:
err, debug = message.parse_error()
LOG.error('!! Error %s: Debug INFO: %s', err, debug)
loop.quit()
elif message.type == Gst.MessageType.STATE_CHANGED:
old, new, pending = message.parse_state_changed()
LOG.debug('State changed from %s to %s (pending=%s)',
old.value_name, new.value_name, pending.value_name)
elif message.type == Gst.MessageType.STREAM_STATUS:
type_, owner = message.parse_stream_status()
LOG.debug('Stream status changed to %s (owner=%s)',
type_.value_name, owner.name)
elif message.type == Gst.MessageType.DURATION_CHANGED:
LOG.debug('Duration changed')
else:
LOG.debug('!! Unknown message type: %r', message.type)
return True
def pad_factory(element):
def pad_added(src, pad):
target = element.sinkpads[0]
pad_name = '%s:%s' % (pad.get_parent_element().name, pad.name)
tgt_name = '%s:%s' % (target.get_parent_element().name, target.name)
LOG.debug('New dynamic pad %s detected on %s. Auto-linking it to %s',
pad_name, src.name, tgt_name)
pad.link(target)
return pad_added
def debug_event(*args, **kwargs):
LOG.debug('Debug Event: %r, %r', args, kwargs)
def play(filename):
LOG.info('Playing %r', filename)
Gst.init(None)
pipeline = Gst.Pipeline()
# Create pipeline elements
filesrc = Gst.ElementFactory.make('filesrc')
filesrc.set_property('location', filename)
audioconvert = Gst.ElementFactory.make('audioconvert')
decodebin = Gst.ElementFactory.make('decodebin')
decodebin.connect('pad-added', pad_factory(audioconvert))
audioresample = Gst.ElementFactory.make('audioresample')
audioresample.connect('pad-added', debug_event)
shout = Gst.ElementFactory.make('shout2send')
shout.set_property('mount', "/stream.mp3")
shout.set_property('port', 8001)
shout.set_property('username', "stream")
shout.set_property('password', "supersecret")
# Add elements to pipeline
pipeline.add(filesrc)
pipeline.add(decodebin)
pipeline.add(audioconvert)
pipeline.add(audioresample)
pipeline.add(shout)
# Link pipeline
filesrc.link(decodebin)
# decodebing is dynamically linked to audioconvert by pad_factory
audioconvert.link(audioresample)
audioresample.link(shout)
bus = pipeline.get_bus()
bus.add_signal_watch()
# Start playback
GObject.threads_init()
loop = GObject.MainLoop()
bus.connect('message', bus_call, loop)
pipeline.set_state(Gst.State.PLAYING)
try:
loop.run()
except Exception:
LOG.exception('Exception raised during main loop')
LOG.info('Finished playback, cleaning up')
pipeline.set_state(Gst.State.NULL)
Gst.debug_bin_to_dot_file(
pipeline,
Gst.DebugGraphDetails.ALL,
'supersimple-debug-graph')
try:
from gouge.colourcli import Simple
Simple.basicConfig(level=0)
except ImportError:
import logging
logging.basicConfig(level=0)
os.environ["GST_DEBUG_DUMP_DOT_DIR"] = "/tmp"
os.putenv('GST_DEBUG_DUMP_DIR_DIR', '/tmp')
os.putenv('GST_DEBUG', '3')
play('/var/mp3/Tagged/The Pretty Reckless/Who You Selling For/02 Oh My God.mp3')
运行上面的脚本给出了以下输出:
INFO:__main__:Playing '/var/mp3/Tagged/The Pretty Reckless/Who You Selling For/02 Oh My God.mp3'
0:00:00.013040847 449 0x55bf7eeebc90 WARN basesrc gstbasesrc.c:3491:gst_base_src_start_complete:<filesrc0> pad not activated yet
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_PLAYING)
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:Stream status changed to GST_STREAM_STATUS_TYPE_CREATE (owner=typefind)
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:Stream status changed to GST_STREAM_STATUS_TYPE_ENTER (owner=typefind)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
0:00:00.018070819 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TDOR' to GStreamer tag
0:00:00.018098545 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TLAN' to GStreamer tag
0:00:00.018111322 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TMED' to GStreamer tag
0:00:00.018125146 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TSO2' to GStreamer tag
DEBUG:__main__:Stream status changed to GST_STREAM_STATUS_TYPE_CREATE (owner=id3demux0)
0:00:00.018142560 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018177535 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'Artists' of type 'TXXX' to GStreamer tag
0:00:00.018202931 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018223671 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018244385 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018261488 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'MusicBrainz Album Release Country' of type 'TXXX' to GStreamer tag
0:00:00.018281367 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018298526 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'MusicBrainz Album Status' of type 'TXXX' to GStreamer tag
0:00:00.018315989 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
0:00:00.018334832 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'MusicBrainz Album Type' of type 'TXXX' to GStreamer tag
0:00:00.018355051 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018375697 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018392442 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'MusicBrainz Release Group Id' of type 'TXXX' to GStreamer tag
0:00:00.018416280 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018435989 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'MusicBrainz Release Track Id' of type 'TXXX' to GStreamer tag
0:00:00.018454110 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
DEBUG:__main__:Stream status changed to GST_STREAM_STATUS_TYPE_ENTER (owner=id3demux0)
0:00:00.018490954 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'Release type' of type 'TXXX' to GStreamer tag
0:00:00.018516954 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018529746 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'Rip date' of type 'TXXX' to GStreamer tag
0:00:00.018539401 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018547040 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'SCRIPT' of type 'TXXX' to GStreamer tag
0:00:00.018554901 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018566128 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'Source' of type 'TXXX' to GStreamer tag
0:00:00.018573992 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'TXXX' to GStreamer tag
0:00:00.018581258 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:208:gst_tag_from_id3_user_tag: Cannot map ID3v2 user tag 'originalyear' of type 'TXXX' to GStreamer tag
0:00:00.018588932 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'UFID' to GStreamer tag
0:00:00.018601234 449 0x55bf7ed9f450 FIXME id3v2 gstid3tag.c:144:gst_tag_from_id3_tag: Cannot map ID3v2 tag 'WXXX' to GStreamer tag
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:Stream status changed to GST_STREAM_STATUS_TYPE_CREATE (owner=mpegaudioparse0)
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:New dynamic pad decodebin0:src_0 detected on decodebin0. Auto-linking it to audioconvert0:sink
DEBUG:__main__:Stream status changed to GST_STREAM_STATUS_TYPE_ENTER (owner=mpegaudioparse0)
DEBUG:__main__:State changed from GST_STATE_NULL to GST_STATE_READY (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
DEBUG:__main__:Duration changed
DEBUG:__main__:State changed from GST_STATE_READY to GST_STATE_PAUSED (pending=GST_STATE_VOID_PENDING)
0:00:00.023287750 449 0x55bf7ed8ccf0 WARN audio-resampler audio-resampler.c:274:convert_taps_gint32_c: can't find exact taps
0:00:00.023595388 449 0x55bf7ed8ccf0 WARN baseparse gstbaseparse.c:3608:gst_base_parse_loop:<mpegaudioparse0> error: Internal data stream error.
0:00:00.023617643 449 0x55bf7ed8ccf0 WARN baseparse gstbaseparse.c:3608:gst_base_parse_loop:<mpegaudioparse0> error: streaming stopped, reason not-linked (-1)
0:00:00.023991939 449 0x55bf7ed8ccf0 WARN audiodecoder gstaudiodecoder.c:1609:gst_audio_decoder_drain:<mad0> audio decoder push buffers failed
ERROR:__main__:!! Error gst-stream-error-quark: Internal data stream error. (1): Debug INFO: gstbaseparse.c(3608): gst_base_parse_loop (): /GstPipeline:pipeline0/GstDecodeBin:decodebin0/GstMpegAudioParse:mpegaudioparse0:
streaming stopped, reason not-linked (-1)
INFO:__main__:Finished playback, cleaning up
生成的管道图像如下所示: