新时代码农 树莓派 基于树莓派的视频推流方案 dong4j 2024-11-06 2025-02-21
简介 因为项目上有很多设计到监控视频的工作, 所以想通过树莓派来研究一下流媒体相关的技术, 所以总结了一些在树莓派上实现视频推流的方案.
硬件:
摄像头 一个摄像头使用了官方的 RPi Camera V2, 使用了索尼 IMX219 800 万像素传感器, 另一个使用了 IMX519 , 具备 1600W 像素.
RPi Camera V2 插上就能识别, 但是 IMX519 费了点功夫, 找到了几篇相关的讨论:
关于型号 感光芯片型号 支持的树莓派主板型号 支持的驱动类型 OV5647 所有树莓派主板 libcamera / Raspicam OV9281 所有树莓派主板 libcamera IMX219 (树莓派官方) 所有树莓派主板 libcamera / Raspicam IMX219 (第三方) 树莓派计算模块 libcamera IMX290/ IMX327 所有树莓派主板 libcamera IMX378 所有树莓派主板 libcamera IMX477 (树莓派官方) 所有树莓派主板 libcamera / Raspicam IMX477 (第三方) 树莓派计算模块 libcamera IMX519 树莓派主板 libcamera(另装驱动) IMX708 (树莓派 Camera Module 3) 所有树莓派主板 libcamera IMX296(树莓派 Global Camera) 所有树莓派主板 libcamera IMX500(树莓派 AI Camera) 所有树莓派主板 libcamera
下面是具体的实施步骤.
修改固件配置 1 2 3 4 5 6 7 8 sudo nano /boot/config.txt sudo nano /boot/firmware/config.txt camera_auto_detect=0 dtoverlay=imx219,cam0 dtoverlay=imx519,cam1
修改摄像头配置 从 libcamera/src/ipa/rpi/pisp/data at arducam · ArduCAM/libcamera · GitHub 下载最新的 imx519.json
文件, 替换掉原来的配置: /usr/share/libcamera/ipa/rpi/pisp/imx519.json
, 然后重启即可.
驱动检查 1 2 3 4 5 6 7 8 9 dmesg | grep imx [ 0.532486] platform 1f00110000.csi: Fixed dependency cycle(s) with /axi/pcie@120000/rp1/i2c@88000/imx219@10 [ 0.532607] platform 1f00128000.csi: Fixed dependency cycle(s) with /axi/pcie@120000/rp1/i2c@80000/imx519@1a [ 3.298575] imx519 4-001a: Device found is imx519 [ 3.311363] rp1-cfe 1f00110000.csi: found subdevice /axi/pcie@120000/rp1/i2c@88000/imx219@10 [ 3.312865] rp1-cfe 1f00128000.csi: found subdevice /axi/pcie@120000/rp1/i2c@80000/imx519@1a [ 3.312891] rp1-cfe 1f00128000.csi: Using sensor imx519 4-001a for capture [ 3.598311] rp1-cfe 1f00110000.csi: Using sensor imx219 6-0010 for capture
可以看到 imx519 的驱动成功加载了.
检查摄像头 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 v4l2-ctl --list-devices pispbe (platform:1000880000.pisp_be): /dev/video20 /dev/video21 /dev/video22 /dev/video23 /dev/video24 /dev/video25 /dev/video26 /dev/video27 /dev/video28 /dev/video29 /dev/video30 /dev/video31 /dev/video32 /dev/video33 /dev/video34 /dev/video35 /dev/video36 /dev/video37 /dev/media2 /dev/media3 rp1-cfe (platform:1f00110000.csi): /dev/video8 /dev/video9 /dev/video10 /dev/video11 /dev/video12 /dev/video13 /dev/video14 /dev/video15 /dev/media0 rp1-cfe (platform:1f00128000.csi): /dev/video0 /dev/video1 /dev/video2 /dev/video3 /dev/video4 /dev/video5 /dev/video6 /dev/video7 /dev/media1 rpivid (platform:rpivid): /dev/video19 /dev/media4
主要关注 rp1-cfe 信息, 这个设备通常指的是连接到 Raspberry Pi 的 CSI (Camera Serial Interface) 设备, 可查看具体设备的详细信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 ➜ ~ v4l2-ctl -d /dev/video0 --all Driver Info: Driver name : rp1-cfe Card type : rp1-cfe Bus info : platform:1f00128000.csi Driver version : 6.6.31 Capabilities : 0xaca00001 Video Capture Metadata Capture Metadata Output Streaming Extended Pix Format Device Capabilities Device Caps : 0x24a00001 Video Capture Metadata Capture Streaming Extended Pix Format Media Driver Info: Driver name : rp1-cfe Model : rp1-cfe Serial : Bus info : platform:1f00128000.csi Media version : 6.6.31 Hardware revision: 0x00114666 (1132134) Driver version : 6.6.31 Interface Info: ID : 0x03000017 Type : V4L Video Entity Info: ID : 0x00000015 (21) Name : rp1-cfe-csi2_ch0 Function : V4L2 I/O Pad 0x01000016 : 0: Sink, Must Connect Link 0x02000037: from remote pad 0x1000006 of entity 'csi2' (Video Interface Bridge): Data Priority: 2 Video input : 0 (rp1-cfe-csi2_ch0: ok) Format Video Capture: Width/Height : 640/480 Pixel Format : 'pRAA' (10-bit Bayer RGRG/GBGB Packed) Field : None Bytes per Line : 800 Size Image : 384000 Colorspace : Raw Transfer Function : None YCbCr/HSV Encoding: ITU-R 601 Quantization : Full Range Flags : Format Metadata Capture: Sample Format : 'SENS' (Sensor Ancillary Metadata) Buffer Size : 16384
测试摄像头 自动对焦并拍摄照片
1 libcamera-still -t 10000 -n --autofocus-mode auto -o test1.jpg --camera 1
Raspberry Pi Camera Autofocus: Complete Guide (V1, V2 & HQ)
IMX219 直接使用 rpicam-jpeg
来拍摄一张图片:
1 rpicam-jpeg -o test.jpg --camera 0
通过 WebUI 控制摄像头 picamera2-WebUI 是 Raspberry Pi 相机模块的轻量级 Web 界面,基于 Picamera2 Python 库并使用 Flask 构建。此项目提供了一个用户界面,用于配置相机设置、拍摄照片以及在基本图库中管理图像。
部署 1 2 3 git clone git@github.com:monkeymademe/picamera2-WebUI.git cd picamera2-WebUIpython app.py
一切正常的话, 会在 8080 端口开启一个 Web 服务:
2 个摄像头都成功识别到了.
还能够控制摄像头的分辨率:
摄像头控制
查看视频流 Your browser does not support the video tag.
Your browser does not support the video tag.
左边:IMX219: 1080P 右边: IMX519 4K
流媒体服务器 基于树莓派的流媒体服务器非常多, 下面 shi 一些常见的方案
调研结果 mjpg-stream - web 可以直接访问,但是帧率太低,参考
vlc - 延迟高,大约 2s-5s
raspivid - 延迟 170ms 左右,并支持 h264 硬件编码,好像可以 参考这里
该工具已经默认集成到了树莓派之中
1 raspivid -t 0 -w 1280 -h 720 -fps 20 -o - | nc -k -l 8090
-t 表示延时;-o 表示輸出;-fps 表示帧率;端口号为 8090
-w 表示图像宽度;,-h 表示图像高度,此处设置的分辨率为 1280720;我们可以修改 -w 1920 -h 1080 将分辨率设置为 1920 1080
该命令执行玩后不会出现任何打印信息即可
在局域网内的 linux 主机上安装 mplayer 工具(sudo apt-get install mplayer),然后执行命令
1 mplayer -fps 200 -demuxer h264es ffmpeg://tcp://192.168.31.166:8090
即会弹出一个显示树莓派实时视频流的窗口,而且延迟尚可,大概在 200ms 左右,基本上可以满足实时性的要求了。
pistreaming - 性能不错,延迟低
安装依赖
1 2 3 4 5 6 7 8 # 安装python3-picamera sudo apt-get install python3-picamera # 安装pip3 sudo apt-get install python3-pip # 安装ws4py sudo pip3 install ws4py # 安装ffmpeg sudo apt-get install ffmpeg
下载源码
1 git clone https://github.com/waveform80/pistreaming.git
测试效果
1 2 3 4 # 进入源码目录 cd pistreaming # 运行程序 python3 server.py
浏览器访问查看效果
1 http://pi_ip:8082/index.html
motion - 卡顿很严重,延迟在 30s+
fswebcam - 采集摄像头数据保存为图片,用来做视频监控的话,性能和延迟都达不到要求
Camkit - 支持硬件编解码,比较小众,缺少维护
ffmpeg 硬解码推流 - 支持硬件编解码,但是延迟很高(不知道是推流原因还是播放原因),画质很差
流程比较复杂,整理成脚本保存在 ffmpeg 目录中
安装 x264 硬件编码 install_x264.sh
安装 ffmpeg install_ffmpeg.sh
安装运行 nginx install_nginx.sh
启动推流(注意 192.168.0.111 替换为你的 ip 地址)
1 /usr/local/bin/ffmpeg -ss 0 -pix_fmt yuv420p -i /dev/video0 -c:v h264_omx -f flv rtmp://192.168.0.111:1935/live/camera
potplayer 播放 url rtmp://192.168.0.111:1935/live/camera
webrtc - 看视频貌似效果很好,工作量太大,后期验证
最终方案 油管上找到一个 测试树莓派 5 最佳直播方式的视频 , 对比了 WebRTC, TCP, UDP 和 RTSP 的延迟:
看着 MediaMTX 延迟表现非常好, 决定直接使用它来作为媒体服务器使用, 另外一点是它内置了树莓派支持.
1 2 3 4 5 wget https://github.com/bluenviron/mediamtx/releases/download/v1.9.3/mediamtx_v1.9.3_linux_arm64v8.tar.gz tar -zxvf mediamtx_v1.9.3_linux_arm64v8.tar.gz -C mediamtx_v1.9.3_linux_arm64v8 cd mediamtx_v1.9.3_linux_arm64v8./mediamtx
内置支持 MediaMTX 自带了树莓派摄像头支持, 配置如下 (mediamtx-rpiCamera.yml):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 ... paths: cam0: source: rpiCamera rpiCameraCamID: 0 rpiCameraWidth: 1920 rpiCameraHeight: 1080 rpiCameraHFlip: True rpiCameraVFlip: True cam1: source: rpiCamera rpiCameraCamID: 1 rpiCameraWidth: 2560 rpiCameraHeight: 1440 rpiCameraHFlip: True rpiCameraVFlip: True rpiCameraBrightness: 0.0 rpiCameraContrast: 1 rpiCameraSaturation: 1 rpiCameraSharpness: 0 rpiCameraExposure: normal rpiCameraAWB: auto rpiCameraDenoise: "cdn_off" rpiCameraShutter: 0 rpiCameraMetering: centre rpiCameraGain: 0 rpiCameraEV: 0 rpiCameraHDR: false rpiCameraFPS: 30 rpiCameraIDRPeriod: 60 rpiCameraBitrate: 2000000 rpiCameraProfile: main rpiCameraLevel: "4.1" rpiCameraAfMode: continuous rpiCameraAfRange: normal rpiCameraAfSpeed: normal rpiCameraLensPosition: 0
启动方式:
1 2 export PATH=$PATH :/usr/sbin && nohup ./mediamtx mediamtx-rpiCamera.yml &
RTMP 方式 配置(mediamtx-rtmp.yml)
1 2 3 4 5 6 7 paths: cam0: runOnInit: bash -c 'rpicam-vid --hflip --vflip -t 0 --camera 0 --nopreview --codec yuv420 --width 1920 --height 1080 --inline --listen -o - | ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f flv rtmp://192.168.21.7/live/pi5a-camera0' runOnInitRestart: yes cam1: runOnInit: bash -c 'rpicam-vid --hflip --vflip -t 0 --autofocus-mode auto --camera 1 --nopreview --codec yuv420 --width 2540 --height 1440 --inline --listen -o - | ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 2560x1440 -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f flv rtmp://192.168.21.7/live/pi5a-camera1' runOnInitRestart: yes
将视频流推送到 192.168.21.7
服务器, 这个是使用 WVP 搭建的另一个流媒体服务器:
启动
1 nohup ./mediamtx mediamtx-rtmp.yml &
1 2 3 4 5 6 7 8 9 10 11 12 ... Output Metadata: encoder : Lavf59.27.100 Stream Metadata: encoder : Lavc59.37.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A frame= 0 fps=0.0 q=0.0 Lsize=N/A time=00:00:00.00 bitrate=N/A speed= 0x video:0kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown frame= 1863 fps= 18 q=18.0 size=N/A time=00:01:14.48 bitrate=N/A speed=0.721x
RTMP 明显要比 WebRTC 延迟高, 基本上在 4 秒以上.
RTSP 方式 配置(mediamtx-rtsp.yml)
1 2 3 4 5 6 7 paths: cam0: runOnInit: bash -c 'rpicam-vid --hflip --vflip -t 0 --camera 0 --nopreview --codec yuv420 --width 1920 --height 1080 --inline --listen -o - | ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 1920x1080 -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH' runOnInitRestart: yes cam1: runOnInit: bash -c 'rpicam-vid --hflip --vflip -t 0 --camera 1 --nopreview --codec yuv420 --width 2560 --height 1440 --inline --listen -o - | ffmpeg -f rawvideo -pix_fmt yuv420p -s:v 2560x1440 -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp rtsp://localhost:$RTSP_PORT/$MTX_PATH' runOnInitRestart: yes
启动
1 nohup ./mediamtx mediamtx-rtsp.yml &
1 2 3 4 5 6 7 8 9 Output Metadata: encoder : Lavf59.27.100 Stream Metadata: encoder : Lavc59.37.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A frame= 1245 fps= 18 q=19.0 size=N/A time=00:00:49.76 bitrate=N/A speed=0.72x
使用 WVP 的拉流代理:
延迟有高出一大截, 毕竟是经过 2 个流媒体服务器多次转码的:
延迟对比
启动脚本 为了方便测试, 写了一个启动脚本, 支持多种协议以及分辨率:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #!/bin/bash if [[ "$1 " == "-h" ]]; then echo "使用方法: $0 [协议] [摄像头编号] [宽度] [高度] [URL地址]" echo "示例: $0 rtmp 0 1920 1080 192.168.21.7/pi5b, 最终URL: rtmp://192.168.21.7/pi5b/0" echo echo "参数说明:" echo " 协议 : rtmp 或 rtsp (用于选择流媒体传输协议)" echo " 摄像头编号 : 摄像头编号 (例如 0 或 1)" echo " 宽度 : 分辨率宽度 (例如 1920)" echo " 高度 : 分辨率高度 (例如 1080)" echo " URL地址 : 基础的 URL 地址 (例如 192.168.21.7/pi5b)" echo echo "RTMP 推流说明:" echo " 192.168.21.7:1935/pi5b --> rtmp://192.168.21.7:1935/pi5b/0 推流至 m920x 的 zlm 服务, 默认端口 1935, 会出现在 WVP 的推流列表中" echo " 192.168.21.7:41935/pi5b --> rtmp://192.168.21.7:41935/pi5b/0 推流至 m920x 的 mediamtx 服务, 使用 mediamtx 服务的 WebRTC 访问: http://192.168.21.7:48889/pi5b/{CAMERA}" echo " 127.0.0.1:1935/pi5b --> 本地推流至 mediamtx 服务, 使用 WebRTC 访问: http://ip:8889/pi5b/{CAMERA}" echo " ====================================================" echo " ./stream.sh rtmp 0 1920 1080 192.168.21.7/pi5a" echo " ./stream.sh rtmp 0 2560 1440 192.168.21.7:41935/pi5a" echo " ./stream.sh rtmp 0 3840 2160 192.168.21.7/pi5a" echo " ./stream.sh rtmp 0 3840 2160 127.0.0.1/pi5a" echo echo "RTSP 推流说明:" echo " 192.168.21.7:554/pi5b --> rtsp://192.168.21.7:554/pi5a/0 推流至 m920x 的 zlm 服务, 默认端口 554, 会出现在 WVP 的推流列表中" echo " 192.168.21.7:48554/pi5b --> rtsp://192.168.21.7:48554/pi5b/0 推流至 m920x 的 mediamtx 服务, 使用 WebRTC 访问: http://192.168.21.7:48889/pi5b/{CAMERA}" echo " 127.0.0.1:8554/pi5b --> 本地推流至 mediamtx 服务, 使用 WebRTC 访问: http://ip:8889/pi5b/{CAMERA}" echo " ====================================================" echo " ./stream.sh rtsp 1 1920 1080 192.168.21.7/pi5b" echo " ./stream.sh rtsp 1 2560 1440 192.168.21.7:48554/pi5a" echo " ./stream.sh rtsp 1 3840 2160 192.168.21.7:8554/pi5a" echo " ./stream.sh rtsp 1 3840 2160 127.0.0.1:8554/pi5a" exit 0 fi PROTOCOL=$1 CAMERA=$2 WIDTH=$3 HEIGHT=$4 URL=$5 if [ "$PROTOCOL " == "rtmp" ]; then OUTPUT_URL="rtmp://${URL} /${CAMERA} " FFMPEG_FORMAT="flv" elif [ "$PROTOCOL " == "rtsp" ]; then OUTPUT_URL="rtsp://${URL} /${CAMERA} " FFMPEG_FORMAT="rtsp" else echo "不支持的协议: $PROTOCOL " exit 1 fi nohup bash -c "rpicam-vid --hflip --vflip -t 0 --camera $CAMERA --nopreview --codec yuv420 --width $WIDTH --height $HEIGHT --inline --listen -o - | ffmpeg -f rawvideo -pix_fmt yuv420p -s:v ${WIDTH} x${HEIGHT} -i /dev/stdin -c:v libx264 -preset ultrafast -tune zerolatency -f $FFMPEG_FORMAT $OUTPUT_URL " > ${PROTOCOL} -cam${CAMERA} .log 2>&1 &
相关资源 高阶玩法 V4L2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $ sudo apt-get install v4l-utils $ v4l2-ctl --list-devices bcm2835-codec-decode (platform:bcm2835-codec): /dev/video10 /dev/video11 /dev/video12 /dev/media1 bcm2835-isp (platform:bcm2835-isp): /dev/video13 /dev/video14 /dev/video15 /dev/video16 /dev/media0 mmal service 16.1 (platform:bcm2835-v4l2): /dev/video0
驱动程序 V4L2 驱动程序提供用于访问摄像头和编解码器功能的标准 Linux 接口。通常,Linux 会在启动期间自动加载驱动程序。但在某些情况下,可能需要 明确加载摄像头驱动程序 。
使用时的设备节点 libcamera
/dev/videoX 默认操作 video0
第一个 CSI-2 接收器的 Unicam 驱动程序 video1
用于第二个 CSI-2 接收器的 Unicam 驱动程序 video10
视频解码 video11
视频编码 video12
简单的 ISP,除了 Bayer 到 RGB/YUV 的转换外,还可以执行 RGB/YUV 格式之间的转换和调整大小 video13
输入至完全可编程 ISP video14
完全可编程 ISP 的高分辨率输出 video15
完全可编程 ISP 的结果输出较低 video16
来自完全可编程 ISP 的图像统计数据 video19
HEVC 解码
使用 V4L2 驱动程序 参阅 V4L2 文档 。