GStreamer, Tee in RTSP server

Viewed 62

New to Gstreamer, trying to create an RTSP server that consumes a source once per output stream. Code follows. In the factory do_create_element(), if I use the source_pipeline as a return value, I am able to connect to the server and consume the stream. However, as expected, if I connect multiple clients, the server crashes with an error saying the src pad is already connected. My idea was to use the tee element, add a queue after it, and wrap the queue in a pipeline (since I need a GstBin element to give back from the factory). However, this does not work. When I connect a first client to server, nothing happens server-side (as-in, no crashes. The function is called and exits successfully). However, client side, no stream is read, with a 'SDP contains no stream error' (see the console output after the code).

I tried connecting the tee manually to the queue (line left in comment) instead of using the pipeline to do it, but nothing changes. I suspect the queue needs something to consume it, but I'm not sure how/what to use (or if that's the actual issue).

Here is a minimal example:

import gi

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

# noinspection PyUnresolvedReferences
from gi.repository import Gst, GstRtspServer, GObject


def create_source():
    s_src = "videotestsrc ! video/x-raw,rate=30,width=320,height=240,format=I420"
    s_h264 = "x264enc tune=zerolatency"
    pipeline_str = "( {s_src} ! queue max-size-buffers=1000 name=q_enc ! {s_h264} ! rtph264pay name=pay0 pt=96 )".format(
        **locals()
    )
    return Gst.parse_launch(pipeline_str)


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

    source = create_source()
    tee = Gst.ElementFactory.make("tee", "tee")

    source_pipeline = Gst.Pipeline()
    source_pipeline.add(source)
    source_pipeline.add(tee)

    source_pipeline.set_state(Gst.State.PLAYING)

    class Factory(GstRtspServer.RTSPMediaFactoryURI):
        def __init__(self):
            super(Factory, self).__init__()
            self._n = 0

        def do_create_element(self, url):  # -> GstBin (Pipeline)
            print("in [Factory] do_create_element")

            source_pipeline.set_state(Gst.State.PAUSED)

            stream_pipeline = Gst.Pipeline()

            # Create a new queue to buffer the tee's output
            q = Gst.ElementFactory.make("queue")
            stream_pipeline.add(q)

            source_pipeline.add(tee)
            source_pipeline.add(stream_pipeline)
            # tee.link(q)

            stream_pipeline.set_state(Gst.State.PLAYING)
            source_pipeline.set_state(Gst.State.PLAYING)

            return stream_pipeline

    factory = Factory()
    factory.set_shared(True)

    server = GstRtspServer.RTSPServer()
    server.get_mount_points().add_factory("/endpoint", factory)
    server.attach(None)

    loop = GObject.MainLoop()
    loop.run()


if __name__ == "__main__":
    _main()

Here is the shell output when connecting:

> gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/endpoint ! rtph264depay ! h264parse ! mp4mux ! filesink location=file.mp4

Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Progress: (open) Opening Stream
Pipeline is PREROLLED ...
Prerolled, waiting for progress to finish...
Progress: (connect) Connecting to rtsp://127.0.0.1:8554/endpoint
Progress: (open) Retrieving server options
Progress: (open) Retrieving media info
ERROR: from element /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0: Could not get/set settings from/on resource.
Additional debug info:
../gst/rtsp/gstrtspsrc.c(7637): gst_rtspsrc_setup_streams_start (): /GstPipeline:pipeline0/GstRTSPSrc:rtspsrc0:
SDP contains no streams
ERROR: pipeline doesn't want to preroll.
Setting pipeline to NULL ...
Freeing pipeline ...

Thanks ahead!

0 Answers
Related