如何使用支持 H264 的网络摄像头在 raspberry Pi 和 rtp 客户端上设置 gstreamer?

How to setup gstreamer on raspberry Pi and client for rtp with H264-capable webcam?

在水下 ROV 项目的背景下,我正在尝试从 Raspberry Pi 型号 2 流式传输(通过 rtp)高清视频流。网络摄像头是 Logitech C920 网络摄像头,我前段时间买的,因为它是当时唯一支持 H264 的摄像头。 我获得尽可能低的延迟也很重要,因为视频将用于驾驶 ROV。

所以我用C920(戴尔站,运行 Ubuntu 14.04)在我的台式电脑上完善了一些gstreamer-1.0流水线,效果很好,但是我在尝试的时候遇到了一些问题使用覆盆子代替它。

首先,我尝试(在 RPi 上)将 H264 摄像机流捕获到 matroska 文件:

#this sets the C920 cam to H264 encoding, framerate 30/1:
v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=1 

gst-launch-1.0 -vvv v4l2src \
! video/x-h264, width=1920, height=1080, framerate=30/1 \
! queue max-size-buffers=1 \
! matroskamux \
! filesink location=/tmp/video.mkv

这非常有效。有点断断续续,我猜是由于缓冲区的大小,但没关系。

然后,我尝试将流放在指向我笔记本电脑的 rtp 流上(MacBook Pro,Yosemite,通过 brew 安装的 gstreamer)。

# on the server (RPi):
gst-launch-1.0 -vvv v4l2src \
! video/x-h264,width=1920,height=1080,framerate=30/1 \
! rtph264pay \
! udpsink host=192.168.0.168 port=5000

# on the client (MacBookPro)
gst-launch-1.0 -vvv udpsrc port=5000 \
   caps="application/x-rtp, media=(string)video, \
   clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" \
! rtpjitterbuffer drop-on-latency=true latency=300 \
! rtph264depay \
! queue max-size-buffers=1 \
! matroskamux \
! filesink location=/tmp/video.mkv

在那里,我一无所获。我用 sudo tcpdump (port 5000 and udp) 检查了客户端,它在端口 5000 上有效地接收了 udp 数据包,但仅此而已。 video.mkv 中没有任何记录,即 "touched",但保持为 0 字节。

在这里阅读了一些相关问题后,我尝试了很多变体,包括:

** (gst-launch-1.0:2832): CRITICAL **: gst_rtp_buffer_map: assertion 'GST_IS_BUFFER (buffer)' failed ** (gst-launch-1.0:2832): CRITICAL **: gst_rtp_buffer_unmap: assertion 'rtp->buffer != NULL' failed

但仍然没有任何输出。

这是客户端的输出:

gst-launch-1.0 -vvv udpsrc port=5000 caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" ! rtpjitterbuffer drop-on-latency=true latency=300 ! rtph264depay ! queue max-size-buffers=10 ! matroskamux ! filesink location=/tmp/movie.mkv
Définition du pipeline à PAUSED...
Le pipeline est actif et n’a pas besoin de phase PREROLL…
/GstPipeline:pipeline0/GstUDPSrc:udpsrc0.GstPad:src: caps = application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96
/GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0.GstPad:sink: caps = application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96
Passage du pipeline à la phase PLAYING…
New clock: GstSystemClock
/GstPipeline:pipeline0/GstRtpJitterBuffer:rtpjitterbuffer0.GstPad:src: caps = application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96
/GstPipeline:pipeline0/GstRtpH264Depay:rtph264depay0.GstPad:sink: caps = application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96

^Chandling interrupt.
Interruption : arrêt du pipeline…
Execution ended after 0:16:23.292637000
Définition du pipeline à PAUSED...
Définition du pipeline à READY (prêt)…
Définition du pipeline à NULL…
Libération du pipeline…

我希望这里有人能给我一些关于这个问题的线索:我应该指出(如果需要的话)我在很大程度上仍然是 gstreamer 的初学者...

编辑 (12/11/16) 按照 ensonic 的建议,我使用了 GST_DEBUG="*:3"。客户端现在告诉它的问题:它找不到视频的类型:

0:00:35.185377000 12349 0x7f878904bb20 WARN typefind
gsttypefindelement.c:983:GstFlowReturn
gst_type_find_element_chain_do_typefinding(GstTypeFindElement *, gboolean, gboolean):<typefind> error: Le flux ne contient pas assez de données.

