VivaFidel
VivaFidel

Reputation: 1

Stream video/another camera through RTSP using Gstreamer

I am pretty new to Gstreamer and I am trying to make a pipeline that would take video or another RTSP camera stream and stream that as RTSP. I managed to create this code and I am able to open the stream with VLC using this link: rtsp://localhost:8554/stream, but it shows me only the first frame of the video. What should I change to make it work?

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


class Camera:
    def __init__(self):

        self.camera_url = 'RTSP link/video path'

        self.number_frames = 0
        self.fps = 12
        self.duration = 1 / self.fps * Gst.SECOND
        self.pipe = "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME " \
            " caps=video/x-raw,format=BGR,width=1280,height=720,framerate={}/1 " \
            "! videoconvert ! video/x-raw,format=I420 ! x264enc speed-preset=ultrafast tune=zerolatency " \
            "! rtph264pay config-interval=1 name=pay0 pt=96 " \
            "! udpsink host=127.0.0.1 port=5400 sync=true async=false".format(self.fps)
        self.pipeline = Gst.parse_launch(self.pipe)
        self.loop = None
        appsrc=self.pipeline.get_by_name('source')
        appsrc.connect('need-data', self.start_camera)


    
    def create_rtsp_server(self):
        server = GstRtspServer.RTSPServer.new()
        server.set_property("service", "8554")
        server.attach(None)

        factory = GstRtspServer.RTSPMediaFactory.new()

        pipeline = "( udpsrc port=5400 name=pay0 caps=\"application/x-rtp, media=video, clock-rate=90000, encoding-name=(string)H264, payload=96 \" )"
        factory.set_launch(pipeline)
        factory.set_shared(True)
        server.get_mount_points().add_factory("/stream", factory)
    
    def run(self):
        
        self.pipeline.set_state(Gst.State.READY)
        self.pipeline.set_state(Gst.State.PLAYING)

        self.create_rtsp_server()

        self.loop = GLib.MainLoop()
        self.loop.run()



    def start_camera(
        self, src, lenght
    ):

        cap = cv2.VideoCapture(self.camera_url)  

        try:

            while cap.isOpened():
                ret, frame = cap.read()

                if not ret:
                    break
                
                data = frame.tobytes()
                
                buf = Gst.Buffer.new_allocate(None, len(data), None)
                buf.fill(0, data)
                buf.duration = self.duration
                timestamp = self.number_frames * self.duration
                buf.pts = buf.dts = int(timestamp)
                buf.offset = timestamp
                self.number_frames += 1

                retval = src.emit('push-buffer', buf)
                print('pushed buffer, frame {}, duration {} ns, durations {} s'.format(self.number_frames, self.duration, self.duration / Gst.SECOND))                                                                                  
                if retval != Gst.FlowReturn.OK:
                    print(retval)
                

                return True
                

        finally:
            cap.release()
            cv2.destroyAllWindows()

I tried to search similar Gstreamer pipelines, but couldn`t find anything similar

Upvotes: 0

Views: 193

Answers (1)

Akkshay
Akkshay

Reputation: 140

I am surprised that rtsp factory is able to create stream with the name property set on the udpsrc element. While it could be possible, I am thinking that udpsrc element is stuck between receiving the packets and sending them over rtsp. and because its a single threaded, it could be reaching the race condition.

Generally its a good idea to add queue element after the src element and before heavy processing elements such as x264enc. queue adds buffer for the frames and also simulates the multi threading in GStreamer.

So I would suggest changing both pipeline as follows and give it a try

Source pipeline

self.pipe = "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME " \
        " caps=video/x-raw,format=BGR,width=1280,height=720,framerate={}/1 " \
        "! queue ! videoconvert ! video/x-raw,format=I420 ! queue ! x264enc speed-preset=ultrafast tune=zerolatency " \
        "! rtph264pay config-interval=1 name=pay0 pt=96 " \
        "! queue ! udpsink host=127.0.0.1 port=5400 sync=true async=false".format(self.fps)

Factory pipeline

pipeline = "( udpsrc port=5400 caps=\"application/x-rtp, media=video, clock-rate=90000, encoding-name=(string)H264\" ! queue ! rtph264depay ! h264parse ! rtph264pay name=pay0 pt=96 )"

Upvotes: 0

Related Questions