
直播推拉流方案我见过不少但绝大多数都绕不开一台昂贵的小主机。这次我把目光放回一块吃灰的 ARM 电视盒子主板上四核 A53、1GB 内存、无风扇、整机功耗不到 5W。在这个基础上搭出的 MEDAI V2是一套低成本直播推拉流边缘网关同时承担六种协议接入分发、硬编硬解、绿幕抠像和轻量 AI 人像分割。如果你也想做小型直播间、校园活动直播、户外移动机位或者只是想把手里老旧盒子用起来这篇内容应该能帮你省掉不少弯路的钱。下面全是实际搭建和调试过程中记录下来的东西。1. 项目定位与硬件选型思路1.1 为什么盯上 RK3528 这种“电视盒子级”主板先聊选型。直播推流任务本质上分两类一类是“转发”另一类是“转码”。转发只做协议转换和封装对 CPU 要求很低转码则要把视频重新编码对硬件要求很高。很多项目的误区是一上来就打算软编软解于是被 CPU 性能绑架被迫买 8 核 x86 小主机。实际上大量场景只需要“接入——协议转换——输出”特别是从摄像头或上游拉流再推到平台时视频码流甚至可以做到不重新编码。RK3528 这类芯片的特点是解码能力强、编码能力够用、功耗极低。它更适合作为“边缘处理节点”而不是“大型流媒体服务器”。用我做的 MEDAI V2 来说核心定位就是把 RTSP 摄像头、USB 摄像头、上游 RTMP/FLV 流统一收进来在本地完成协议仲裁、必要时的硬编硬解、绿幕或 AI 遮挡处理再以 RTMP、SRT、HLS、HTTP-FLV、WebRTC、RTSP 任意形式分发出去。这样选型有几点现实原因成本足够低。一块 RK3528 核心板或旧盒子价格通常不到一台 N5100 小主机的三分之一。功耗墙很低。被动散热就能长期稳定运行放在户外直播背包里也不用担心散热和电源体积。接口够用。USB 3.0、千兆网口、HDMI 输入输出都能覆盖常见采集需求。VPU 单元完整。日常直播需要的 H.264/H.265 硬解和硬编都有关键是不占 CPU。当然也有代价1GB 内存太小没法跑重型任务稍微复杂一点的服务编排都会出问题。所以整个 MEDAI V2 的设计逻辑从一开始就是“省内存、少切换、硬承担”。1.2 MEDAI V2 的整体架构我不太喜欢把方案说得特别玄。MEDAI V2 其实就是一条串起来的数据流水线采集输入 - 协议接入 - 帧处理绿幕/AI - 硬件编码 - 协议分发 - 多端输出输入侧支持USB HDMI 采集卡或 UVC 摄像头走 Video4Linux2 设备节点。网络摄像头 RTSP 流。上游平台 RTMP/FLV 流。本地文件循环播出也可以这个适合做测试信号源。输出侧支持六种协议这在后面的章节再拆开讲。核心进程只有三个流媒体接入网关、FFmpeg 处理引擎、轻量 Web 管理端。三个进程各自独立通过本地 Socket 或内存映射交换帧避免把所有功能塞进一个大进程后内存爆炸。为什么这么设计因为 1GB 内存下多进程的隔离性比单进程更好控制。某个协议崩溃了只要拉起对应子进程不影响推流主链路。另外每个进程的峰值内存更容易估算方便用 cgroup 或 systemd 资源限制做保护。1.3 1GB 内存下的取舍哲学很多人一听 1GB 内存第一反应是“不够用”。但直播推流场景其实有很强的规律性视频帧是连续到达的不是突发密集计算内存压力主要体现在缓冲队列和编码参考帧上。我的取舍如下不用桌面系统也不用重型容器运行时。根文件系统裁剪到 200MB 左右基础服务全部静态编译。内存里只保留最近 1~2 秒的视频帧缓冲不做全量 GOP 缓存。用 ZRAM 代替磁盘 Swap内存紧张时先把最不活跃的页面压缩而不是直接写 SD 卡。绿幕处理尽量在帧内完成不做跨帧光流除非开 AI 隔帧模式。实际效果是系统空载内存占用约 180MB六协议网关全开约 320MBFFmpeg 硬编码进程约 300MB绿幕处理约 80MB剩余内存给缓存和伞余。这个占比留给系统很大余地实测跑一整天没有掉过链子。# 启用 256MB ZRAM优先级高于磁盘 Swap zramctl -f -s 256M mkswap /dev/zram0 swapon -p 100 /dev/zram0有一点提醒不要在 1GB 内存设备上把所有协议进程全部开成独占模式更不要让每个输入流都独立拉一个 FFmpeg 进程。后面会专门讲如何用一个处理后管道做多路复用。2. 六协议推拉流接入、转发与低延迟设计2.1 先理清六协议各自的用武之地说“支持六协议”之前要搞清楚这些协议并不是平级关系。有的适合推流上云有的适合低延迟播放有的适合监控对接有的适合网页端零插件观看。把它们组合在一起才叫“六协议全支持”。我列一个实际使用矩阵协议方向典型场景延迟表现在 MEDAI V2 中的角色RTMP推流向直播平台、CDN 推流3~8 秒最核心的输出协议SRT推/拉流弱网环境、跨地域回传1~3 秒长距离传输优先HTTP-FLV拉流播放网页端低延迟播放1~5 秒默认网页播放协议HLS拉流播放平台分发、超大并发5~15 秒兼容性兜底WebRTC双向通信连麦、监看、互动0.2~1 秒延迟敏感场景RTSP拉流本地摄像头、NVR 对接0.5~3 秒输入源接入优先六协议不是指六路视频同时硬编码。真正的意思是输入可以是任意协议输出也可以是任意协议并且多个输出协议可以同时在线。比如从 RTSP 摄像头拉流进来同时输出一路 RTMP 给平台、一路 HLS 给网页、一路 WebRTC 给监看端这就是“一进多出”。2.2 用现成组件还是自己写直播推流协议栈如果从零写工作量很大。实际上 RTMP、HLS、SRT 这些协议的封装和解析已经有非常成熟的开源实现我们不需要重复造轮子。MEDAI V2 的方案是以 FFmpeg 作为统一音视频处理引擎以开源流媒体网关做协议聚合和 WebRTC 信令再把 RK3528 的硬件编解码通过 FFmpeg 插件暴露出来。编译 FFmpeg 时我建议重点关注这几个选项./configure \ --prefix/opt/medai \ --enable-cross-compile \ --archaarch64 \ --target-oslinux \ --enable-rkmpp \ --enable-libdrm \ --enable-avcodec \ --enable-avfilter \ --enable-libx264 \ --enable-libx265 \ --enable-nonfree \ --enable-gpl注意实际版本对应关系要根据厂商 SDK 适配不能直接拿电脑上的参数硬套。RK3528 的硬编能力通过rkmpp接口暴露--enable-rkmpp是关键。如果你只是软编那这个芯片的 CPU 很快会被打满根本跑不了多路。2.3 从采集到输出的标准链路我这里给出一个最常用的链路USB 摄像头 - 硬编码 - RTMP 推流。命令看起来像这样ffmpeg -f v4l2 -input_format mjpeg -video_size 1920x1080 -framerate 30 -i /dev/video0 \ -c:v h264_rkmpp -b:v 2500k -r 30 -g 60 -f flv rtmp://your-platform/live/streamh264_rkmpp就是让视频编码走到 RK3528 的 VPU 硬件单元而不是 CPU 软编。-g 60表示 2 秒一个关键帧适合低延迟播放。码率 2.5Mbps 在 1080p30 下观感足够也不会给网络造成压力。如果是网络摄像头 RTSP 拉流并同时输出多种协议可以先把拉流进程做成一个内部源ffmpeg -i rtsp://192.168.1.64:554/stream1 \ -c:v copy -c:a copy -f flv tcp://127.0.0.1:4090这样就让流媒体网关从tcp://127.0.0.1:4090读取已经接入的 RTSP 流再对外统一分发成 RTMP、HLS、WebRTC 等协议。copy表示不重新编码几乎不消耗 CPU。2.4 为什么要保留 RTSP 输出很多人会忽略 RTSP 输出但直播现场经常需要把画面回给监视器或者原有监控系统。例如一面背景墙、一块大屏播放端往往只认 RTSP。保留这个协议让 MEDAI V2 既能从 RTSP 摄像头拉流也能把处理后的画面以 RTSP 输出就省掉了一个转接设备。实测 RTSP 输出延迟在 0.5~3 秒内用于本地监看完全够用。3. 硬编硬解怎么把 RK3528 的 VPU 吃干榨净3.1 先摸清楚 VPU 的能力边界RK3528 的 VPU 是分开的解码单元和编码单元。解码能力明显强于编码4K 级别的高码率流也能解编码更倾向于 1080p 级别如果强行做两路 1080p 重编码内存和带宽都会吃紧。在 MEDAI V2 里我给硬件编解码定了几条使用原则解码优先用硬解通过rkmpp直接输出到 DRM 或内存帧不要先去 CPU 拷贝一圈。编码只在“必须重新编码”时使用例如绿幕合成、AI 处理后或者上游流格式不兼容输出端。如果最终输出端都支持同样编码格式尽量走copy模式不碰 VPU。为什么不无条件硬编因为 VPU 编码会引入 GOP 结构和参考帧重排对低延迟场景不友好。copy模式等于透传原始码流延迟最低内存占用最小。3.2 硬解硬编的零拷贝链路低配置设备上最容易忽略的是内存拷贝。视频一帧 1080p YUV 数据约 3MB30 帧就是 90MB/s。如果在 VPU、CPU、网络各环节之间反复拷贝内存带宽很快耗尽延迟也会拉高。正确做法是尽量让帧数据在同一个内存区域流转网络/摄像头 - VPU 硬解 - DRM Prime 帧 - FFmpeg filter - VPU 硬编 - 协议封装 - 网络输出FFmpeg 中可以用-hwaccel rkmpp -hwaccel_output_format drm把解码帧直接以 DRM 格式交给下游。如果需要做绿幕再把 DRM 帧映射到 CPU 可访问的内存段。这样大部分路径是零拷贝只有绿幕像素变换时发生一次性访问。一个典型的硬解硬编命令ffmpeg -hwaccel rkmpp -hwaccel_output_format drm -i rtsp://camera/stream \ -c:v h264_rkmpp -b:v 2000k -f flv rtmp://target/live/app这套命令在 MEDAI V2 上跑 1080p30 时CPU 占用通常只有 10%~15%多数时间在等待 VPU 返回。3.3 缓冲队列和丢帧策略直播最怕“累积延迟”。当网络抖动时如果接收端缓冲队列设置过大画面会越来越慢最终延迟失去意义。我建议把每个环节的缓冲队列控制在固定帧数以内解码队列最大 4 帧。处理后队列最大 3 帧。编码输入队列最大 2 帧。网络发送队列由 socket buffer 控制不做应用层大缓存。如果队列满了优先丢旧帧不丢新帧。视频编码里参考帧依赖需要连续性但丢帧总比延迟爆炸好。可以通过 AVFilter 里的settbfps和fps滤镜配合控制帧率或者直接调 VPU 编码器的输入队列长度。3.4 B 帧对延迟的影响低延迟直播编码时我一般会关闭 B 帧或者限制 B 帧数量为 0。B 帧需要等待前后帧都编码完才能输出重排会显著增加延迟。在 FFmpeg 里硬编码参数通常可以设置-c:v h264_rkmpp -profile:v high -g 60 -sc_threshold 0 \ -b:v 2500k -maxrate 2500k -bufsize 500k-g 60控制关键帧间隔-sc_threshold 0关闭场景检测避免编码器突然插入非预期关键帧。对 RTMP 或 SRT 输出这些都直接关系到起播速度和端到端延迟。4. AI 与绿幕低成本设备上的抠像实践4.1 绿幕优先AI 只能做补充标题里同时出现“AI”和“绿幕”很多人以为必须用 AI 才能抠像。实际上传统绿幕抠像用的色度键算法极其成熟而且开销远小于 AI 人像分割。在 1GB 内存设备上第一选择应该永远是绿幕。绿幕原理很简单把画面从 RGB 转到 YCbCr 色彩空间只要某个像素的 Cb、Cr 颜色分量接近预设的背景绿色就认为它是背景替换成新背景画面。这个算法是逐像素操作非常适合 SIMD 优化CPU 完全能应付。AI 人像分割更适合没有绿幕的复杂背景但轻量模型也要几百 MB 甚至上 GB 的算力资源。因此在 RK3528 上我把 AI 定位成“应急方案”绿幕效果不好、或者需要跟拍移动主播且背景不定时才启用 AI 隔帧分割。4.2 绿幕抠像的像素级实现在 MEDAI V2 里绿幕处理不是简单把绿色变透明而是做了容差、羽化和去色溢三层处理。伪代码大概是for each pixel: y, cb, cr rgb_to_ycbcr(pixel) dist sqrt((cb - bg_cb)^2 (cr - bg_cr)^2) if dist low_threshold: alpha 0.0 else if dist high_threshold: alpha (dist - low) / (high - low) // 边缘羽化 else: alpha 1.0 output foreground * alpha new_bg * (1 - alpha)low_threshold和high_threshold决定了抠像边缘的软硬度。如果直接一刀切边缘会有严重锯齿如果羽化区间太大头发和透明边缘容易发虚。我的经验是low40high90并针对不同灯光环境做一次标定。去色溢则必须对保留的前景边缘做处理。绿色背景会产生绿色环境光反射到人肩膀、头发上看起来就是一圈“绿毛边”。我采用的方法是只对 alpha 处于 0 到 1 之间的过渡像素把 Cb、Cr 向中性色方向拉近一点。4.3 用彩色键分离替代背景建模还有一个小技巧如果直播场景中主播需要经常走动而绿幕又不够大可以用“双重色键”。背景设置成两种不同饱和度的绿先抠掉一个范围再在另一侧保留一条“虚拟地线”让主播脚底产生投影。这一步在 CPU 上只需多遍历一遍像素但效果非常明显。这个流程可以用 AVFilter 的chromakey滤镜实现也可以用自定义滤镜实现。MEDAI V2 里我建议把滤镜注册为 FFmpeg 自定义 filter方便复用ffmpeg -hwaccel rkmpp -i input.mp4 \ -vf chromakey0x00FF00:0.2:0.1,padiw:ih40:0:20:black \ -c:v h264_rkmpp -f flv rtmp://target/live0.2是相似度容差0.1是平滑度。不同环境要反复测试没有一组参数是万能的。4.4 AI 人像分割的“隔帧光流”策略实在需要 AI 时我的做法是控制频率而不是全速跑。以 720p 为例轻量分割模型在 RK3528 的 CPU 上大约只能跑到 10~15 帧每秒。如果直播源是 30 帧就让 AI 每隔 2 帧算一次 mask中间帧用上一帧 mask 补上再用简单边缘追踪修正。这样实际 AI 处理量降到了 720p 10 帧左右CPU 不会被打满内存也能控制在 100MB 以内。虽然画质比不了高配电脑上的逐帧分割但直播流畅度优先观众不会盯着边缘像素看。另一个取舍是模型量化。把模型从 FP16 量化到 INT8 后体积和内存占用都能明显下降代价是分割边缘会毛糙一些。可以用形态学开闭运算和羽化把瑕疵压下去最终效果在手机端看基本够用。4.5 合成后的编码注意点抠像处理后会得到 RGBA 或 YUV 帧编码前需要先转成 VPU 需要的格式。这里的坑是色彩范围不一致有些摄像机输出 limited range有些输出 full range。编码参数里如果没有指定画面容易发灰或者过曝。建议在滤镜链后面加-vf chromakey...,formatyuv420p,setparamsrangelimited硬编码器输入格式必须严格匹配否则 VPU 会拒绝编码或者在画面边缘产生奇怪的条纹。5. 性能调优与稳定性记录5.1 CPU 绑核与中断隔离四核 A53 看起来 CPU 资源不多但乱用反而容易性能抖动。我把 CPU 规划分成三组CPU0系统中断、网关主进程、Web 管理。CPU1~2FFmpeg 解码、绿幕滤镜、编码任务。CPU3AI 推理、SRT/WebRTC 网络线程。用 taskset 把不同服务固定到核心能有效避免线程在核间迁移带来的缓存失效taskset -c 1-2 /opt/medai/ffmpeg -i ... taskset -c 3 /opt/medai/ai-worker注意taskset只能做 CPU 亲和性更严格的做法还要设置中断亲和性。千兆网卡的中断如果一直打在 CPU0网络吞吐高时会影响管理端响应。可以通过/proc/irq/{irq}/smp_affinity把网卡中断也挪到 CPU1实测网络抖动明显减少。5.2 网络缓冲和 socket 调优直播对网络的敏感程度远超一般应用。RK3528 的千兆网口性能是够的但应用层默认 socket buffer 可能不够。遇到高码率推流时建议调大收发缓冲sysctl -w net.core.rmem_default26214400 sysctl -w net.core.wmem_default26214400 sysctl -w net.core.rmem_max67108864 sysctl -w net.core.wmem_max67108864同时关闭 TCP 的自动调优限制避免突发流量时缓冲不足。对于 SRT 和 WebRTC 这类基于 UDP 的协议还需要开启优雅关闭和协议层的拥塞控制不然弱网环境下延迟会忽高忽低。5.3 长时间运行的稳定性设计低成本设备长时间跑直播最容易死机的原因不是 CPU 过载而是内存碎片、日志暴涨和散热。我做了三件很管用的事给 FFmpeg 和网关设置 cgroup 内存上限。一旦超过上限杀掉最不重要的输出通道而不是让整个系统被 OOM killer 随机处理。日志轮转最多保留 3 天并通过 logrotate 压缩。直播现场经常没人盯着看日志写满存储卡会导致系统卡死。使用硬件看门狗每 30 秒喂狗一次。如果进程卡死看门狗自动重启服务不中断市电也能快速恢复。一个更深层的坑是 SD 卡或 eMMC 的寿命。直播会产生大量日志和临时文件连续写入很容易损耗存储。我建议把所有临时文件放内存tmpfs摄像头的片段录制也单独挂一块可更换的移动存储盘不要长时间折磨系统盘。5.4 实测数据参考我在 MEDAI V2 上跑过一组比较典型的混合场景一路 1080p30 RTSP 摄像头输入同时分发 RTMP、HLS、WebRTC、HTTP-FLV 输出再叠加绿幕抠像。结果如下指标实测值系统空载内存约 180MB六协议全部启动后内存约 320MB绿幕处理内存增量约 80MB1080p30 硬编码 CPU 占用约 12%~15%绿幕处理 CPU 占用约 35%~40%端到端延迟WebRTC约 500msRTMP 到播放器首帧 800ms连续运行时间48 小时无重启这个结果说明只要分工合理1GB 内存并不是不可逾越的门槛。6. 常见问题与排查实录6.1 RTMP 推流高延迟或断流现象是高负载时 RTMP 输出延迟从 3 秒慢慢涨到 10 秒然后连接断开。大多数原因不是网络而是关键帧间隔过长或编码队列堆积。先检查-g参数再看编码器是否因为 B 帧重排导致帧乱序。把-g设成帧率的 1~2 倍同时开启-flush_packets 1实测能明显缓解。6.2 WebRTC 花屏或无法播放WebRTC 需要信令服务协调 SDP很多盒子上跑不起来是因为 UDP 端口受限或浏览器没有正确协商。排查思路是先确认信令通道是否正常再检查 UDP 端口是否被防火墙拦截。另外 RK3528 硬编出的 H.264 可能是 Annex-B 格式而 WebRTC 需要 AVCC 格式的封装必须在封装层做转换。6.3 绿幕边缘发绿如果人像边缘泛绿基本不是算法问题而是色键容差太宽把头发丝和外套边缘的绿色也误判成背景。把相似度容差调小同时提高羽化平滑度。另一个问题是绿幕布褶皱产生的阴影阴影区域的绿色值偏低会被判定为前景。解决办法就是熨平背景布、均匀布光或者把背景色值作为动态标定而不是固定0x00FF00。6.4 系统突然 OOMOOM 大多时候不是因为某个进程瞬间占用过多而是内存碎片累积。长时间运行后FFmpeg 的动态滤镜链会不断申请和释放小内存块。我最终用预分配缓冲池解决启动时一次性申请好 1080p 处理所需的帧缓冲运行中不再动态申请大块内存。这个改动之后48 小时跑下来内存碎片非常稳定。6.5 硬编 H.265 失败RK3528 的硬编虽然支持 H.265但在低码率低延迟模式下画质和兼容性不如 H.264。如果输出目标是网页播放或移动端我建议默认走 H.264只有在需要保存本地录像或高压缩比时才切 H.265。硬编失败时FFmpeg 日志会报rkmpp相关错误先确认编解码器有没有被正确初始化再看内核态驱动版本是否匹配。最后分享一点个人感受这套 MEDAI V2 折腾下来最大的体会是低配硬件做直播重点不在“堆配置”而在“减少不必要的工作”。能用 copy 就不转码能走硬解就不让 CPU 碰帧能离线标定绿幕就不实时跑 AI。很多问题不是硬件扛不住而是架构没有给硬件留余地。RK3528 可能不是最强的直播芯片但在低成本和低功耗这个维度上它确实能挤出不少惊喜。下一步我打算加一个双网口配置把 SRT 回传和本地输出彻底分开到时候再回来补充实测数据。