使用 v4l2h264enc 使用 opencv 和 gstreamer 的 RPi tcp 视频流
RPi tcp video streaming with opencv and gstreamer using v4l2h264enc
我正在尝试在 Python 中使用 OpenCV 和 Gstreamer 流式传输帧。我在 64 位 Bulseye Raspberry Pi 4。
这是我在 Raspberry 上使用的管道:
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""
这两个错误对我来说最重要,但您可以查看完整的日志 here。
使用类似的 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)
非常欢迎任何帮助!
不确定这是适合您的情况的解决方案,但以下内容可能会有所帮助:
- 不要将 RTP 用于 TCP 流式传输。 AFAIK,RTP 主要依赖于 UDP 打包(尽管在请求 TCP 传输时并非不可能像 RTSP 服务器那样完成)。您可以只使用 flv、matroska 或 mpegts 等容器:
... ! h264parse ! matroskamux ! tcpserversink
... ! h264parse ! flvmux ! tcpserversink
... ! h264parse ! mpegtsmux ! tcpserversink
并调整接收机如:
tcpclientsrc ! matroskademux ! h264parse ! ...
tcpclientsrc ! flvdemux ! h264parse ! ...
tcpclientsrc ! tsdemux ! h264parse ! ...
在 gst-launch 的情况下,您正在接收 UYVY 帧并将它们发送到 h264 编码器,而在 opencv 的情况下,您收到的 BGR 帧可能不被编码器支持作为输入。只需在编码器之前添加插件 videoconvert。
您也可以设置 h264 配置文件级别。
如 @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
,因为它提供了更好的流性能。
我正在尝试在 Python 中使用 OpenCV 和 Gstreamer 流式传输帧。我在 64 位 Bulseye Raspberry Pi 4。 这是我在 Raspberry 上使用的管道:
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""
这两个错误对我来说最重要,但您可以查看完整的日志 here。
使用类似的 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)
非常欢迎任何帮助!
不确定这是适合您的情况的解决方案,但以下内容可能会有所帮助:
- 不要将 RTP 用于 TCP 流式传输。 AFAIK,RTP 主要依赖于 UDP 打包(尽管在请求 TCP 传输时并非不可能像 RTSP 服务器那样完成)。您可以只使用 flv、matroska 或 mpegts 等容器:
... ! h264parse ! matroskamux ! tcpserversink
... ! h264parse ! flvmux ! tcpserversink
... ! h264parse ! mpegtsmux ! tcpserversink
并调整接收机如:
tcpclientsrc ! matroskademux ! h264parse ! ...
tcpclientsrc ! flvdemux ! h264parse ! ...
tcpclientsrc ! tsdemux ! h264parse ! ...
在 gst-launch 的情况下,您正在接收 UYVY 帧并将它们发送到 h264 编码器,而在 opencv 的情况下,您收到的 BGR 帧可能不被编码器支持作为输入。只需在编码器之前添加插件 videoconvert。
您也可以设置 h264 配置文件级别。
如 @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
,因为它提供了更好的流性能。