Обработка ошибок с привязками Python gst-rtsp-сервера - PullRequest
0 голосов
/ 17 января 2019

У меня есть простая программа на Python, создающая поток RTSP с использованием gst-rtsp-server. Это работает, но как есть, нет обработки ошибок. Если в конвейере есть опечатка или есть какая-то проблема с подключением к источнику видео, я не вижу трассировки стека или какой-либо регистрации. Где бы я подключил код для решения подобных проблем?

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

В случае, если это полезно, вот мой код, который у меня есть сейчас:

from threading import Thread
from time import sleep
import signal

import gi
gi.require_version("Gst", "1.0")
gi.require_version("GstRtsp", "1.0")
gi.require_version("GstRtspServer", "1.0")
from gi.repository import GLib, GObject, Gst, GstRtsp, GstRtspServer

PIPELINE = (
    "( videotestsrc ! vp8enc ! rtpvp8pay name=pay0 pt=96 )")


def main():
    GObject.threads_init()
    Gst.init(None)

    server = GstRtspServer.RTSPServer.new()
    server.props.service = "3000"

    server.attach(None)

    loop = GLib.MainLoop.new(None, False)

    def on_sigint(_sig, _frame):
        print("Got a SIGINT, closing...")
        loop.quit()
    signal.signal(signal.SIGINT, on_sigint)

    def run_main_loop():
        loop.run()

    main_loop_thread = Thread(target=run_main_loop)

    main_loop_thread.start()

    media_factory = GstRtspServer.RTSPMediaFactory.new()
    media_factory.set_launch(PIPELINE)
    media_factory.set_shared(True)
    server.get_mount_points().add_factory("/test", media_factory)
    print("Stream ready at rtsp://127.0.0.1:3000/test")


    while loop.is_running():
        sleep(0.1)


if __name__ == "__main__":
    main()

1 Ответ

0 голосов
/ 21 января 2019

После еще нескольких экспериментов с GStreamer и библиотекой RTSP-сервера ситуация с обработкой ошибок усложняется.

Нормальный путь

Канонический способ увидеть ошибки в конвейере GStreamer - добавить наблюдателя в шину конвейера и прослушивать сообщения об ошибках.

def watcher(bus, message, *user_data);
    if message.type == Gst.MessageType.ERROR:
        error, message = message.parse_error()
        # TODO: Do something with the error

my_pipeline.get_bus().add_watch(
    GLib.PRIORITY_DEFAULT,
    watcher,
    None)

Однако вы не можете сделать это с конвейерами, которые вы предоставляете GstRtspServer. Это связано с тем, что GstRtspServer ожидает установки собственного наблюдателя на шину конвейера, и только один наблюдатель может быть подключен к шине одновременно. Это особенно прискорбно, потому что это мешает нам слушать любые события в конвейере, а не только ошибки.

Мой обходной путь

Мы можем разделить конвейер на две части: одну, которая отвечает за подверженный ошибкам процесс соединения с исходным и декодирующим кадрами, и другую, которая отвечает за кодирование результирующих кадров и загрузку их для GstRtspServer. Затем мы можем использовать плагин intervideo для связи между ними.

Например, допустим, вы пытаетесь выполнить потоковую передачу из файла в формате VP8. Наш первый конвейер, отвечающий за чтение и декодирование кадров, будет выглядеть так:

filesrc location="{filepath}" ! decodebin ! intervideosink channel="file-channel"

... и наш второй конвейер, отвечающий за кодирование и загрузку кадра, будет выглядеть так:

intervideosrc channel="file-channel" ! videoconvert ! vp8enc deadline=1 ! rtpvp8pay name=pay0 pt=96

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

...