I'm trying to generate a RTSP stream of opencv frames from python. I've used Gstreamer for that and was able to stream frames and read them with VLC in another PC.
My problem is that my code uses the default port 8554 (i.e the stream is in rtsp://hostIp:8554/test
), while I want to stream to port 554.
I've tried many additions to the launch_string
, for example '! gdppay ! tcpserversink host=serverIp port=554'
. However the app crashes with a gstreamer error or just nothing is streamed.
Is that even possible?
my code (took most of it from here):
import cv2
import gi
import subprocess
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GObject
class SensorFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self, fps, img_shape, cols, properties={}):
super(SensorFactory, self).__init__(**properties)
self.height = int(img_shape[0])
self.width = int(img_shape[1] * cols)
self.number_frames = 0
fps = int(fps)
self.cap = None
self.duration = 1.0 / fps * Gst.SECOND # duration of a frame in nanoseconds
caps_str = 'caps=video/x-raw,format=BGR,width={},height={},framerate={}/1 '.format(self.width,
self.height,
fps)
self.launch_string = 'appsrc name=source is-live=true block=true format=GST_FORMAT_TIME ' + caps_str + \
'! videoconvert ' + \
'! video/x-raw,format=I420 ' + \
'! x264enc tune=zerolatency speed-preset=fast ' + \
'! rtph264pay config-interval=1 pt=96 name=pay0 ' + \
'' # <<<=== add more configs here
print(self.launch_string)
def set_cap(self, cap):
self.cap = cap
def on_need_data(self, src, length):
if self.cap.isOpened():
ret, frame = self.cap.read()
if ret:
if frame.shape[:2] != (self.height, self.width):
frame = cv2.resize(frame, (self.width, self.height))
data = frame.tostring()
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 = self.appsrc.emit('push-buffer', buf)
print('[INFO]: frame {}'.format(self.number_frames))
if retval != Gst.FlowReturn.OK:
print("[INFO]: retval not OK: {}".format(retval))
def do_create_element(self, url):
return Gst.parse_launch(self.launch_string)
def do_configure(self, rtsp_media):
self.number_frames = 0
self.appsrc = rtsp_media.get_element().get_child_by_name('source')
self.appsrc.connect('need-data', self.on_need_data)
class GstServer(GstRtspServer.RTSPServer):
def __init__(self, fps, img_shape, cols, properties={}):
GObject.threads_init()
Gst.init(None)
super(GstServer, self).__init__(**properties)
self.factory = SensorFactory(fps=fps, img_shape=img_shape, cols=cols)
self.factory.set_shared(True)
self.get_mount_points().add_factory('/test', self.factory)
self.attach(None)
self.loop = None
def run(self):
self.loop = GObject.MainLoop()
self.loop.run()
Thank you.