从 Raspberry Pi 上的 USB 摄像头获取原始 h264 数据包

Getting raw h264 packets from USB camera on Raspberry Pi

我正在尝试从连接到我的 Raspberry PI

的 USB 网络摄像头接收 H264 帧

使用 RPi 摄像头模块,我可以运行以下命令获取标准输入中输出的 H264 数据:raspivid -t 0 -w 640 -h 320 -fps 15 -o - 接近零延迟

USB 摄像头是否有等效的功能?我有两个 USB 相机,我想用它来做这个。

使用 ffprobe /dev/videoX 我得到以下输出:(简化为重要细节):

$ ffprobe /dev/video0
...
Input #0, video4linux2,v4l2, from '/dev/video0':
Duration: N/A, start: 18876.273861, bitrate: 147456 kb/s
Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 1280x720, 147456 kb/s, 10 fps, 10 tbr, 1000k tbn, 1000k tbc

$ ffprobe /dev/video1
...
Input #0, video4linux2,v4l2, from '/dev/video1':
Duration: N/A, start: 18980.783228, bitrate: 115200 kb/s
Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 800x600, 115200 kb/s, 15 fps, 15 tbr, 1000k tbn, 1000k tbc


$ ffprobe /dev/video2
...
Input #0, video4linux2,v4l2, from '/dev/video2':
Duration: N/A, start: 18998.984143, bitrate: N/A
Stream #0:0: Video: h264 (Main), yuv420p(progressive), 1920x1080, -5 kb/s, 30 fps, 30 tbr, 1000k tbn, 2000k tbc

据我所知,其中两个不是 H264,这需要 "decoded" 到 H264,所以我知道那里增加了一点延迟。但是第三个 (video2) 是 H264,所以我应该能够从中获取数据?我试图用 CAT 将其输出,但它说我得到了无效的参数。

据我所知,使用 FFMPEG 可能是这里唯一的选择。想使用适用于所有 RPi 的软件(apt 安装)。

关于 H264 数据包的额外问题: 当我将数据从 raspivid 命令流式传输到我的解码器时,它工作得很好。但是,如果我决定丢弃前 10 个数据包,那么它永远不会初始化解码过程,只会显示黑色背景。任何人都知道我可以在我的软件中重新创建的第一个数据包中可能缺少什么,所以我不必为每个新连接的用户重新启动流?

编辑:奖金问题答案: 谷歌搜索后,我看到 raspivid 发送给我的前两帧是。因此,通过忽略前两个帧,我的解码器将无法正确 "decode" 。因此,如果我保存这些帧并首先将它们发送给所有新用户,它就可以完美运行。似乎这些用于某种初始过程。

0x27 = 01 00111 = type 7    Sequence parameter set (B-frame)
0x28 = 01 01000 = type 8    Picture parameter set (B-frame)

首先,让我们弄清楚数据流。对于 Raspi 凸轮:

  1. Raspi 的Raspi camera is connected by CSI(相机串行接口)。此 link 携带未压缩的原始图像数据。

  2. raspivid talks to the embedded GPU of the Raspi to access the image data and also asks the GPU to perform H.264 encoding, which always adds some latency (you could use raspiyuv 获取未压缩的原始数据,可能延迟更短)。

USB 网络摄像头通常传输未压缩的原始图像数据。但有些还传输 H.264 或 jpeg 编码数据。

接下来,Video for Linux API version 2 不是为 shell 管道制作的,所以你无法从 /dev/videoX 与猫。您需要一些代码来执行 IOCTL 调用,以协商从设备读取数据的内容和方式。 ffmpeg 正是这样做的。

关于您的奖励问题,您可以尝试 raspivid 的 --inline option,它会强制流在每个 I-frame.

上包含 PPS 和 SPS headers

接下来,使用 -f rawvideo 从 ffmpeg 输出 H.264 数据在我看来是错误的,因为 rawvideo 表示未压缩的视频。您可以改为尝试 -f h264 强制使用原始 H.264 视频输出格式:

ffmpeg -i /dev/video2 -c copy -f h264 pipe:1

最后,您实际上想要从您的 USB 网络摄像头 获取 H.264 流。由于图像数据来自相机未压缩,因此必须首先将其编码为 H.264。 Raspi 上的明智选择是使用硬件编码器,因为使用像 x264 这样的软件编码器会消耗太多 CPU 资源。

如果您有使用 --enable-mmal and/or --enable-omx-rpi[= 配置的 ffmpeg 53=],您可以使用 ffmpeg 与硬件 H.264 编码器对话。

要不,看看gstreamer and its omxh264enc element, eg. here. gstreamer can also talk to v4l2 devices