pythongstreamernvidiagobject

convert gstreamer pipeline to python code


Im trying to convert gstreamer pipeline to python code using gi library.

This is the pipeline which is running successfully in terminal:

gst-launch-1.0 rtspsrc location="rtsp://admin:123456@192.168.0.150:554/H264?ch=1&subtype=0&proto=Onvif" latency=300 ! rtph264depay ! h264parse ! nvv4l2decoder drop-frame-interval=1 ! nvvideoconvert ! video/x-raw,width=1920,height=1080,formate=I420 ! queue !  nveglglessink window-x=0 window-y=0 window-width=1080 window-height=720

but while running the same pipeline using python code, there is no output window displaying rtsp stream and also no error on the terminal. The terminal simply stuck until i press ctrl+c.

This is the code that im using to run the gstreamer command:

import gi

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

from gi.repository import Gst, GObject


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

    pipeline = Gst.Pipeline()

    source = Gst.ElementFactory.make("rtspsrc", "video-source")
    source.set_property("location", device)
    source.set_property("latency", 300)
    pipeline.add(source)

    depay = Gst.ElementFactory.make("rtph264depay", "depay")
    pipeline.add(depay)
    source.link(depay)

    parse = Gst.ElementFactory.make("h264parse", "parse")
    pipeline.add(parse)
    depay.link(parse)

    decoder = Gst.ElementFactory.make("nvv4l2decoder", "decoder")
    decoder.set_property("drop-frame-interval", 2)
    pipeline.add(decoder)
    parse.link(decoder)

    convert = Gst.ElementFactory.make("nvvideoconvert", "convert")
    pipeline.add(convert)
    decoder.link(convert)

    caps = Gst.Caps.from_string("video/x-raw,width=1920,height=1080,formate=I420")
    filter = Gst.ElementFactory.make("capsfilter", "filter")
    filter.set_property("caps", caps)
    pipeline.add(filter)
    convert.link(filter)

    queue = Gst.ElementFactory.make("queue", "queue")
    pipeline.add(queue)
    filter.link(queue)

    sink = Gst.ElementFactory.make("nveglglessink", "video-sink")
    sink.set_property("window-x", 0)
    sink.set_property("window-y", 0)
    sink.set_property("window-width", 1280)
    sink.set_property("window-height", 720)

    pipeline.add(sink)

    queue.link(sink)

    loop = GObject.MainLoop()

    pipeline.set_state(Gst.State.PLAYING)

    try:
        loop.run()
    except:
        pass

    pipeline.set_state(Gst.State.NULL)

if __name__ == "__main__":
    main("rtsp://admin:123456@192.168.0.150:554/H264?ch=1&subtype=0&proto=Onvif")

Does anyone know what is the mistake? Thank you!


Solution

  • The reason it doesn't work is because rtspsrc's source pad is a so-called "Sometimes pad". The link here explains it quite well, but basically you cannot know upfront how many pads will become available on the rtspsrc, since this depends on the SDP provided by the RTSP server.

    As such, you should listen to the "pad-added" signal of the rtspsrc, where you can link the rest of your pipeline to the source pad that just showed up in the callback.

    So summarised:

    def main(device):
        GObject.threads_init()
        Gst.init(None)
    
        pipeline = Gst.Pipeline()
        source = Gst.ElementFactory.make("rtspsrc", "video-source")
        source.set_property("location", device)
        source.set_property("latency", 300)
        source.connect("pad-added", on_rtspsrc_pad_added)
        pipeline.add(source)
    
        # We will add/link the rest of the pipeline later
        loop = GObject.MainLoop()
    
        pipeline.set_state(Gst.State.PLAYING)
    
        try:
            loop.run()
        except:
            pass
    
        pipeline.set_state(Gst.State.NULL)
    
    def on_rtspsrc_pad_added(rtspsrc, pad, *user_data):
        # Create the rest of your pipeline here and link it 
        depay = Gst.ElementFactory.make("rtph264depay", "depay")
        pipeline.add(depay)
        rtspsrc.link(depay)
    
        # and so on ....