使用v4l2h264enc的opencv和gstreamer的RPi tcp视频流



我正在尝试在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-rawvideo/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,因为它提供了更好的流性能。

不确定这是否适合您的情况,但以下可能会有所帮助:

  1. 不要将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 ! ...
  1. 在gst启动的情况下,您正在接收UYVY帧并将这些帧发送到h264编码器,而在opencv情况下,你正在获得编码器可能不支持输入的BGR帧。只需在编码器之前添加插件videoconvert。

  2. 您也可以设置h264配置文件的级别。

最新更新