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.