appsrc + decodebin

dgoiko dario at dail-software.com
Fri Nov 23 10:32:50 UTC 2018




baldman88 wrote
> Hi to everyone. Sorry for my English. I have tried to find answer to my
> question, but without any results. I need to decode mp3 data to raw PCM
> data. I tried to change example for stream from github, but made something
> wrong. I need to get data from external buffer (on the start the size of
> data in stream is unknown, but for test I read chunks of data from the
> file), next decode it with decodebin, and finaly push decoded RAW data to
> appsink. But for begin I tried to push RAW data to alsasink (it is much
> more easy to test). The problem is that instead of sound i hear some noise
> (something like a fast forward). It looks like that the every new buffer,
> readed on "need-data" signal, starts play imediately. I have tried to
> change different settings of appsrc and decodebin, but it have no any
> effect. What i do wrong?

Hi there. You need source-setup and on_source_need_data. In my case, I've a
glitch in my code: source emits that signal BEFORE I've opened  my own
stream from the outside. In order to avoid such problems, Imade a small loop
inside. This should be done only while testing, and a more robust solution
shall be looked for.

No idea about decodebin, but this should be similar to uridecodebin. This
script works. Gets data from appsrc and feeds it to autoaudiosink and
autovideosink: Be carefull with pads! I'm not sure if pads are allways added
in the same order, it should be wiser to compare against caps yo see if
they're audio or video, and then link with your stuff.

This is a very basic draft I just made out of my development state app, if
there's something anyone would improve, i'm happy to listen: I'm new to
gstreamer.

class PlayerUriDecoodeBin:
    def __init__(self):
        # SSocket abierto
        self.fd = None
        self.pipeline = None
        self.binRecord = None
        self.binTranscripcion = None
        self.binDebug = None

        # Pipeline. Es el corazón del sistema. Gestiona punteros, tiempos,
flujos... Worship the pipeline!
        self.pipeline = Gst.Pipeline()
        # Conectamos las funciones de alimentación de datos al Pipeline.
        # Obtenemos el bus principal de la pipeline y le añadimos signal
handlers.
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        self.bus.connect('message::eos', self.on_eos)
        self.bus.connect('message::tag', self.on_tag)
        self.bus.connect('message::error', self.on_error)

        # Create elements
        self.srcdec = Gst.ElementFactory.make('uridecodebin')
        self.srcdec.connect("source-setup", self.on_source_setup)
        # self.conv = Gst.ElementFactory.make('audioconvert')
        # self.rsmpl = Gst.ElementFactory.make('audioresample')
        # self.sink = Gst.ElementFactory.make('alsasink')
        self.videosink = Gst.ElementFactory.make('autovideosink')
        self.audiosink = Gst.ElementFactory.make('autoaudiosink')

        # Set 'location' property on filesrc
        self.srcdec.set_property('uri', "appsrc://")

        # Connect handler for 'pad-added' signal
        self.srcdec.connect('pad-added', self.on_pad_added)

        # Add elements to pipeline
        self.pipeline.add(self.srcdec)
        # self.pipeline.add(self.conv)
        # self.pipeline.add(self.rsmpl)
        self.pipeline.add(self.videosink)
        self.pipeline.add(self.audiosink)
        # Link *some* elements
        # This is completed in self.on_new_decoded_pad()
        # self.conv.link(self.rsmpl)
        # self.rsmpl.link(self.sink)
        # Gst.element_link_many(self.conv, self.rsmpl, self.sink)

        # Reference used in self.on_new_decoded_pad()
        # self.apad = self.conv.get_pad('sink')
        self.apad_audio = self.audiosink.get_static_pad('sink')
        self.apad_video = self.videosink.get_static_pad('sink')

        # And off we go!
        self.pipeline.set_state(Gst.State.PLAYING)

    def on_pad_added(self, element, pad):
        print('on_pad_added:', pad)
        print('target: ' + pad.get_name())
        if pad.get_name() == "src_0":
            if not self.apad_video.is_linked():  # Linkar solo una vez
                pad.link(self.apad_video)
        if pad.get_name() == "src_1":
            if not self.apad_audio.is_linked():  # Linkas solo una vez
                pad.link(self.apad_audio)

    def on_source_setup(self, element, source):
        # Una vez lista, configurar la fuente para que cuando necesite datos
        # ejecute el callback self.on_source_need_data
        print(source)
        source.connect("need-data", self.on_source_need_data)

    def habilitar_lectura_buffer(self):
        self.srcdec.connect("source-setup", self.on_source_setup)
        ##self.bus.connect("need-data", self.on_source_need_data)

    def on_source_need_data(self, source, length):
        # La fuente de datos "source" solicita "length" bytes de datos.
        # Intentar leer del stream
        while self.fd is None:
            # Si no hay un stream listo, pausar esto. OJO! bucle bloqueante,
aunque no deberia
            # ser un problema porque esto lo lleva gstreamer en hilos
separados.
            time.sleep(1)
        try:
            data = self.fd.read(length)
            if not data:
                print("EOS")
                source.emit("end-of-stream")
                return
            # Convertir los bytes Python en bytes aceptables para Gstreammer
            # y empujarlos al appsrc del playbin
            # TODO: Revisar si esto puede mejorarse, tiene que ser "caro".
            buf = Gst.Buffer.new_wrapped(data)
            source.emit("push-buffer", buf)
        except IOError as err:
            print("Error leyendo datos del stream stream: {0}".format(err))
            self.exit("Error leyendo datos del stream stream:
{0}".format(err))
        except AttributeError as err:
            print("Error leyendo datos del stream stream: {0}".format(err))
            self.exit("Error leyendo datos del stream stream:
{0}".format(err))

    def on_eos(self, bus, msg):
        print('on_eos')
        self.pipeline.set_state(Gst.State.NULL)

    def on_tag(self, bus, msg):
        taglist = msg.parse_tag()
        print('on_tag:')
        for key in taglist.keys():
            print('\t%s = %s' % (key, taglist[key]))

    def on_error(self, bus, msg):
        error = msg.parse_error()
        print('on_error:', error[1])

    def exit(self, msg):
        self.stop_y_close_buffer()
        print(msg)
        exit(msg)

    def stop(self):
        # Stop playback and exit mainloop
        self.pipeline.set_state(Gst.State.NULL)

    def stop_y_close_buffer(self):
        # Stop playback and exit mainloop
        self.stop()
        # Close the stream
        if self.fd:
            self.fd.close()
            self.fd = None

    def set_stream(self, stream):
        # Attempt to open the stream
        if self.fd is not None:
            try:
                self.stop_y_close_buffer()
            except Exception as err:
                self.exit("Error cerrando el stream antiguo
{0}".format(err))
        try:
            print("Abriendo Stream")
            self.fd = stream.open()
        except StreamError as err:
            self.exit("Failed to open stream: {0}".format(err))

    def play(self):
        self.pipeline.set_state(Gst.State.PLAYING)
        # self.mainloop.run()

    def pausar_todo(self):
        self.pipeline.set_state(Gst.State.PAUSED)

    def reanudar_todo(self):
        self.pipeline.set_state(Gst.State.PLAYING)



--
Sent from: http://gstreamer-devel.966125.n4.nabble.com/


More information about the gstreamer-devel mailing list