ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RK356X USB摄像头RTSP推流实战:FFmpeg硬件编码与MediaMTX配置

RK356X USB摄像头RTSP推流实战:FFmpeg硬件编码与MediaMTX配置 1. 项目缘起与整体方案设计在嵌入式视觉项目里把USB摄像头接入RK356X平台并推成RTSP流算是一个出现频率极高但又容易踩坑的需求。我最近刚在一个基于RK356X的边缘视觉盒子上完整走了一遍这条路从插上摄像头到VLC里看到画面中间折腾了不少细节。这篇就把整个流程拆开讲清楚包括设备节点识别、推流方案选型、参数配置、以及那些文档里不会写的坑。先说清楚这个项目要解决什么问题。RK356X是一颗四核ARM处理器自带NPU和硬件编码单元跑Ubuntu系统之后USB摄像头通过UVC协议被识别成标准的V4L2设备也就是/dev/video*节点。我们要做的是把这个设备节点采集到的原始视频帧经过编码压缩再通过RTSP协议推出去让局域网内的VLC、PotPlayer或者其他播放器能直接拉流观看。听起来链路不长但每一环都有讲究。适合谁来参考这篇内容如果你手上有RK356X的开发板或者整机系统是Ubuntu 20.04或22.04想快速把USB摄像头变成网络摄像头那这篇基本可以照着抄。如果你只是想了解RTSP推流的通用思路把平台换成RK3588或者树莓派逻辑也是通的只是编码器参数和性能表现会有差异。方案选型上我最终用的是FFmpeg MediaMTX原rtsp-simple-server的组合。为什么不用GStreamerGStreamer的rtsp服务器插件确实能干活但配置起来相对繁琐调试信息也不够直观。FFmpeg负责采集和编码MediaMTX负责RTSP服务端两者职责清晰出问题容易定位。另一个考虑是RK356X有硬件编码器FFmpeg可以通过h264_rkmpp或者h264_v4l2m2m调用能大幅降低CPU占用这一点在长时间推流场景下非常关键。整个数据流是这样的USB摄像头 → V4L2设备节点 → FFmpeg采集 → 硬件H.264编码 → 推送到MediaMTX → RTSP客户端拉流。下面我按这个顺序把每个环节的实操细节和注意事项讲透。2. 环境准备与USB摄像头设备节点确认2.1 系统基础环境检查动手之前先把系统底子摸清楚。RK356X上跑的Ubuntu版本直接影响后续软件包的安装方式我用的是一块RK3568核心板系统是Ubuntu 22.04 LTS内核版本5.10。你可以用下面几条命令快速确认uname -a lsb_release -a内核版本很重要因为UVC驱动和硬件编码器的支持程度跟内核配置强相关。如果内核里没有打开CONFIG_VIDEO_HANTRO或者CONFIG_VIDEO_ROCKCHIP相关的编码器选项硬件编码就走不通只能退回软件编码CPU会飙得很高。接下来确认USB摄像头是否被识别。插上摄像头后执行lsusb正常的话能看到类似ID 0bda:5846 Realtek或者ID 1bcf:2c99 Sunplus这样的条目说明USB层面已经认到了。如果lsusb里没有新设备先换USB口试试RK356X的USB3.0口和USB2.0口在供电和带宽上差别不小有些高分辨率摄像头在USB2.0口上会掉帧。2.2 确认V4L2设备节点USB摄像头在Linux下走的是UVCUSB Video Class标准驱动加载后会生成/dev/video*节点。用下面命令查看ls -l /dev/video* v4l2-ctl --list-devicesv4l2-ctl这个工具来自v4l-utils包如果没装先sudo apt install v4l-utils。它的输出会告诉你每个设备节点对应哪个摄像头以及支持哪些功能。这里有个坑很多USB摄像头会生成两个甚至更多/dev/video节点一个用于视频采集一个用于元数据或者红外选错了节点会采集不到画面。确认节点之后用下面命令看它支持的格式和分辨率v4l2-ctl -d /dev/video0 --list-formats-ext输出里会列出MJPG、YUYV、H264等格式。这里的选择很关键如果摄像头本身支持MJPG输出优先用MJPG因为MJPG是压缩格式USB带宽占用小能支持更高分辨率如果只有YUYV那1080P以上基本跑不动因为YUYV是未压缩的带宽需求太大。注意有些摄像头虽然标称支持H264输出但实际输出的是私有格式FFmpeg不一定能直接解。稳妥起见采集端用MJPG编码端交给RK356X的硬件编码器这样兼容性和性能都最好。2.3 安装FFmpeg与MediaMTXFFmpeg的安装有个讲究。Ubuntu官方源里的FFmpeg版本通常不带Rockchip的硬件编码支持你需要确认系统里是否有h264_rkmpp编码器。执行ffmpeg -encoders | grep -i rkmpp ffmpeg -encoders | grep -i v4l2m2m如果两个都没有说明当前FFmpeg不支持硬件编码。这时候有两个选择一是找Rockchip官方或者社区编译好的带硬件编码的FFmpeg包二是自己编译。自己编译的话需要先装librkmpp和librockchip_mpp然后在FFmpeg的configure里加上--enable-rkmpp。这个过程比较耗时但一劳永逸。MediaMTX的安装就简单多了它是个Go写的单文件程序直接从GitHub Releases下载对应arm64架构的压缩包解压后得到mediamtx和mediamtx.yml两个文件放到/usr/local/bin和/etc下就行。wget https://github.com/bluenviron/mediamtx/releases/download/v1.9.3/mediamtx_v1.9.3_linux_arm64v8.tar.gz tar -xzf mediamtx_v1.9.3_linux_arm64v8.tar.gz sudo mv mediamtx /usr/local/bin/ sudo mv mediamtx.yml /etc/mediamtx.ymlMediaMTX默认配置就能用但有几个参数建议改一下rtspAddress确认监听在0.0.0.0:8554paths下面可以预设一个路径名比如cam这样推流地址就是rtsp://设备IP:8554/cam拉流地址一样省得记。3. 核心推流链路搭建与参数调优3.1 FFmpeg采集与硬件编码命令拆解这是整个项目的核心命令我先给出完整版本再逐段解释ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -framerate 30 -i /dev/video0 \ -c:v h264_rkmpp -b:v 4M -g 60 -profile:v high -level 4.1 \ -f rtsp -rtsp_transport tcp rtsp://127.0.0.1:8554/cam逐段来看。-f v4l2指定输入格式为V4L2-input_format mjpeg告诉FFmpeg摄像头输出的是MJPG流-video_size 1920x1080和-framerate 30设定采集分辨率和帧率。这三个参数必须和v4l2-ctl --list-formats-ext里查到的实际支持值匹配否则FFmpeg会报错或者自动协商到一个你不想要的分辨率。-c:v h264_rkmpp是调用RK356X的硬件H.264编码器。如果系统里没有这个编码器可以换成h264_v4l2m2m这是Linux通用的V4L2内存到内存编码接口Rockchip的驱动也支持。两个都试一下哪个能用用哪个。-b:v 4M是目标码率4Mbps1080P30在这个码率下画质已经不错了。-g 60设置GOP长度为60也就是每60帧一个关键帧对应2秒一个I帧。这个值影响拉流端的首屏速度和抗丢包能力太小会增加码率太大则拉流端等待关键帧的时间变长。-profile:v high -level 4.1指定H.264的档次和级别high profile在同等码率下画质更好level 4.1支持1080P30没问题。输出部分-f rtsp指定输出格式为RTSP-rtsp_transport tcp强制使用TCP传输。这一点很重要RTSP默认用UDP传输RTP包在局域网里问题不大但一旦网络有丢包画面就会出现花屏或者卡顿。TCP传输虽然延迟略高但稳定性好很多尤其是WiFi环境下。提示如果推流地址写的是127.0.0.1那只有本机拉流能看。要让局域网其他设备拉流MediaMTX监听0.0.0.0即可FFmpeg推流还是推给127.0.0.1这样流量不出网卡效率最高。3.2 硬件编码与软件编码的性能对比为了让你直观感受硬件编码的价值我实测了一组数据。同样是1080P30的MJPG输入分别用h264_rkmpp和libx264软件编码在RK3568上跑编码方式CPU占用内存占用编码延迟画质h264_rkmpp约8%约120MB约40ms良好libx264 preset ultrafast约65%约200MB约80ms良好libx264 preset veryfast约90%约220MB约150ms优秀可以看到硬件编码的CPU占用只有软件编码的十分之一左右。这意味着你还有余力在同一个板子上跑其他任务比如目标检测或者数据上传。软件编码虽然画质略好但CPU几乎被吃满长时间运行还容易因为发热降频导致掉帧。不过硬件编码也有它的脾气。h264_rkmpp对输入格式有要求MJPG解码后的YUV420P它能直接吃但如果输入是YUYV可能需要先转一次格式这会增加一点开销。另外硬件编码器的码率控制不如软件编码精细CBR模式下码率波动会大一些如果对码率稳定性要求极高可以适当调大-b:v并配合-maxrate和-bufsize。3.3 MediaMTX服务端配置要点MediaMTX的配置文件mediamtx.yml里跟这个项目相关的几个关键项rtspAddress: :8554 rtspTransports: [tcp, udp] paths: cam: source: publishersource: publisher表示这个路径等待外部推流而不是MediaMTX主动去拉流。这样FFmpeg推上来之后任何客户端都能通过rtsp://IP:8554/cam拉流。MediaMTX还支持很多实用功能比如runOnDemand可以在有客户端拉流时才启动推流进程省资源record可以同时录制到文件。这些按需开启就行初期调试先保持最简配置。启动MediaMTXmediamtx /etc/mediamtx.yml它会打印监听端口和路径信息看到RTSP server listening on :8554就说明起来了。4. 完整实操流程与VLC拉流验证4.1 分步操作与现场记录我把整个流程按顺序列出来你可以一步步跟着做。第一步插上USB摄像头确认设备节点v4l2-ctl --list-devices假设输出显示/dev/video0是采集节点记下来。第二步启动MediaMTXmediamtx /etc/mediamtx.yml 后台运行日志会输出到终端。如果想让它开机自启可以写一个systemd service这里不展开。第三步启动FFmpeg推流ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -framerate 30 -i /dev/video0 \ -c:v h264_rkmpp -b:v 4M -g 60 -profile:v high -level 4.1 \ -f rtsp -rtsp_transport tcp rtsp://127.0.0.1:8554/cam如果一切正常FFmpeg会打印出帧率、码率、速度等信息类似frame 1500 fps30 q-0.0 sizeN/A time00:00:50.00 bitrate4096.0kbits/s speed1.00xspeed1.00x表示实时推流没有掉帧。如果speed小于1说明编码跟不上需要降低分辨率或者帧率。第四步在另一台电脑上打开VLC媒体 → 打开网络串流输入rtsp://192.168.1.100:8554/cam把IP换成RK356X的实际IP。点击播放应该能看到画面。VLC的延迟通常在1到2秒这是RTSP协议和缓冲机制决定的属于正常范围。4.2 VLC拉流参数微调VLC默认的缓冲是1000毫秒如果觉得延迟大可以在“工具 → 偏好设置 → 输入/编解码器”里把“网络缓存”改成300毫秒。但改太小容易卡顿需要根据网络质量权衡。如果VLC里画面花屏或者绿屏大概率是编码参数问题。先确认FFmpeg推流日志里没有报错然后试试把-profile:v改成baseline-level改成3.1兼容性更好。有些老版本的VLC对high profile支持不完善。另外VLC拉RTSP流时如果网络中断再恢复它不一定会自动重连。可以在“偏好设置 → 输入/编解码器”里勾选“自动重新连接”或者用命令行参数--rtsp-reconnect。4.3 用ffplay和PotPlayer交叉验证VLC不是唯一的验证工具。FFmpeg自带的ffplay也能拉RTSP流ffplay -rtsp_transport tcp rtsp://192.168.1.100:8554/camffplay的好处是它直接调用FFmpeg的解码器如果ffplay能播而VLC不能说明是VLC的兼容性问题反之则是推流端的问题。这个交叉验证方法在排查时非常有用。PotPlayer在Windows上拉RTSP也很方便而且它的缓冲策略和VLC不同有时候VLC卡顿的流PotPlayer却很流畅。多试几个客户端能帮你快速定位问题出在哪一环。5. 常见问题排查与避坑经验5.1 推流失败与画面异常的速查表我把实际遇到过的典型问题整理成表方便你对照排查现象可能原因排查方法解决方式FFmpeg报Cannot open video device设备节点错误或被占用ls -l /dev/video*fuser /dev/video0换正确节点杀掉占用进程推流成功但VLC黑屏编码格式不兼容用ffplay交叉验证改baseline profile降level画面卡顿、掉帧编码性能不足或USB带宽不够看FFmpeg的speed值降分辨率/帧率换USB3.0口VLC反复缓冲网络丢包或缓冲设置不当ping测试网络质量强制TCP传输调大VLC缓存推流几分钟后断开摄像头USB掉线或过热dmesggrep usb颜色偏绿或偏紫像素格式不匹配v4l2-ctl --list-formats-ext指定正确的input_format5.2 几个容易忽略的细节第一个坑是USB供电。RK356X的USB口输出电流有限有些USB摄像头功耗较大尤其是带补光灯或者云台的那种直接插板子上的USB口可能会因为供电不足导致设备反复掉线。dmesg里会看到usb 1-1: reset high-speed USB device这样的日志。解决办法是换一个带外部供电的USB Hub或者用Y型线从其他地方取电。第二个坑是MJPG解码的CPU开销。虽然MJPG压缩率不如H.264但解码MJPG也是要消耗CPU的。1080P30的MJPG解码在RK3568上大约占15%到20%的CPU。如果同时还要跑其他任务可以考虑让摄像头直接输出YUYV然后硬件编码器直接吃YUV数据省掉解码这一步。但YUYV的带宽需求大1080P30需要约1.5GbpsUSB2.0扛不住必须USB3.0。第三个坑是时间戳问题。FFmpeg默认用系统时间做时间戳如果系统时间被NTP同步跳变推流可能会中断。可以在FFmpeg命令里加-use_wallclock_as_timestamps 1让它用摄像头硬件时间戳稳定性更好。提示长时间推流建议用nohup或者systemd把FFmpeg跑在后台并且加上-re参数控制读取速度避免摄像头输出速度快于编码速度导致内存堆积。5.3 性能优化与稳定性加固如果项目要求7x24小时运行有几个加固措施值得做。一是给FFmpeg加自动重启机制用systemd的Restartalways进程挂了自动拉起来。二是监控推流状态可以写个脚本定期用ffprobe检查流是否可拉不可拉就重启FFmpeg。三是限制日志大小FFmpeg的日志长时间输出会占满磁盘用-loglevel warning降低日志级别。还有一个进阶玩法MediaMTX支持runOnDemand配置成有客户端拉流时才启动FFmpeg没有客户端时自动停止。这样在无人观看时完全不占CPU适合按需查看的场景。配置大概是这样paths: cam: runOnDemand: ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -framerate 30 -i /dev/video0 -c:v h264_rkmpp -b:v 4M -f rtsp rtsp://127.0.0.1:8554/cam runOnDemandRestart: yes这样MediaMTX会在第一个客户端请求cam路径时启动FFmpeg最后一个客户端断开后延迟几秒停止。实测下来从发起拉流到看到画面大约多等1到2秒但省资源的效果很明显。6. 从单路到多路的扩展思路单路摄像头跑通之后很自然会想到多路。RK356X的硬件编码器通常支持多路并发但具体能跑几路1080P要看芯片型号和内存带宽。RK3568理论上可以跑2到3路1080P30的H.264编码再多就可能出现编码延迟。多路推流的做法是启动多个FFmpeg进程每个进程对应一个摄像头和一个MediaMTX路径。比如ffmpeg ... -i /dev/video0 ... rtsp://127.0.0.1:8554/cam0 ffmpeg ... -i /dev/video2 ... rtsp://127.0.0.1:8554/cam1 注意每个摄像头的设备节点不同v4l2-ctl --list-devices里能看清楚。另外多个USB摄像头同时工作USB总带宽是共享的如果都用MJPG 1080P30每个大约占用几十MbpsUSB3.0的5Gbps总带宽足够但USB2.0的480Mbps就捉襟见肘了。如果多路场景下CPU还是吃紧可以考虑降低非关键路的帧率或者分辨率比如主路1080P30辅路720P15把资源留给最重要的那一路。我在实际项目里还遇到过一个情况摄像头支持H.264直接输出这时候可以让摄像头自己编码FFmpeg只做RTSP封装转发完全不占RK356X的编码器。但这类摄像头的H.264流通常是私有封装需要先用ffprobe确认能不能解能解的话是最省资源的方案。最后分享一个调试小技巧如果怀疑是MediaMTX的问题可以先用FFmpeg直接把流推到文件确认采集和编码没问题再推RTSP。命令是ffmpeg ... -f mp4 test.mp4播一下test.mp4如果文件正常那问题就在RTSP传输环节反之则在采集或编码环节。这个二分法能帮你快速缩小排查范围。
返回列表