OpenCV和gstreamer rtsp服务器

3

我正在尝试设置一个rtsp服务器,用于编辑OpenCV处理后的IP摄像头的rtsp流并重新传输。捕获rtsp流并编辑帧可以正常工作,但我无法使rtsp服务器正常工作。我收到以下错误消息:

[ 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

我已经尝试了两个不同的管道,如下代码所示,但两者都收到相同的错误消息。
我试图通过rtsp://192.168.y.y:8554/test在VLC播放器中访问rtsp流,但无法建立连接。
我的错误在哪里?有没有调试建议?我对GStreamer没有经验。
我正在使用 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()

不确定你的情况,但是VideoWriter可能期望fps的浮点值。尝试:..., fps=float(frame_fps), ... - SeB
谢谢。这解决了错误1757。 但是其他三个错误896、933和1663仍然存在 :( - George
前两个警告只是提示说没有持续时间(这对于实时流是预期的),因此无法计算当前位置。 - SeB
1个回答

0
主要原因是您的编写管道没有接收端。从OpenCV开始,您可以更好地使用RTP流添加udpsink(在pay0之后由test-launch附加):
# 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'

请注意,使用gstreamer后端时fourcc无用,只需使用0。

然后,您可以为接收器创建一个SDP文件,例如:

m=video 5004 RTP/AVP 96
c=IN IP4 224.1.1.1
a=rtpmap:96 H264/90000

请确保没有防火墙规则阻止服务器向接收器发送UDP/5004。 然后您可以通过打开SDP文件在VLC中接收:

cvlc test.sdp

如果你真的想使用RTSP流媒体(它会自动将SDP发送到客户端),可以使用shmsink / shmsrc,例如here,但这不是一种高效的解决方案,可能会有一些CPU开销,因此如果尝试这个方法,你也需要检查CPU使用情况。


我现在已经编辑了我的答案,使用SDP中的多播地址(在单主机模式下也可能有效),并在x264enc中添加了insert-vui。 VLC可能会发出有关死锁预防的警告。 运行可能需要10秒钟。 如果没有,请确保您可以从发送方向接收方发送UDP / 5004上的数据。 - SeB
为了排除OpenCV编写器,您可以使用终端中的GStreamer,例如:gst-launch-1.0 videotestsrc!video / x-raw,width = 320,height = 240,framerate = 30/1!x264enc speed-preset = veryfast tune = zerolatency bitrate = 2000 insert-vui = 1!h264parse!rtph264pay config-interval = 1!application / x-rtp,media = video,encoding-name = H264!udpsink port = 5004 host = 224.1.1.1 - SeB
最终我找到了一些时间来解决这个问题。我在树莓派终端上运行了以下管道: ./test-launch --gst-debug=3 "( videotestsrc ! video/x-raw, width=640, height=480, framerate=30/1 ! videoconvert ! queue ! x264enc tune=zerolatency ! rtph264pay name=pay0 pt=96 )" 在接收器上,我通过使用vlc打开网络流来访问: rtsp://192.168.x.x:8554/test 显然,我之前有一些针对vlc的防火墙限制,这不允许vlc访问端口8554。 现在我正在尝试使用opencv使相同的管道工作。 - George
我可以使用cv2.imshow读取框架并显示它。但是当将流写入输出管道时,我收到以下错误: [ 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 可能是什么问题? - George
这个错误在每一帧中都会出现。 vlc 显示错误消息,无法连接到流(尽管我使用了与 opencv 无关的相同 rtsp 网络流)。 我使用: [GCC 8.3.0] OpenCV: 4.1.1 Gst: 1.14.4.0 - George
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接