2011-11-18 141 views
7

¿Hay alguna manera de hacer una tubería que reproduzca cualquier archivo de video (que también contendrá audio)? He tratado de elementos como la vinculación de:Reproducir audio y video con una tubería en Gstreamer (Python)

filesrc -> decodebin 

junto con

queue -> audioconvert -> autoaudiosink 

y

queue -> autovideoconvert -> autovideosink 

Esto causa dos problemas:

  1. A queue no se pueden vincular a una autovideoconvert .
  2. No tengo idea de cómo implementar una plataforma con el evento "pad-added", especialmente cuando la conexión admite audio y video.

Me gustaría saber cómo hacerlo sin la necesidad de gst.parse_launch. Además, quiero que el pieline funcione con cualquier formato que arroje (como playbin), pero no puedo usar un playbin ya que necesitaré vincular otros elementos (level y volume).

Alternativamente, ¿hay alguna forma de conectar elementos (como level) a un playbin?

Respuesta

3

he construido un example video player que hace uso de los elementos que has descrito.

Debería mostrarle cómo conectar dinámicamente las almohadillas.

''' 
Copyright (c) 2011 Joar Wandborg 

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

--- 

- A response to http://stackoverflow.com/questions/8187257/play-audio-and-video-with-a-pipeline-in-gstreamer-python/8197837 
- Like it? Buy me a beer! https://flattr.com/thing/422997/Joar-Wandborg 
''' 

import gst 
import gobject 
gobject.threads_init() 
import logging 


logging.basicConfig() 

_log = logging.getLogger(__name__) 
_log.setLevel(logging.DEBUG) 


class VideoPlayer(object): 
    ''' 
    Simple video player 
    ''' 

    source_file = None 

    def __init__(self, **kwargs): 
     self.loop = gobject.MainLoop() 

     if kwargs.get('src'): 
      self.source_file = kwargs.get('src') 

     self.__setup() 

    def run(self): 
     self.loop.run() 

    def stop(self): 
     self.loop.quit() 

    def __setup(self): 
     _log.info('Setting up VideoPlayer...') 
     self.__setup_pipeline() 
     _log.info('Set up') 

    def __setup_pipeline(self): 
     self.pipeline = gst.Pipeline('video-player-pipeline') 

     # Source element 
     self.filesrc = gst.element_factory_make('filesrc') 
     self.filesrc.set_property('location', self.source_file) 
     self.pipeline.add(self.filesrc) 

     # Demuxer 
     self.decoder = gst.element_factory_make('decodebin2') 
     self.decoder.connect('pad-added', self.__on_decoded_pad) 
     self.pipeline.add(self.decoder) 

     # Video elements 
     self.videoqueue = gst.element_factory_make('queue', 'videoqueue') 
     self.pipeline.add(self.videoqueue) 

     self.autovideoconvert = gst.element_factory_make('autovideoconvert') 
     self.pipeline.add(self.autovideoconvert) 

     self.autovideosink = gst.element_factory_make('autovideosink') 
     self.pipeline.add(self.autovideosink) 

     # Audio elements 
     self.audioqueue = gst.element_factory_make('queue', 'audioqueue') 
     self.pipeline.add(self.audioqueue) 

     self.audioconvert = gst.element_factory_make('audioconvert') 
     self.pipeline.add(self.audioconvert) 

     self.autoaudiosink = gst.element_factory_make('autoaudiosink') 
     self.pipeline.add(self.autoaudiosink) 

     self.progressreport = gst.element_factory_make('progressreport') 
     self.progressreport.set_property('update-freq', 1) 
     self.pipeline.add(self.progressreport) 

     # Link source and demuxer 
     linkres = gst.element_link_many(
      self.filesrc, 
      self.decoder) 

     if not linkres: 
      _log.error('Could not link source & demuxer elements!\n{0}'.format(
        linkres)) 

     linkres = gst.element_link_many(
      self.audioqueue, 
      self.audioconvert, 
      self.autoaudiosink) 

     if not linkres: 
      _log.error('Could not link audio elements!\n{0}'.format(
        linkres)) 

     linkres = gst.element_link_many(
      self.videoqueue, 
      self.progressreport, 
      self.autovideoconvert, 
      self.autovideosink) 

     if not linkres: 
      _log.error('Could not link video elements!\n{0}'.format(
        linkres)) 

     self.bus = self.pipeline.get_bus() 
     self.bus.add_signal_watch() 
     self.bus.connect('message', self.__on_message) 

     self.pipeline.set_state(gst.STATE_PLAYING) 

    def __on_decoded_pad(self, pad, data): 
     _log.debug('on_decoded_pad: {0}'.format(pad)) 

     if pad.get_caps()[0].to_string().startswith('audio'): 
      pad.link(self.audioqueue.get_pad('sink')) 
     else: 
      pad.link(self.videoqueue.get_pad('sink')) 

    def __on_message(self, bus, message): 
     _log.debug(' - MESSAGE: {0}'.format(message)) 


