RTSP video feed and recording video with Gstreamer and Nvidia AGX Orin

318 Views Asked by At

I am trying to setup a gstreamer pipeline via gstreamer python bindings. The pipeline should use the camera to record footage to files (and roll them), it should also support clients connecting to the device to view them live with RTSP. While the pipeline writes to the file, it only displays 1 to 2 seconds before the stream freezes. I've tried variety of changes to the script but I'm not able to get it to work beyond few frames. Here is my code

import gi
import os
import signal
import sys

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

Gst.init(None)

def signal_handler(sig, frame):
    print("Caught signal, cleaning up and stopping the main loop.")
    mainloop.quit()

def on_new_sample(appsink, appsrc):
    sample = appsink.emit("pull-sample")
    if sample:
        appsrc.emit("push-sample", sample)
    return Gst.FlowReturn.OK

BITRATE = 2000000

main_pipeline_str = f"""
v4l2src device=/dev/video7 do-timestamp=true ! video/x-raw, format=YUY2, width=1920, height=1080, framerate=30/1 ! nvvidconv ! video/x-raw(memory:NVMM) ! nvv4l2h264enc bitrate={BITRATE} preset-level=4 insert-sps-pps=true ! tee name=t
t. ! h264parse ! splitmuxsink location=/external/video_%05d.mkv max-size-time=100000000000 max-files=10
t. ! h264parse ! appsink name=appsink emit-signals=true sync=false
"""

main_pipeline = Gst.parse_launch(main_pipeline_str)
main_pipeline.set_state(Gst.State.PLAYING)
appsink = main_pipeline.get_by_name("appsink")

def error_cb(bus, msg):
    err, debug_info = msg.parse_error()
    print(f"Error: {err.message}")

bus = main_pipeline.get_bus()
bus.add_signal_watch()
bus.connect("message::error", error_cb)

class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
    def __init__(self, appsink):
        GstRtspServer.RTSPMediaFactory.__init__(self)
        self.appsink = appsink

    def do_create_element(self, url):
        print("New client has entered!")
        pipeline_str = "appsrc name=appsrc is-live=true do-timestamp=true ! h264parse ! rtph264pay config-interval=1 pt=96 name=pay0"
        pipeline = Gst.parse_launch(pipeline_str)
        appsrc = pipeline.get_by_name("appsrc")
        self.appsink.connect("new-sample", on_new_sample, appsrc)
        return pipeline

rtsp_server = GstRtspServer.RTSPServer()
rtsp_server.set_service("8557")
factory = TestRtspMediaFactory(appsink)
factory.set_shared(True)
mount_points = rtsp_server.get_mount_points()
mount_points.add_factory("/camera", factory)
rtsp_server.attach(None)

signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)

mainloop = GLib.MainLoop()
mainloop.run()

1

There are 1 best solutions below

0
On

This might not be the optimal solution, but the following code works (tested on AGX Orin with a ZED camera):

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

Gst.init(None)
mainloop = GLib.MainLoop()
pipeline = Gst.parse_launch ('v4l2src device=/dev/video0 do-timestamp=true ! video/x-raw, format=YUY2, width=1344, height=376, framerate=30/1 ! nvvidconv ! video/x-raw(memory:NVMM) ! nvv4l2h264enc preset-level=4 insert-sps-pps=1 idrinterval=30 insert-vui=1 ! tee name=t ! queue ! h264parse ! matroskamux ! multifilesink location=/external/video_%05d.mkv next-file=5 max-file-duration=10000000000 max-files=10     t. ! queue ! h264parse ! video/x-h264,stream-format=byte-stream ! queue ! shmsink socket-path=tmpSock')
server = GstRtspServer.RTSPServer()
mounts = server.get_mount_points()
factory = GstRtspServer.RTSPMediaFactory()
factory.set_launch('( shmsrc socket-path=tmpSock is-live=1 do-timestamp=1 ! video/x-h264,stream-format=byte-stream ! queue ! h264parse ! rtph264pay name=pay0 )')
mounts.add_factory("/test", factory)
server.attach(None)
print ("stream ready at rtsp://127.0.0.1:8554/test")
pipeline.set_state(Gst.State.PLAYING)
mainloop.run()

The bad thing with shmsink and shmsrc is that shmsink creates a named socket, but it will not be deleted if the pipelines are not cleanly closed, such as stopping the server with Ctrl-C. So I'd suggest to use the following command for running the server, that will ensure deletion of the socket:

bash -c 'sh -c "trap exit\ 0 INT; python3 ../rtspServerShm.py; "; rm tmpSock*'