Как получить длительность пропаривания данных с GStreamer

1

Я пишу программу для преобразования медиафайла в 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?

Благодарю.

Теги:
audio
gstreamer

1 ответ

1
Лучший ответ

К сожалению, с appsrc невозможно получить точную продолжительность потока, хотя в некоторых форматах с фиксированным битрейтом можно оценить его на основе длины файла, но другие форматы, использующие переменные битрейты, сообщают о неизвестной длине.

Поскольку appsrc работает с входящими буферами (либо push, либо pull model), тем самым получая кусок данных, потребляя его, а затем либо он запрашивает, либо предоставляется следующий фрагмент данных и, следовательно, делает невозможным оценку продолжительности медиа. Кроме того, в модели push невозможно искать носители.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню