Где сообщения журнала шины Gstreamer? - PullRequest
1 голос
/ 05 мая 2020

Я пытаюсь передать .mp4 на сервер RTSP, используя Gstreamer in python

import sys
import gi

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

loop = GLib.MainLoop()
Gst.init(None)
file_path = "test.mp4"
class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self):
        GstRtspServer.RTSPMediaFactory.__init__(self)

    def do_create_element(self, url):
        src_demux = f"filesrc location={file_path} ! qtdemux name=demux"
        h264_transcode = "demux.video_0"
        pipeline = "{0} {1} ! queue ! rtph264pay name=pay0 config-interval=1 pt=96".format(src_demux, h264_transcode)
        print ("Element created: " + pipeline)

        self._pipeline = Gst.parse_launch(pipeline)
        def bus_handler(bus, message):
            print(message)
        self.bus = self._pipeline.get_bus()
        self.bus.connect('message', bus_handler)
        self.bus.add_signal_watch_full(1)
        return self._pipeline

class GstreamerRtspServer():
    def __init__(self):
        self.rtspServer = GstRtspServer.RTSPServer()
        factory = TestRtspMediaFactory()
        factory.set_shared(True)
        mountPoints = self.rtspServer.get_mount_points()
        self.address = '127.0.0.1' #my RPi's local IP
        self.port = '8553'
        self.rtspServer.set_address(self.address)
        self.rtspServer.set_service(self.port)
        urlstr = "/user=&password=.sdp"
        url = GstRtsp.RTSPUrl.parse(urlstr)
        mountPoints.add_factory(urlstr, factory)

        self.rtspServer.attach(None)

if __name__ == '__main__':
    s = GstreamerRtspServer()
    loop.run()

Однако я пытаюсь понять, как используйте шину Gstreamer для регистрации таких сообщений, как eos , или ошибок и предупреждений, но я их не вижу, даже когда я отправляю события eos, и потоковая передача фактически останавливается

s.rtspServer._pipeline._end_stream_event.set()
s.rtspServer._pipeline.send_event(Gst.Event.new_eos())

Правильно ли я его использую? Если нет, что я могу исправить для правильного протоколирования сообщений шины?

1 Ответ

0 голосов
/ 15 мая 2020

Следующее решение основано на этот принятый, но как-то неполный ответ.

Я обнаружил способ, который не требует «ручного» создания элементов конвейера, а вместо этого сохраняет (в этом сценарий) удобный метод Gst.parse_launch(pipelineCmd) и расширяет Gst.Bin, чтобы включить отладку сообщений.

Вот полный пример исходного кода (см. закомментированные строки для некоторых объяснений):

#!/usr/bin/env python

import sys
import gi

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

Gst.init(None)
loop = GLib.MainLoop()

# extended Gst.Bin that overrides do_handle_message and adds debugging
class ExtendedBin(Gst.Bin):
    def do_handle_message(self,message):
        if message.type == Gst.MessageType.ERROR:
            error, debug = message.parse_error()
            print("ERROR:", message.src.get_name(), ":", error.message)
            if debug:
                print ("Debug info: " + debug)
        elif message.type == Gst.MessageType.EOS:
            print ("End of stream")
        elif message.type == Gst.MessageType.STATE_CHANGED:
            oldState, newState, pendingState = message.parse_state_changed()
            print ("State changed -> old:{}, new:{}, pending:{}".format(oldState,newState,pendingState))
        else :
            print("Some other message type: " + str(message.type))

        #call base handler to enable message propagation
        Gst.Bin.do_handle_message(self,message)

class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):

    def __init__(self):
        GstRtspServer.RTSPMediaFactory.__init__(self)

    def do_create_element(self, url):
        #set mp4 file path to filesrc's location property
        src_demux = "filesrc location=/path/to/dir/test.mp4 ! qtdemux name=demux"
        h264_transcode = "demux.video_0"
        #uncomment following line if video transcoding is necessary
        #h264_transcode = "demux.video_0 ! decodebin ! queue ! x264enc"
        pipelineCmd = "{0} {1} ! queue ! rtph264pay name=pay0 config-interval=1 pt=96".format(src_demux, h264_transcode)

        self.pipeline = Gst.parse_launch(pipelineCmd)
        print ("Pipeline created: " + pipelineCmd)

        # creates extended Gst.Bin with message debugging enabled
        extendedBin = ExtendedBin("extendedBin")

        # Gst.pipeline inherits Gst.Bin and Gst.Element so following is possible
        extendedBin.add(self.pipeline)

        # creates new Pipeline and adds extended Bin to it
        self.extendedPipeline = Gst.Pipeline.new("extendedPipeline")
        self.extendedPipeline.add(extendedBin)

        return self.extendedPipeline

class GstreamerRtspServer(GstRtspServer.RTSPServer):
    def __init__(self):
        self.rtspServer = GstRtspServer.RTSPServer()
        self.factory = TestRtspMediaFactory()
        self.factory.set_shared(True)
        mountPoints = self.rtspServer.get_mount_points()
        mountPoints.add_factory("/stream", self.factory)
        self.rtspServer.attach(None)
        print ("RTSP server is ready")

if __name__ == '__main__':
    s = GstreamerRtspServer()
    loop.run()

Обратите внимание что Gst.Pipeline на самом деле наследует / расширяет Gst.Bin (и Gst.Element), поэтому возможно (как бы странно это ни звучало) добавить конвейер в bin .

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

В более сложном сценарии ios, если синтаксис командной строки не применим, решение будет следующим:

  • создать ExtendedBin,
  • «вручную» создать элементы с помощью метода Gst.ElementFactory.make ( и установить необходимые свойства)
  • добавить созданные элементы в ExtendedBean
  • элементы связи
  • создать новый конвейер и добавить в него бункер
  • использовать конвейер там, где он есть необходимо.
...