我正在尝试在Python中使用OpenCV和Gstreamer来流式传输帧。我正在使用64位Bulseye Raspberry Pi 4。这是我在复盆子上使用的管道:
pipeline = 'appsrc ! "video/x-raw,framerate=25/1,format=BGR,width=640,height=480" ! '
'queue ! v4l2h264enc ! "video/x-h264,level=(string)4" ! h264parse ! '
'rtph264pay ! gdppay ! tcpserversink host=0.0.0.0 port=7000 '
cv2.VideoWriter(pipeline, cv2.CAP_GSTREAMER, 0, args.fps, (args.width, args.height))
v4l2h264enc
似乎有问题。启用GST_DEBUG=4
会给我
0x3e39a00 ERROR GST_PIPELINE gst/parse/grammar.y:1007:priv_gst_parse_yyparse: no source element for URI "/x-raw,framerate=25/1,format=BGR,width=640,height=480""
0:00:00.087855767 92892 0x3e39a00 ERROR GST_PIPELINE gst/parse/grammar.y:1007:priv_gst_parse_yyparse: no source element for URI "/x-h264,level=(string)4""
这两个错误对我来说是最重要的,但你可以在这里看到完整的日志。
使用类似的CLI管道,流连接得很好(除了一些编码灰度,这对我来说不是最关键的(。
# Stream
gst-launch-1.0 v4l2src device=/dev/video0 !
'video/x-raw,framerate=30/1,format=UYVY,width=1280,height=720' !
v4l2h264enc ! 'video/x-h264,level=(string)4' ! h264parse !
rtph264pay config-interval=1 pt=96 ! gdppay ! tcpserversink host=0.0.0.0 port=7000
# Client
sudo gst-launch-1.0 -v tcpclientsrc host=yraspberry ip> port=7000 !
gdpdepay ! rtph264depay ! avdec_h264 ! videoconvert !
autovideosink sync=false
使用appsrc
和opencv,我也尝试过写入文件,但没有成功。
opencv库是在Gstream支持下编译的。这是我从cv2.getBuildInformation()
:得到的
Video I/O:
DC1394: NO
FFMPEG: YES
avcodec: YES (58.91.100)
avformat: YES (58.45.100)
avutil: YES (56.51.100)
swscale: YES (5.7.100)
avresample: NO
GStreamer: YES (1.18.4)
v4l/v4l2: YES (linux/videodev2.h)
欢迎任何帮助!
如@SeB所述,v4l2h264enc
可能不支持BGR帧。并导致这个错误,videoconvert
修复了这个错误:
opencv/opencv/modules/videoio/src/cap_gstreamer.cpp (2293) writeFrame OpenCV | GStreamer warning: Error pushing buffer to GStreamer pipeline
但no source element for URI
错误的主要原因是video/x-raw
和video/x-h264
周围的双引号。
这是最后一条有效的管道。
pipeline = 'appsrc ! videoconvert ! v4l2h264enc ! video/x-h264,level=(string)4 ! '
'h264parse ! matroskamux ! tcpserversink host=0.0.0.0 port=7000 '
此外,正如@SeB所建议的,我还包含了matroskamux
而不是rtph264pay ! gdppay
,因为它提供了更好的流性能。
不确定这是否适合您的情况,但以下可能会有所帮助:
- 不要将RTP用于TCP流。AFAIK,RTP主要依赖于UDP分组(尽管并非不可能,就像RTSP服务器在请求TCP传输时所做的那样(。您可以只使用一个容器,如flv、matroska或mpegts:
... ! h264parse ! matroskamux ! tcpserversink
... ! h264parse ! flvmux ! tcpserversink
... ! h264parse ! mpegtsmux ! tcpserversink
并调整接收机,如:
tcpclientsrc ! matroskademux ! h264parse ! ...
tcpclientsrc ! flvdemux ! h264parse ! ...
tcpclientsrc ! tsdemux ! h264parse ! ...
在gst启动的情况下,您正在接收UYVY帧并将这些帧发送到h264编码器,而在opencv情况下,你正在获得编码器可能不支持输入的BGR帧。只需在编码器之前添加插件videoconvert。
您也可以设置h264配置文件的级别。