Я пишу программу для преобразования медиафайла в mp3 файл с помощью GStreamer. Он работает, но я также хотел бы знать продолжительность аудиопотока. Ниже приведен упрощенный код.
import logging
import pygst
pygst.require('0.10')
import gst
# this is very important, without this, callbacks from gstreamer thread
# will messed our program up
import gobject
gobject.threads_init()
def on_new_buffer(appsink):
buf = appsink.emit('pull-buffer')
print 'new buffer', len(buf)
def on_new_preroll(appsink):
buf = appsink.emit('pull-preroll')
print 'new preroll', len(buf)
def on_pad_added(decoder, pad):
print 'Pad added'
decoder.link(converter)
pipeline.set_state(gst.STATE_PLAYING)
def on_msg(msg):
if msg.type == gst.MESSAGE_ERROR:
error, debug = msg.parse_error()
print error, debug
elif msg.type == gst.MESSAGE_EOS:
duration = pipeline.query_duration(gst.FORMAT_TIME)
print 'Duration', duration
pipeline = gst.Pipeline('pipeline')
appsrc = gst.element_factory_make('appsrc', 'src')
decoder = gst.element_factory_make('decodebin2', 'decoder')
converter = gst.element_factory_make('audioconvert', 'converter')
lame = gst.element_factory_make('lamemp3enc', 'lame')
appsink = gst.element_factory_make('appsink', 'sink')
pipeline.add(appsrc, decoder, lame, converter, appsink)
gst.element_link_many(appsrc, decoder)
gst.element_link_many(converter, lame, appsink)
# -- setup appskink --
# -- setup decoder --
decoder.connect('pad-added', on_pad_added)
# -- setup mp3 encoder --
lame.set_property('bitrate', 128)
# -- setup appsink --
# this makes appsink emit singals
appsink.set_property('emit-signals', True)
# turns off sync to make decoding as fast as possible
appsink.set_property('sync', False)
appsink.connect('new-buffer', on_new_buffer)
appsink.connect('new-preroll', on_new_preroll)
pipeline.set_state(gst.STATE_PAUSED)
data = open(r'D:\Musics\Fiona Fung - Proud Of You.mp3', 'rb').read()
buf = gst.Buffer(data)
appsrc.emit('push-buffer', buf)
appsrc.emit('end-of-stream')
bus = pipeline.get_bus()
while True:
msg = bus.poll(gst.MESSAGE_ANY, -1)
on_msg(msg)
Я не использовал filesrc в качестве источника, вместо этого я использую appsrc. Я хотел бы читать потоковые данные из Интернета, а не из файла. Как ни странно, в результате длительность вывода -1
....
new buffer 315
new buffer 320
new buffer 335
new buffer 553
Duration (-1L, <enum GST_FORMAT_TIME of type GstFormat>)
Если я переключу appsrc на filesrc, то продолжительность будет верной
import logging
import pygst
pygst.require('0.10')
import gst
# this is very important, without this, callbacks from gstreamer thread
# will messed our program up
import gobject
gobject.threads_init()
def on_new_buffer(appsink):
buf = appsink.emit('pull-buffer')
print 'new buffer', len(buf)
def on_new_preroll(appsink):
buf = appsink.emit('pull-preroll')
print 'new preroll', len(buf)
def on_pad_added(decoder, pad):
print 'Pad added'
decoder.link(converter)
pipeline.set_state(gst.STATE_PLAYING)
def on_msg(msg):
if msg.type == gst.MESSAGE_ERROR:
error, debug = msg.parse_error()
print error, debug
elif msg.type == gst.MESSAGE_EOS:
duration = pipeline.query_duration(gst.FORMAT_TIME)
print 'Duration', duration
pipeline = gst.Pipeline('pipeline')
filesrc = gst.element_factory_make('filesrc', 'src')
decoder = gst.element_factory_make('decodebin2', 'decoder')
converter = gst.element_factory_make('audioconvert', 'converter')
lame = gst.element_factory_make('lamemp3enc', 'lame')
appsink = gst.element_factory_make('appsink', 'sink')
pipeline.add(filesrc, decoder, lame, converter, appsink)
gst.element_link_many(filesrc, decoder)
gst.element_link_many(converter, lame, appsink)
# -- setup filesrc --
filesrc.set_property('location', r'D:\Musics\Fiona Fung - Proud Of You.mp3')
# -- setup decoder --
decoder.connect('pad-added', on_pad_added)
# -- setup mp3 encoder --
lame.set_property('bitrate', 128)
# -- setup appsink --
# this makes appsink emit singals
appsink.set_property('emit-signals', True)
# turns off sync to make decoding as fast as possible
appsink.set_property('sync', False)
appsink.connect('new-buffer', on_new_buffer)
appsink.connect('new-preroll', on_new_preroll)
pipeline.set_state(gst.STATE_PAUSED)
bus = pipeline.get_bus()
while True:
msg = bus.poll(gst.MESSAGE_ANY, -1)
on_msg(msg)
Как вы можете видеть, результат теперь правильный.
new buffer 322
new buffer 323
new buffer 315
new buffer 320
new buffer 549
Duration (189459000000L, <enum GST_FORMAT_TIME of type GstFormat>)
Итак, мой вопрос: как получить правильную продолжительность данных аудиопотока от appsrc?
Благодарю.
К сожалению, с appsrc
невозможно получить точную продолжительность потока, хотя в некоторых форматах с фиксированным битрейтом можно оценить его на основе длины файла, но другие форматы, использующие переменные битрейты, сообщают о неизвестной длине.
Поскольку appsrc
работает с входящими буферами (либо push, либо pull model), тем самым получая кусок данных, потребляя его, а затем либо он запрашивает, либо предоставляется следующий фрагмент данных и, следовательно, делает невозможным оценку продолжительности медиа. Кроме того, в модели push невозможно искать носители.