如何使用GStreamer获取流数据的持续时间

时间:2011-11-04 06:46:52

标签: python audio gstreamer

我正在编写一个用GStreamer将媒体文件转换为mp3文件的程序。它有效,但我也想知道音频流的持续时间。以下是简化代码。

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获取正确的音频流数据持续时间?

感谢。

1 个答案:

答案 0 :(得分:1)

不幸的是,对于appsrc,无法获得流的确切持续时间,尽管某些格式具有固定比特率,但可以根据文件长度估算它,但使用可变比特率的其他格式报告未知的长度。

因为appsrc适用于传入的缓冲区(推或拉模型),它接收一大块数据,消耗它,然后它请求或提供下一个数据块,因此估计媒体时间几乎不可能。此外,在推模型中,无法寻找媒体。