Python Gstreamer Playbin запись и воспроизведение - PullRequest
0 голосов
/ 01 октября 2018

Я использую GStreammer Python 3 bind для создания приложения, которое записывает и дополнительно воспроизводит на экране во время записи потокового видео в Интернете.Я использую Streamlink, чтобы получить m3u8 и / или поток.Пользователи могут добавлять странные источники, поэтому моей первоначальной идеей было использование чего-то, что могло бы определять формат источника и автоматически его декодировать.Для этого я обнаружил, что наилучшим способом было использовать Streamlink в сочетании с Плагином GStreammer .

Этот код из документации Streamlink позволяет игратьлюбой поток m3u8:

#!/usr/bin/env python
from __future__ import print_function

import sys

import gi

gi.require_version("Gst", "1.0")

from gi.repository import GObject as gobject, Gst as gst
from streamlink import Streamlink, StreamError, PluginError, NoPluginError


def exit(msg):
    print(msg, file=sys.stderr)
    sys.exit()


class StreamlinkPlayer(object):
    def __init__(self):
        self.fd = None
        self.mainloop = gobject.MainLoop()

        # This creates a playbin pipeline and using the appsrc source
        # we can feed it our stream data
        self.pipeline = gst.ElementFactory.make("playbin", None)
        self.pipeline.set_property("uri", "appsrc://")

        # When the playbin creates the appsrc source it will call
        # this callback and allow us to configure it
        self.pipeline.connect("source-setup", self.on_source_setup)

        # Creates a bus and set callbacks to receive errors
        self.bus = self.pipeline.get_bus()
        self.bus.add_signal_watch()
        self.bus.connect("message::eos", self.on_eos)
        self.bus.connect("message::error", self.on_error)

    def exit(self, msg):
        self.stop()
        exit(msg)

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

        # Close the stream
        if self.fd:
            self.fd.close()

    def play(self, stream):
        # Attempt to open the stream
        try:
            self.fd = stream.open()
        except StreamError as err:
            self.exit("Failed to open stream: {0}".format(err))

        print(vars(self.pipeline))

        # Start playback
        self.pipeline.set_state(gst.State.PLAYING)



        self.mainloop.run()

    def on_source_setup(self, element, source):
        # When this callback is called the appsrc expects
        # us to feed it more data
        source.connect("need-data", self.on_source_need_data)

    def on_source_need_data(self, source, length):
        # Attempt to read data from the stream
        try:
            data = self.fd.read(length)
        except IOError as err:
            self.exit("Failed to read data from stream: {0}".format(err))

        # If data is empty it's the end of stream
        if not data:
            source.emit("end-of-stream")
            return

        # Convert the Python bytes into a GStreamer Buffer
        # and then push it to the appsrc
        buf = gst.Buffer.new_wrapped(data)
        source.emit("push-buffer", buf)

    def on_eos(self, bus, msg):
        # Stop playback on end of stream
        self.stop()

    def on_error(self, bus, msg):
        # Print error message and exit on error
        error = msg.parse_error()[1]
        self.exit(error)


def main():
    if len(sys.argv) < 3:
        exit("Usage: {0} <url> <quality>".format(sys.argv[0]))

    # Initialize and check GStreamer version
    gi.require_version("Gst", "1.0")
    gobject.threads_init()
    gst.init(None)

    # Collect arguments
    url = sys.argv[1]
    quality = sys.argv[2]

    # Create the Streamlink session
    streamlink = Streamlink()

    # Enable logging
    streamlink.set_loglevel("info")
    streamlink.set_logoutput(sys.stdout)

    # Attempt to fetch streams
    try:
        streams = streamlink.streams(url)
    except NoPluginError:
        exit("Streamlink is unable to handle the URL '{0}'".format(url))
    except PluginError as err:
        exit("Plugin error: {0}".format(err))

    if not streams:
        exit("No streams found on URL '{0}'".format(url))

    # Look for specified stream
    if quality not in streams:
        exit("Unable to find '{0}' stream on URL '{1}'".format(quality, url))

    # We found the stream
    stream = streams[quality]

    # Create the player and start playback
    player = StreamlinkPlayer()

    # Blocks until playback is done
    player.play(stream)


if __name__ == "__main__":
    main()

Использование:

TestStreamlink.py https://www.mitele.es/directo/divinity best

Вы можете, например, изменить URL-адрес mitele на один.

Я проверил gst документацию (справочник по GStreammer API) и я думаю, что для сохранения файлов лучше всего использовать «мусорную корзину», однако я понятия не имею, как сделать тройник на выходе плейбина для разделения между записью и воспроизведением,Я не знаю, как делать только запись.

Я новичок в Python, но я должен делать это на этом языке, так что это довольно удобная вещь для меня.Насколько я знаю, путь состоит в том, чтобы создать «тройник» для клонирования загруженного потока в два разных канала, один для обычного выхода графического интерфейса, подключенного к стандартному пэду (это дополнительный поток воспроизведения, который будет использоваться толькодля отладки), а другой подключен к «bin», например, filesink.Тогда включение и отключение live play - это просто удаление / добавление пэда.Я ознакомился с этим руководством , однако, как я уже сказал, я новичок в Python и GST, поэтому я не знаком с ним: S

Кстати, возможностьзапись намного важнее, чем живое воспроизведение, поэтому любые идеи о том, как интегрировать playbin и fileink (для записи в mp4, скажем, в случайном аудио / видео) формате, были бы достаточны.Кстати, я должен записывать аудио / видео (mp4), но также обрабатывать аудио в другом процессе, поэтому моя идея состояла в том, чтобы одновременно записывать mp4, содержащий видео + аудио И mp3, содержащий ТОЛЬКО аудио.mp3 может быть отправлено в другое приложение с использованием ОЗУ ИЛИ сохранено на диске для последующего чтения.

...