if __name__ == '__main__': 
    player = VideoPlayer(
     src='/home/joar/Videos/big_buck_bunny_1080p_stereo.avi') 

    player.run()
+0

Perfecto, pero todavía tengo una pregunta más: 'new-decoded-pad' está en desuso. ¿Cómo uso 'pad-added'? –

+0

Gracias por el aviso, he actualizado el código pero aún no he tenido tiempo de probarlo, aunque debería ser muy similar, solo otro método. – joar

+0

Funciona, pero debes poner 'if not sink_pad.is_linked():' antes de vincular los pads. Además, probé esto solo con audio, y nunca se reproduce. ¿Sabes por qué? –

1

queue no es un elemento de origen, debe tener uridecodebin o decodebin o algo similar como elemento de origen.

Este es un ejemplo de canal en el formato gst-launch.

uridecodebin \ 
    uri="file:///home/joar/Dropbox/Music/04 - Deadmau5 - Clockwork (Jonas Steur Remix).mp3" \ 
! audioconvert ! autoaudiosink 

que significa que en la tubería no es

  • uridecodebin - Un cubo de decodificación, capaz de decodificar cualquier archivo fuente es compatible con GStreamer, con la propiedad uri establecido en file:///home/joar/Dropbox/Music/04 - Deadmau5 - Clockwork (Jonas Steur Remix).mp3.
  • audioconvert - Convierte audio entre diferentes formatos
  • autoaudiosink

Si es necesario, se puede añadir un elemento de queue entre el uridecodebin y la audioconvert.


actualización

que pueda hacer lo que usted describe mediante la siguiente GST-lanzamiento de comandos

gst-launch-0.10 filesrc \ 
    location="/home/joar/Dropbox/Skrillex vs. Adele - Set Fire to Everybody.mov" \ 
! decodebin name=dmux \ 
dmux. ! queue ! audioconvert ! autoaudiosink \ 
dmux. ! queue ! autovideoconvert ! autovideosink 
+1

Útil, pero realmente no responde mi pregunta. He actualizado el diseño de la interconexión para hacer las cosas más claras. –

+0

Veo, tengo una idea de cómo resolver esto, desafortunadamente no tengo tiempo por el momento. Por favor, agrega un comentario después de esto para recibir una notificación, luego responderé como pronto como estoy frente a mi PC. – joar

+0

Está bien, agregó una nueva sección, si no está usando el formato de lanzamiento gst, dígame y lo ayudaré a realizarlo con 'gst.element_factory_make()'. – joar

1

Estoy seguro de que ya habrías implementado esto. Pero para otros que vean su pregunta, mi respuesta podría ayudar. El código es el siguiente

#!/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 


def on_new_decoded_pad(dbin, pad, islast): 
    structure_name = pad.get_caps()[0].get_name() 
    decode = pad.get_parent() 
    pipeline = decode.get_parent() 
    if structure_name.startswith("video"): 
      queuev = pipeline.get_by_name('queuev') 
     decode.link(queuev) 
    if structure_name.startswith("audio"): 
      queuea = pipeline.get_by_name('queuea') 
    print queuea 
     decode.link(queuea) 


def main(): 
    pipeline = gst.Pipeline('pipleline') 

    filesrc = gst.element_factory_make("filesrc", "filesrc") 
    filesrc.set_property('location', '/home/thothadri/Videos/nuclear.avi') 

    decode = gst.element_factory_make("decodebin", "decode") 

    queuev = gst.element_factory_make("queue", "queuev") 

    sink = gst.element_factory_make("autovideosink", "sink") 

    queuea = gst.element_factory_make("queue", "queuea") 

    convert = gst.element_factory_make('audioconvert', 'convert') 

    sink_audio = gst.element_factory_make("autoaudiosink", "sink_audio") 

    pipeline.add(filesrc,decode,queuev,queuea,convert,sink,sink_audio) 

    gst.element_link_many(filesrc, decode) 
    gst.element_link_many(queuev,sink) 
    gst.element_link_many(queuea,convert,sink_audio) 

    decode.connect("new-decoded-pad", on_new_decoded_pad) 

    pipeline.set_state(gst.STATE_PLAYING) 



main() 
gtk.gdk.threads_init() 
gtk.main() 
1

Alternativamente podría utilizar GStreamer 1.0 por ahora.

Allí encontrará las nuevas propiedades audio-filter y video-filter, que puede ser utilizado para conectar elementos (tales como level) a un playbin

Con Python GObject introspección esto se podría hacer tan fácil como:.

level = Gst.ElementFactory.make('level') 

playbin = Gst.ElementFactory.make("playbin") 
playbin.props.audio_filter = level 
Cuestiones relacionadas