0:00:35.185416000 12349 0x7f878904bb20 WARN typefind
gsttypefindelement.c:983:GstFlowReturn 
gst_type_find_element_chain_do_typefinding(GstTypeFindElement *, gboolean, gboolean):<typefind> error: Can't typefind stream

ERREUR : de l’élément /GstPipeline:pipeline0/GstDecodeBin:decodebin0   
/GstTypeFindElement:typefind : Le flux ne contient pas assez de données.

Information de débogage supplémentaire :
gsttypefindelement.c(983): GstFlowReturn     
gst_type_find_element_chain_do_typefinding(GstTypeFindElement *, gboolean, gboolean) (): /GstPipeline:pipeline0/GstDecodeBin:decodebin0  
/GstTypeFindElement:typefind:

Can't typefind stream

因此,客户端在流中没有足够的数据来确定其类型... 我应该如何改变它?我不明白缺少什么!

几点评论:

1) 在客户端使用 "gst-launch-1.0 -e ... " 使 ctrl-c 发送一个 eos 以便文件最终确定。

2) 在raspi上,在udpsink前添加"gdppay",在客户端上在udpsrc后添加"gdpdepay"。这将传输事件和查询,因为您不使用 rtsp。

3) 在客户端尝试运行 GST_DEBUG="*:3" 看看是否有任何错误。也可以尝试 运行 " !decodebin !auto​​videosink" 看看是否有图像。

根据 ensonic 的评论(见下文),我终于设法让两条管道都正常工作。 诀窍是使用 gdppay/gdpdepay 元素而不是 rtph264pay/rtph264depay.

上server-side(Raspberry Pi)

#set the Logitech C920 cam properly (1920x1080, 30 fps)
v4l2-ctl --set-fmt-video=width=1920,height=1080,pixelformat=1 --set-parm=30

# exec the following pipeline (only after gstreamer runs on the client!):
gst-launch-1.0 -vvv -e v4l2src \
 ! video/x-h264,width=1920,height=1080,framerate=30/1 \
 ! gdppay \
 ! udpsink host=192.168.0.168 port=5000

在客户端 (MacBookPro)

# launch the following command before executing server pipeline:
gst-launch-1.0 -e -vvv udpsrc port=5000 \
   caps="application/x-gdp, streamheader=(buffer)< [insert long header here] >" \
 ! gdpdepay \
 ! video/x-h264, width=1920, height=1080, pixel-aspect-ratio=1/1, framerate=30/1 \
 ! decodebin \
 ! queue max-size-buffers=10 \
 ! autovideosink sync=false async=false

结果

  • CPU 加载

C920在Raspberry Pi上的表现可圈可点。对于 1920x1080 分辨率,在 30 fps 下,总 cpu 负载小于 3%。作为比较,当我在 Raspberry 上编码等效的原始 YUV-stream 时,负载攀升至 96%。客户端的负载(对于我的 2011 Intel i5 MacBookPro)大约是 25%。

  • 视频延迟

我已经连续 20 分钟测试了之前的管道一次,总共测试了 10 多次。每次我得到非常 约 250 毫秒 的可重现延迟,无论是通过 LAN 还是 WLAN。更改 queues' 缓冲区的大小并没有多大帮助。考虑到人们可以在网上阅读到有关流媒体延迟的内容,我认为这是完全可以接受的。并且足够低速驾驶车辆。

  • 流开始

有时,在 server-side 上启动管道后,许多数据包由于以下错误而丢失:

gst_h264_parse_handle_frame:<h264parse0> broken/invalid nal Type: 1 Slice, Size: xxxx will be dropped  

但是这些错误很快就消失了,也许在接收到下一个关键帧之后(一个问题是,我不能轻易更改 cam 的编码参数)?

其他提示和备注

  • 启动顺序

如上所述,确保在 客户端管道之后 启动服务器管道。否则协商失败。

  • 正在获取 header 缓冲区

要获取服务器流的(很长)header 缓冲区,请使用 -vvv 选项执行一次服务器管道,将其终止,然后 copy/paste 将其置于客户端的上限中管道。

  • gstreamer 和 OS 使用的版本

Raspberry Pi 2,Raspbian,4.1.19-v7+,gstreamer 1.2.0 (http://packages.qa.debian.org/gstreamer1.0)

客户: MacBook Pro 2011、i5、Apple OSX Yosemite、gstreamer 1.10.1(通过 brew 安装)

再次感谢 ensonic 提出了切换到 gdp 的想法!