Real-Time Camera UDP Stream VLC Player Problem

Hello,

I want to read a frame with opencv and stream this frame with UDP(H264). I want to read the frame first because I will be processing the image later. My code;

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

class UDPStreamer:
    def __init__(self):
        Gst.init(None)
        
        self.pipeline = Gst.parse_launch((
            "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME "
            "caps=video/x-raw,format=I420,width=1280,height=1024,framerate=50/1 ! "
            "videoconvert ! x264enc tune=zerolatency bitrate=5000 speed-preset=ultrafast ! "
            "rtph264pay ! udpsink host=192.168.1.48 port=5000"
        ))

        self.source = self.pipeline.get_by_name("source")
        self.frame_number = 0

    def start(self):
        self.pipeline.set_state(Gst.State.PLAYING)
        print("UDP streaming to udp://192.168.1.48:5000")

    def stop(self):
        self.pipeline.set_state(Gst.State.NULL)


def main():
    cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)
    cap.set(cv2.CAP_PROP_FPS, 50)
    cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"YUYV"))

    streamer = UDPStreamer()
    streamer.start()

    try:
        while True:
            ret, frame = cap.read()
            if not ret:
                print("Error: Unable to read frame from the camera.")
                break

            #Send frame to GStreamer appsrc
            if streamer.source:
                frame_i420 = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420)
                data = frame_i420.tobytes()
                buf = Gst.Buffer.new_allocate(None, len(data), None)
                buf.fill(0, data)

                buf.pts = Gst.util_uint64_scale(streamer.frame_number, Gst.SECOND, 50)
                buf.duration = Gst.util_uint64_scale(1, Gst.SECOND, 50)
                streamer.frame_number += 1

                retval = streamer.source.emit("push-buffer", buf)
                if retval != Gst.FlowReturn.OK:
                    print("Error: Unable to push buffer to the pipeline.")

            cv2.imshow("Camera Feed", frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

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

if __name__ == "__main__":
    main()


I can’t watch frames with VLC Player on the host computer. My host computer’s IP Address: 192.168.1.48. I tried udp://192.168.1.48:5000 and udp://@:5000 but I can’t get any image. Then I created a .slp file and added the following lines to it;

v=0
c=IN IP4 192.168.1.48
m=video 5000 RTP/AVP 96
a=rtpmap:96 H264/90000

When I click “Open File” in VLC Player, select the “.slp” file, and press play, I can get images, but there is a lot of lag. Instead of “Open File” in VLC, I want to select “Open Network Stream” and enter the IP address to watch the images. What could I be doing wrong?

The features of my camera are as follows;

In addition to all this, the RTSP code below works without any problems, but I could not run UDP.

import cv2
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')

from gi.repository import Gst, GstRtspServer, GLib


class RTSPServer:
    def __init__(self):
        Gst.init(None)
        Gst.debug_set_default_threshold(3)
        
        self.server = GstRtspServer.RTSPServer()
        self.factory = GstRtspServer.RTSPMediaFactory()
        self.factory.set_launch((
            "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME "
            "caps=video/x-raw,format=I420,width=1280,height=1024,framerate=50/1 ! "
            "videoconvert ! x264enc tune=zerolatency bitrate=5000 speed-preset=ultrafast ! "
            "rtph264pay name=pay0 pt=96"
        ))
        self.factory.set_shared(True)
        self.server.get_mount_points().add_factory("/test", self.factory)
        self.server.set_service("8554")
        self.source = None
        self.frame_number = 0

    def start(self):
        self.server.attach(None)
        print("RTSP server running at rtsp://<your-ip>:8554/test")

    def configure_pipeline(self, factory, media):
        self.source = media.get_element().get_child_by_name("source")


def main():
    cap = cv2.VideoCapture(0, cv2.CAP_V4L2)
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1024)
    cap.set(cv2.CAP_PROP_FPS, 50)
    cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"YUYV"))

    server = RTSPServer()
    server.factory.connect("media-configure", server.configure_pipeline)
    server.start()

    while True:
        ret, frame = cap.read()
        if not ret:
            print("Error: Unable to read frame from the camera.")
            break

        #Send frames to GStreamer appsrc
        if server.source:
            frame_i420 = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420)
            data = frame_i420.tobytes()
            buf = Gst.Buffer.new_allocate(None, len(data), None)
            buf.fill(0, data)

            buf.pts = Gst.util_uint64_scale(server.frame_number, Gst.SECOND, 50)
            buf.duration = Gst.util_uint64_scale(1, Gst.SECOND, 50)
            server.frame_number += 1

            server.source.emit("push-buffer", buf)

        cv2.imshow("Camera Feed", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

I can open the RTSP stream from VLC Player by typing the address “rtsp://my-ip:8554/test”. I want the same for UDP. Can you help me?

Hi,
There are some manual steps to set up VLC player to receive and decode UDP. A user has shared experience in the post:
Gstreamer TCPserversink 2-3 seconds latency - #13 by Bazziil

Please take a look and give it a try.

Hi DaneLLL,

Thank you for your response. I looked at the link you sent, but that solution doesn’t use VLC either. I want to watch the video with VLC Player by just entering the stream address. VLC connects to the address and the time in the VLC progresses. Sometimes random sounds come but there is no image.

My last pipeline;

        self.pipeline = Gst.parse_launch((
            "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME "
            "caps=video/x-raw,format=I420,width=1280,height=1024,framerate=50/1 !"
            "videoconvert ! timeoverlay valignment=2 halignment=2 ! x264enc tune=zerolatency bitrate=500000 speed-preset=ultrafast ! "
             "rtph264pay config-interval=1 pt=96 ! queue ! udpsink host=192.168.1.48 port=5000"
        ))

Hi,
Please try

  1. On Jetson platform, run the command:
$ gst-launch-1.0 videotestsrc is-live=1 ! video/x-raw,width=1280,height=720,format=I420 ! timeoverlay valignment=4 halignment=1 ! nvvidconv ! 'video/x-raw(memory:NVMM),width=1280,height=720' ! nvv4l2h264enc insert-sps-pps=1 idrinterval=15 ! h264parse ! mpegtsmux ! udpsink host=10.23.8.73 port=5003 sync=0

Where 10.23.8.73 is IP address of the PC receiving UDP stream through VLC player.

  1. On the PC, open network stream udp://@0.0.0.0:5003 via VLC

Hi DaneLLL,

When I added the pipeline below to my code, I was able to UDP stream without any problems. I can also watch the stream with VLC Player using udp://@:5003. Thank you for your support.

        self.pipeline = Gst.parse_launch((
            "appsrc name=source is-live=true block=true format=GST_FORMAT_TIME "
            "caps=video/x-raw,width=1280,height=1024,framerate=50/1,format=I420,pixel-aspect-ratio=1/1 ! "
            "nvvidconv ! nvv4l2h264enc insert-sps-pps=1 idrinterval=15 ! h264parse ! "
            "mpegtsmux ! udpsink host=192.168.1.48 port=5003 sync=false"
        ))

I have a small problem right now. Normally, when I just show the camera on the screen with “cv2.imshow(“Camera Feed”, frame)” without UDP stream, I can watch the camera for hours without any problems. But, when I start the UDP stream, the camera sometimes times out and I have to restart the code. I couldn’t understand why. I’m trying to solve it.