ARTICLE DETAIL

资讯详情

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

空地协同低延迟图传方案:RTMP上行+RTSP下行,从2秒压到400ms

空地协同低延迟图传方案:RTMP上行+RTSP下行,从2秒压到400ms 干四足机器人和无人机联调这活儿的人基本都经历过同一个崩溃瞬间机器人明明在楼下走得好好的屏幕里那画面却像幻灯片一样卡了三四秒等你在延迟画面里看到障碍物再打方向机器人都已经撞上去了。我这边实际项目里四足机器人、无人机两台设备要组一套空地协同巡检小队可视操控的延迟直接决定了这套系统能不能用。折腾到最后把链路定格在SmartMediaKit做流媒体中枢、上行走RTMP、下行走RTSP这套方案上延迟从原来的两三秒压到了四百毫秒以内画面基本能做到“手到眼到”。这篇文章就把这套低延迟可视操控方案从头到尾拆开讲从协议选型、系统架构到具体推拉流参数、避坑经验适合正在做机器人图传、无人机地面站、或者想搞明白RTSP/RTMP到底怎么配合的朋友想直接抄作业也完全没问题。1. 先搞清楚为什么图传链路偏偏要用RTSP和RTMP很多第一次接触图传方案的人上来就问一句“现在WebRTC不是最火吗延迟最低为什么不用”这个问题很真实但答案得从机器人的实际部署环境说起。1.1 RTSP不是“老古董”遥控场景它依然能打RTSPReal Time Streaming Protocol是个1998年就定下来的老协议但它并没有过时相反在监控、安防、机器人图传这些领域一直活得很好。它的核心工作方式是“控制与媒体分离”先用RTSP的DESCRIBE、SETUP、PLAY这些命令把会话建立起来然后用RTP协议承载实际的音视频数据包。这个机制带来两个操控场景非常需要的特性一是延迟天然低因为RTP包可以走UDP没有TCP那套拥塞控制和重传机制网络通畅的时候数据是流水一样过去的二是交互灵活客户端可以随时发出PLAY、PAUSE、TEARDOWN指令想在机器人行驶过程中暂停看某一帧细节都做得到。在我实际调试四足机器人时地面站和机器人之间通常是同一个局域网或者点对点自组网这种网络环境带宽稳定、丢包率低RTSP/UDP模式简直是为它量身定做的。机载端摄像头通过硬件编码器出H.264流地面站用RTSP拉流播放端到端延迟能做到200到400毫秒连机器人遇到台阶时腿部的颠簸姿态都能实时看到。1.2 RTMP的意义在于上行稳定且生态兼容那上行为什么选RTMP而不是RTSP这里有个容易忽略的现实问题RTSP推流在公网环境里很容易被防火墙挡而且很多嵌入式设备、尤其是无人机飞控板或者配套的图传模块对RTMP推流的支持比RTSP推流成熟得多。RTMP基于TCP1977端口在很多网络环境里是放行的数据包只要发出去就不会丢最多是延迟变高。对机载端来说要的不是“极低延迟”而是“稳定不中断地往上送画面”因为上行链路一旦断流地面站那边直接就是黑屏比延迟更致命。另外从生态来看PC端OBS、ffmpeg、几乎所有编码器硬件都天然支持RTMP推流。无人机机载的H.264/H.265编码器海思、瑞芯微、Jetson平台输出之后用ffmpeg封装成FLV格式一条命令就能推上去几乎没有适配成本。1.3 为什么不用WebRTC、GB28181或者纯私有协议这里我直接给一张自己选型时做的对比表方案延迟表现部署复杂度嵌入式适配难度适合场景RTSP低局域网200-400ms低中局域网/点对点低延迟操控RTMP中1-3秒低低公网上行推流、CDN分发WebRTC极低300ms高信令穿透高跨公网实时互动GB28181中中中国标监控平台对接私有协议视实现而定高高全自研链路封闭系统WebRTC确实延迟最低但它需要信令服务器做协商还要处理ICE穿透、DTLS加密机载端那颗算力有限的芯片上跑WebRTC库内存和CPU都吃不消。GB28181呢更多是给监控平台对接用的做低延迟遥控明显不对路。私有协议就更不用说了四足机器人和无人机如果来自不同团队要求大家都适配你的私有协议协作成本直接起飞。所以最终方案就是“上行RTMP 下行RTSP”而中间需要一个既能收RTMP、又能发RTSP的转换中枢这正是SmartMediaKit这套中间件的位置。2. SmartMediaKit在空地协同链路里的角色协议的“翻译中枢”一条完整的图传链路里SmartMediaKit要解决的问题是机载端推上来的RTMP流和地面端要拉的RTSP流它们不是同一种封装格式也不是同一种传输语义。RTMP推上来的是FLV封装RTSP要发的是RTP载荷这之间必须有一个组件做“翻译”。2.1 一条完整图传链路长什么样拿我的实际项目举例链路是这样的四足机器人身上装一个USB或MIPI接口的摄像头机载的RK3588/海思芯片做H.264编码然后用ffmpeg把编码后的流推成RTMP到SmartMediaKit无人机那边同样机载相机编码后推RTMP上行地面站电脑或者遥控手柄上的安卓屏幕通过RTSP地址从SmartMediaKit拉流如果现场有多个观察员也有人用网页端看那就走HTTP-FLV流浏览器里用flv.js播放。这套链路里SmartMediaKit既是接收端又是发送端还承担了转封装的工作。我不需要机载端去理解地面端要什么协议机载端永远只推RTMP地面端永远只拉RTSP两边的职责单一出了问题排查起来也很方便。2.2 核心模块拆开看接入、转封装与分发SmartMediaKit这类流媒体中间件核心模块实际上就是三块。第一块是接入模块它内置RTMP Server和RTSP Server机载端往1935端口推RTMP服务端就能接入进来形成一路live流。第二块是转封装模块把FLV封装解析成裸的H.264/H.265帧再按照RTSP要求的RTP打包规则重新封装成RTP包甚至还能直接转成HTTP-FLV分发给Web端。第三块是分发模块当RTSP拉流端请求某一路直播流时它从内存里最近一个关键帧开始往下发而不是从头开始发这一点对低延迟观看非常重要。这里有一个很容易踩的坑如果服务端每来一个拉流请求都重新从最早的帧开始发客户端需要等很久才能看到画面而如果服务端直接从最新关键帧开始发首屏秒开。SmartMediaKit在内存里维护了一个GOP缓存也就是关键帧到下一个关键帧之间的完整帧序列每次新客户端接入就从最近一个关键帧开始推流这是低延迟体验的一个隐形功臣。2.3 服务端放哪里局域网直连还是公网中转部署位置决定了延迟上限。最好的情况是把SmartMediaKit跑在地面站的笔记本上机器人和无人机通过自组网WiFi把RTMP流直接推到笔记本的1935端口地面站再从本机的554端口拉RTSP整个链路不出局域网延迟最低实测能稳定在200到300毫秒。如果团队需要远程支援比如人在办公室想看现场画面那就让机载端把RTMP推到云服务器上的SmartMediaKit远程端再拉RTSP但公网中转难免会引入50到200毫秒的附加延迟这个要做好心理准备。还有一点值得注意如果用的是树莓派、Jetson Nano这一级别的小主机当服务端尽量用有线网口别用WiFi。我最早图省事服务端跑在连WiFi的笔记本上一开无人机图传WiFi同时要持视频流还要承担控制命令结果控制信号也跟着卡顿后来改成网线直连整个世界清净了。3. 搭一条能用的低延迟链路从部署到首帧画面的完整过程下面进入正题怎么把这条链路从零搭起来。我尽量把每一步的命令和参数给全你可以直接抄。3.1 服务端SmartMediaKit部署和基本配置SmartMediaKit在Linux x86和ARM设备上都有编译好的版本也支持Docker部署。我最常用的是Docker方式一条命令就能跑起来docker run -d --name smk \ -p 1935:1935 \ -p 554:554 \ -p 8080:8080 \ -v /opt/smk/config:/config \ smk-server:latest这里1935是RTMP端口554是RTSP端口8080是HTTP-FLV和Web管理面板端口。启动之后到管理面板里确认一下8044端口绑定是否正确然后把GOP缓存时间设置成1秒或2秒缓冲时长别开太大这两个参数直接决定拉流端的首帧速度和延迟。如果是在内网使用配置里关掉鉴权减小握手开销如果暴露在公网还是老老实实开鉴权免得被扫到盗拉流。部署完可以用netstat确认端口在监听netstat -tlnp | grep -E 1935|554|80803.2 机载端推流ffmpeg一条命令搞定四足机器人机载端如果是Linux系统摄像头是V4L2接口而且摄像头本身输出H.264很多USB摄像头有这种模式可以直接用copy模式推流CPU占用几乎为零ffmpeg -f v4l2 -input_format h264 -video_size 1280x720 -framerate 30 \ -i /dev/video0 -c:v copy -an \ -f flv rtmp://192.168.1.10:1935/live/quadruped如果摄像头输出的是原始YUV格式那就需要先在机载端编码这里要注意编码参数后面会详细讲。先给一个适用于RK3588/海思平台软编码的版本ffmpeg -f v4l2 -input_format yuyv422 -video_size 1280x720 -framerate 30 \ -i /dev/video0 -c:v libx264 -preset ultrafast -tune zerolatency \ -g 30 -bf 0 -b:v 2000k -maxrate 2000k -bufsize 4000k \ -pix_fmt yuv420p -an \ -f flv rtmp://192.168.1.10:1935/live/quadruped-tune zerolatency和-bf 0就是给低延迟服务的前者让x264尽可能降低编码缓冲后者彻底禁用B帧避免解码端等未来帧。-g 30表示30帧一个关键帧也就是一秒一个关键帧。码率2000k是720p30在室内场景的保守值如果你用的是巡检场景画面细节多建议提到4000k否则马赛克严重。无人机那边同理只是摄像头接口可能变成CSI或者SDI但推流的命令结构完全一样把输入源换成你的设备节点就行。机载端推流之后可以用ffprobe在服务端确认流已经进来了ffprobe -v error -show_streams -select_streams v:0 rtsp://127.0.0.1:554/live/quadruped3.3 地面站拉流RTSP地址和播放参数SmartMediaKit收到RTMP流之后会自动生成一路对应的RTSP流地址格式通常是rtsp://服务端IP:554/live/quadruped。地面站用ffplay测试直接用下面这组低延迟参数ffplay -fflags nobuffer -fflags discardcorrupt -flags low_delay \ -probesize 32 -analyzeduration 0 \ -sync ext -framedrop \ rtsp://192.168.1.10:554/live/quadruped这串参数的意思分别是nobuffer是关闭播放端的输入缓冲discardcorrupt是丢弃损坏帧low_delay是要求解码器低延迟输出probesize和analyzeduration设成极小值是让播放器拿到很少的数据就开始解码不要花时间去探测整个流的结构sync ext和framedrop则是用丢帧的方式保持音视频同步和实时性。如果是安卓端的操控App不要直接用系统自带的VideoView它的缓冲策略完全是按点播视频设计的延迟感人。建议用ExoPlayer或者ijkplayer然后手动把buffer大小调小或者干脆用SmartMediaKit提供的HTTP-FLV地址配合flv.js做Web端观看延迟也能控制在1秒以内。3.4 先别急着上真机本地测试流模拟验证一下每次改完链路我都会先用本地生成一路测试流验证连通性而不是直接上机器人跑。方法很简单ffmpeg -re -i /path/to/test.mp4 -c copy -f flv rtmp://127.0.0.1:1935/live/test-re是按原始帧率读取文件模拟实时流。然后地面站用RTSP拉流看能不能出画面。另外一个教训是网上搜“rtmp测试地址”“rtsp测试网络流”经常会找到一些所谓的公共测试源但那些地址很多是内网地址、非公开链路或者随时失效的我见过的类似rtsp://10.x.x.x/pltv/...这种一眼就是内部IPTV源根本联不通。自己造流最靠谱对链路验证来说也足够。想测公网效果找一台云服务器部署SmartMediaKit再推流上去效果一目了然。4. 把延迟从秒级压到毫秒级每个环节逐个拆方案跑通只是第一步真正让这套系统“可用”的是把延迟压下来。我在这上面吃了不少苦头下面把端到端的延迟来源和调优手段完整摊开。4.1 延迟从哪里来一段视频从镜头到屏幕的旅程很多人以为延迟就是网络传输时间但实际上网络延迟只占很小一部分。一帧画面从摄像头出来到屏幕显示要经历这些环节采集环节传感器的曝光时间和帧率等待通常16到33毫秒编码环节编码器要等一组帧才输出如果是带B帧的编码结构延迟会陡增网络传输局域网内一般是几毫秒到几十毫秒服务端缓冲中间件为了平滑转发可能会缓存几百毫秒的数据播放器缓冲播放器为了防止抖动也会缓存数据解码与渲染解码本身快但显示队列如果满了画面会排队。我最初用默认参数做测试全链路延迟在2秒左右。用秒表一测摄像头对着手机计时器地面站屏幕上的时间和真实时间差了整整两秒这才意识到大头全在编码缓冲和播放器缓冲上。4.2 编码层调优关闭B帧、缩短GOP、选对编码档次编码层的调优是性价比最高的一步。先说B帧H.264里的B帧双向预测帧会参考后面的帧所以解码器拿到一个B帧必须等未来的帧到达才能解码这等于强制引入延迟。低延迟场景必须-bf 0把B帧关掉。其次关键帧间隔GOPGOP越长平均码率越省但遇到切流、跳转、丢包恢复等待关键帧的时间就越久。在遥控场景GOP设为1秒比较合理也就是帧率30时-g 30再低的话码率浪费严重没必要。编码档次方面用-preset ultrafast或veryfast配合-tune zerolatency这两个参数组合能让x264在延迟和画质之间向延迟大幅倾斜。码率控制上低延迟要选CBR类也就是-b:v和-maxrate设成相同数值-bufsize设成2倍码率避免瞬时码率波动导致网络排队。我用这套参数把编码延迟稳定控制在了40毫秒以内。4.3 网络和服务端RTSP走TCP还是UDP缓冲怎么设RTSP拉流端可以请求RTP over UDP也可以RTP over TCP。UDP延迟低因为不需要重传机制但一旦网络丢包画面直接花掉TCP丢包会触发重传延迟会出现瞬时尖峰但画面不会破。我的经验是纯局域网或自组网首选UDP四足机器人在室内巡检的场景实测下来UDP比TCP稳定画面干净如果跨公网或者无线信号不稳定选TCP更稳妥宁可延迟偶尔高一点也比满屏花块强。SmartMediaKit服务端的缓冲参数是关键中的关键。GOP cache设太大会导致新端接入时先从很老的帧开始发延迟一下子上来设太小又容易导致弱网下的画面撕裂。我的经验值是1到2秒。另外服务端如果开启了“按需转封装”一定要确保第一个拉流端接入时才启动转封装而不是推流端一上来就转好存着这样可以减少不必要的CPU占用和内存拷贝。4.4 播放端压延迟别让播放器毁掉前面积累的优势播放器是最后也是最容易毁掉延迟的一环。ffmpeg/ffplay可以按前面那串参数直接压但如果你的地面站用的是第三方App就得在播放器初始化时手动设置buffer。用ExoPlayer的话关键代码是LoadControl loadControl new DefaultLoadControl.Builder() .setBufferDurationsMs(200, 200, 50, 50) .setPrioritizeTimeOverSizeThresholds(true) .build();前两个参数是最小缓冲和最大缓冲我直接设成200毫秒第三个参数是缓冲低于50毫秒时开始重新加载第四个是高于50毫秒时停止加载。这样播放器就不会预读大量视频流。还有一个很容易被忽略的问题地面站如果开着其他占带宽的软件比如云同步盘、系统更新延迟会突然恶化。调试现场我一般会把地面站网卡设置为“仅用于本地链路”关掉不必要的后台流量拿秒表实测全链路从400毫秒能再降到350毫秒左右。5. 四足机器人现场调试最容易翻车的四个场景链路搭建和延迟调优都做完之后真正考验人的是现场环境里的各种意外。这里我整理了四个翻车概率最高的场景和对应的处理方式。5.1 弱网环境下的卡顿与花屏四足机器人跑在楼道、地下车库、丛林里的时候无线信号衰减非常严重。带宽不足的直接表现就是画面马赛克、花屏、卡住。一开始我以为是编码问题后来抓包发现是码率超出了实际可用带宽数据在中间被疯狂拥塞控制。解决办法有三条路一是降低编码码率720p从4000k降到1500k牺牲一点清晰度换来流畅二是降低帧率从30fps降到15fps或者10fps运动画面的流畅度虽然下降但维持了可用性三是做码率自适应SmartMediaKit支持对RTSP流做动态转码根据拉流端的网络情况自动降分辨率但前提是服务端CPU算力够用跑在低端ARM板子上就算了。5.2 断线重连与长时间运行无人机飞个十公里巡检中途信号遮挡导致RTMP推流断了这是必然会发生的事。ffmpeg默认断流之后会直接退出不会自动重连。我的处理方式是在机载端写一个循环脚本实时检测ffmpeg进程断线之后马上重新拉起来并重新推流while true; do ffmpeg -f v4l2 -input_format h264 -i /dev/video0 \ -c:v copy -an -f flv rtmp://server/live/uav \ -loglevel error echo stream lost, reconnecting in 1s... sleep 1 done服务端这边也要注意清理僵尸会话。长时间运行之后如果拉流端异常断开但服务端没回收会话内存里的缓存会越来越多最终导致推流被踢或者CPU暴涨。我在SmartMediaKit配置里开了会话保活检测空闲超过30秒就强制回收这样跑一天的巡检任务也不至于服务端崩掉。5.3 多端同时观看时的并发分发空地协同任务往往不只一个人在看画面。遥控员看机器人的第一视角观察员看全局视角还有人盯无人机的云台画面可能同时有3到6个地面端。如果每个端都直接去连机载摄像头机载端上行带宽根本扛不住。SmartMediaKit作为中心分发节点正好把“一路推流”变成“多路拉流”机载端只推一路分发全部在服务端完成。这个场景下服务端机器最好能开千兆网口同时在服务端限制单路拉流的最大码率防止某个端卡顿拖垮所有端。5.4 嵌入式设备上的编码SPS/PPS问题四足机器人机载端如果是海思、瑞芯微这类平台的硬件编码器经常遇到一个典型问题SPS/PPS信息只在编码器初始化的时候发一次而不是像标准H.264 Annex B格式那样在每个关键帧前都带一遍。结果就是SmartMediaKit转成RTSP后有些播放器能出画面有些播放器黑屏还有的播放器画面出来是花屏。解决办法是在ffmpeg推流命令里加上-bsf:v h264_mp4toannexb把所有帧转换成Annex B格式并把SPS/PPS写入每个关键帧前面ffmpeg -f v4l2 -input_format h264 -i /dev/video0 \ -c:v copy -bsf:v h264_mp4toannexb -an \ -f flv rtmp://server/live/quadruped如果是海思方案直接出H.264裸流也可以用h264_attach_sps_pps这个bitstream filter强制附加。这个坑排查起来特别费时间因为明面上所有协议都是对的实际上就折在一个SPS/PPS上。另外一个关联问题是时间戳。有些嵌入式编码器出来的时间戳从零开始但实际推流的时候如果时间戳跳变播放端会判定为流异常然后缓冲卡顿。稳妥做法是在ffmpeg里加上-use_wallclock_as_timestamps 1让时间戳以推流端的系统时间为基准保证平滑播放。6. 我这套方案还能怎么改几种实际衍生玩法如果你已经照着上面的链路跑通了别急着收工这套基于SmartMediaKit的架构还有几个很实用的变种方向可以按需扩展。一个方向是把“下行RTSP”直接对齐到现有监控平台。比如项目要求把无人机实时画面接入到已有的国标28181监控平台那么可以在SmartMediaKit后面再接一层GB28181网关把RTSP流转成国标流推送至上级平台。这样既保住了地面站的低延迟操控又不破坏已有的监管体系。热词里提到的“无人机支持国标28181协议”“无人机管控平台建设方案”基本就是走这条路。另一个方向是结合AI视觉做“看得见还要看得懂”。四足机器人巡检时如果想实时识别仪表盘读数、判断管道是否泄漏可以考虑在服务端加一路低分辨率的分析流用SmartMediaKit把原始RTSP流转成第二个低码率流喂给视觉模型推理然后把推理结果叠加到原始画面上回传给地面站。注意这种做法千万不要在机载端做机载端算力太宝贵留给飞控和避障都嫌不够地面站或者服务端做推理才是合理架构。还有朋友问过我可不可以把延迟压到100毫秒以内。答案是能但得换对抗丢包和抖动的手段比如用SRT协议替代RTMP做上行或者在机载端直接用硬编码器输出RTP裸流传给SmartMediaKit。不过对于四足机器人和无人机的操控场景400毫秒的延迟完全够用再往低压性价比会非常低还容易引入新的不稳定因素。我这里有个实际体会画面延迟降到400毫秒以内之后真正困扰操控员的已经不是延迟而是摄像头的视角太窄、缺乏空间感。所以后来我把注意力放到研究云台增稳和多视角拼接上去了。整套方案跑了大半年最大的心得其实是低延迟不是某一个环节的功劳而是一条链路上每个人都在为“少等一帧”做设计。编码器关掉B帧、服务端缩短GOP缓存、播放器调小缓冲每一环让出几十毫秒积累起来就是天壤之别。如果你也在折腾机器人图传建议先从最简单的RTMP推流RTSP拉流链路开始把延迟实测出来再逐段优化而不是一上来就追求什么黑科技协议这条路我已经替你验证过了行得通。
返回列表