Reputation: 51
I am trying to setup a rtsp-server to re-stream an rtsp-stream of an IP camera after editing with OpenCV. Capturing the rtsp-stream and editing the frames work, but I cannot get the rtsp-server working. I receive the following error message:
[ WARN:0] global /home/pi/opencv/opencv-4.1.1/modules/videoio/src/cap_gstreamer.cpp (896) open OpenCV | GStreamer warning: unable to query duration of stream
[ WARN:0] global /home/pi/opencv/opencv-4.1.1/modules/videoio/src/cap_gstreamer.cpp (933) open OpenCV | GStreamer warning: Cannot query video position: status=1, value=0, duration=-1
[ WARN:0] global /home/pi/opencv/opencv-4.1.1/modules/videoio/src/cap_gstreamer.cpp (1757) handleMessage OpenCV | GStreamer warning: Embedded video playback halted; module appsrc0 reported: Internal data stream error.
[ WARN:0] global /home/pi/opencv/opencv-4.1.1/modules/videoio/src/cap_gstreamer.cpp (1663) writeFrame OpenCV | GStreamer warning: Error pushing buffer to GStreamer pipeline
I tried two different pipes as you can see in the code below, but both receive the same error messages.
I try to access the rtsp-stream in VLC player by rtsp://192.168.y.y:8554/test, but the connection cannot be established.
Where is my mistake? Any suggestions for debugging? I have no experience with GStreamer.
I am using Python: 3.7.3, OpenCV: 4.1.1, GStreamer: 1.14.4.0
import time
import cv2
import sys
print("Python: {}".format(sys.version))
print("OpenCV: {}".format(cv2.__version__))
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
gi.require_version('GstApp', '1.0')
from gi.repository import Gst, GLib, GstApp, GstRtspServer, GObject
print("Gst: {}.{}.{}.{}".format(*Gst.version()))
_ = GstApp
__ = GstRtspServer
Gst.init()
camSet_h265 = 'rtspsrc location=rtsp://192.168.x.x:8554/12 latency=0 buffer-mode=auto ! queue ! rtph265depay ! h265parse ! avdec_h265 ! videoconvert ! video/x-raw, format=BGR ! appsink drop=1'
camSet = camSet_h265
pipe_out = 'appsrc ! video/x-raw, format=BGR ! queue ! videoconvert ! video/x-raw, format=BGRx ! videoconvert ! x264enc speed-preset=veryfast tune=zerolatency bitrate=800 ! h264parse ! rtph264pay name=pay0 pt=96 config-interval=1'
# pipe_out = ' appsrc ! videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast ! h264parse ! rtph264pay name=pay0 pt=96 config-interval=1'
cam= cv2.VideoCapture(camSet, cv2.CAP_GSTREAMER)
time.sleep(2)
ret, frame = cam.read()
frame_num = int(cam.get(cv2.CAP_PROP_FRAME_COUNT))
frame_width = int(cam.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(cam.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_fps = int(cam.get(cv2.CAP_PROP_FPS))
fourcc_fmt = cv2.VideoWriter_fourcc(*'X264')
out = cv2.VideoWriter(pipe_out, fourcc=fourcc_fmt, apiPreference=cv2.CAP_GSTREAMER, fps=frame_fps, frameSize=(frame_width, frame_height), isColor=True)
time.sleep(2)
while 1:
ret, frame = cam.read()
cv2.rectangle(frame,(20,100),(200,300),(0,255,0),8)
# cv2.imshow('nanoCam',frame)
out.write(frame)
if cv2.waitKey(1)==ord('q'):
break
cam.release()
cv2.destroyAllWindows()
Upvotes: 3
Views: 6211
Reputation: 1626
Main cause is that your writer pipeline has no sink. From opencv you may better use RTP streaming adding udpsink (that is appended by test-launch after pay0):
# Multicast to LAN (better avoid with wifi)
pipe_out = 'appsrc ! video/x-raw, format=BGR ! queue ! videoconvert ! video/x-raw, format=BGRx ! videoconvert ! x264enc speed-preset=veryfast tune=zerolatency bitrate=800 insert-vui=1 ! h264parse ! rtph264pay name=pay0 pt=96 config-interval=1 ! udpsink port=5004 host=224.1.1.1'
# Single receiver
pipe_out = 'appsrc ! video/x-raw, format=BGR ! queue ! videoconvert ! video/x-raw, format=BGRx ! videoconvert ! x264enc speed-preset=veryfast tune=zerolatency bitrate=800 insert-vui=1 ! h264parse ! rtph264pay name=pay0 pt=96 config-interval=1 ! udpsink port=5004 host=target_host_IP auto-multicast=0'
Also note that fourcc is useless with gstreamer backend, so just use 0.
Then you would create a SDP file for receiver such as:
m=video 5004 RTP/AVP 96
c=IN IP4 224.1.1.1
a=rtpmap:96 H264/90000
Be sure that no firewall rule prevents UDP/5004 from server to receiver. Then you may be able to receive with VLC opening the SDP file:
cvlc test.sdp
If you really want to use RTSP streaming (that will automatically send the SDP to client), it is possible to use shmsink/shmsrc such as here, but this is not an efficient solution, it may have some CPU overhead, so if trying this you would also check CPU usage.
Upvotes: 0