使用 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)

非常欢迎任何帮助!

不确定这是适合您的情况的解决方案,但以下内容可能会有所帮助:

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

  2. 您也可以设置 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-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,因为它提供了更好的流性能。