Следующее решение основано на этот принятый, но как-то неполный ответ.
Я обнаружил способ, который не требует «ручного» создания элементов конвейера, а вместо этого сохраняет (в этом сценарий) удобный метод 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
- элементы связи
- создать новый конвейер и добавить в него бункер
- использовать конвейер там, где он есть необходимо.