Reputation: 1
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
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