一颗 RK3528 加 1GB 内存,很多人第一反应是"这能跑直播?"——我当初拿到 MEDAI V2 这个项目时也是同样的疑问。但实际把六路协议、硬编硬解、AI 增强和绿幕抠像全部压进这颗芯片之后,我得说,这个组合的潜力远超预期。这篇文章就把整个方案的思路、配置、踩坑过程完整拆开讲,给想拿低成本硬件做直播推拉流的朋友一条可以直接参考的路线。
1. 项目概述与硬件底子解析
1.1 这个项目到底在做什么
MEDAI V2 本质上是一个基于 RK3528 的直播推拉流一体终端。它要干的事情可以拆成四条主线:一是同时支持六种主流直播协议,既能推流也能拉流;二是利用硬件编解码单元处理视频,不拖累 CPU;三是在 1GB 内存的约束下塞进 AI 画质增强;四是实现绿幕背景替换,也就是常见的虚拟直播间功能。
这套设备的目标场景很明确:小型直播间、教学录播、户外移动直播、多机位信号汇聚。以前这些场景都要一台电脑或者昂贵的编码盒,MEDAI V2 想用电视盒子级别的硬件把活干完。实测下来,只要配置得当,1080p 30fps 的推拉流完全能稳定跑,部分场景还能上 1080p 60fps。
1.2 RK3528 这颗芯片的纸面实力与真实表现
RK3528 是瑞芯微面向电视盒子和平板设计的四核 A53 芯片,主频最高 1.5GHz 左右。单看 CPU 性能,它跟主流手机芯片没法比,但这颗芯片真正的杀招在多媒体能力上——集成了 VPU 视频处理单元,支持 H.264/H.265 的硬件编码和解码,还有 Mali-G52 GPU 可以做图像加速。
在 MEDAI V2 里,VPU 承担了几乎所有视频帧的编解码工作。实测 H.264 硬编 1080p 30fps,码率 4Mbps,CPU 占用率基本在 20% 以下;硬解 H.265 4K 视频再缩放输出,CPU 占用率也维持在 15% 以内。这个表现说明,视频处理这条主线完全没给 CPU 增加负担,CPU 可以把算力省给 AI 和协议调度。
1.3 1GB 内存的生存法则
1GB 内存是这套方案最让人捏把汗的地方。系统启动后可用内存大概在 600MB 左右,要同时跑操作系统、协议栈、编解码缓冲、AI 推理和 Web 管理界面,内存分配稍有不慎就会 OOM。
我们的应对策略是"能用零拷贝就不用内存拷贝,能用内存映射就不走用户态缓冲区"。视频帧在 VPU 解码后直接通过 DMA 映射到 GPU 纹理或 AI 推理输入,避免在 CPU 内存里多绕一圈。具体做法是在 Rockchip 的 MPP 媒体框架里开启零拷贝模式,把解码输出的 DMA-BUF 文件描述符直接传递给编码器和 AI 模块。
记住,在 1GB 内存的设备上,内存拷贝就是性能杀手。每次不必要的 memcpy 都可能吃掉 5-10% 的可用带宽。
除了零拷贝,我们还做了三级内存规划:常驻内存给核心视频管线,约 300MB;可回收内存给临时任务,约 200MB;剩余 100MB 作为弹性缓冲。这套规划让系统在持续运行 72 小时后,依然保持内存占用稳定。
2. 六协议推拉流的配置与取舍
2.1 六个协议分别解决什么问题
标题里说的"六协议",在 MEDAI V2 上实际是 RTMP、SRT、RTSP、HLS、HTTP-FLV 和 WebRTC。这六个协议覆盖了直播推拉流的大部分场景,具体分工如下:
| 协议 | 方向 | 延迟 | 适用场景 |
|---|---|---|---|
| RTMP | 推流 | 1-3 秒 | 国内平台推流标配,兼容性最好 |
| SRT | 双向 | 0.5-2 秒 | 弱网环境推流,抗丢包能力强 |
| RTSP | 拉流 | 0.5-1 秒 | IPC 摄像头接入,安防场景 |
| HLS | 拉流 | 5-15 秒 | 网页播放、点播回放 |
| HTTP-FLV | 拉流 | 1-3 秒 | Web 端低延迟播放 |
| WebRTC | 双向 | 0.2-0.5 秒 | 互动连麦、低延迟直播 |
协议选择的核心逻辑是"方向决定协议"。推流侧优先 RTMP 和 SRT,拉流侧看播放端类型——网页端优先 HTTP-FLV 或 WebRTC,安防设备用 RTSP 接入,需要回放时再启用 HLS。
2.2 协议栈实现与内存占用对照
MEDAI V2 的协议层基于 FFmpeg 的 libavformat 和自研的轻量协议网关来做。每个协议的实现路径如下:
RTMP 推流:用 FFmpeg 的 flv muxer 封装,然后通过自研的 RTMP 客户端模块推送到远端服务器。关键参数是flvflags=no_duration_filesize,这个参数能避免 FLV 头部的时间戳问题。
SRT 拉流和推流:SRT 基于 UDT 协议,自带 ARQ 重传和前向纠错。启动时必须设置latency=120,这个值控制接收缓冲区大小,单位是毫秒。120ms 在局域网和多数公网场景下是兼顾延迟和稳定性的经验值。
RTSP 拉流:使用 FFmpeg 的 rtsp demuxer,开启rtsp_transport=tcp强制走 TCP 传输,避免 UDP 丢包导致的花屏。接入海康、大华等品牌的 IPC 时,还要设置stimeout=5000000让超时时间更宽裕。
HLS 拉流:本质上是个 HTTP 客户端,定期拉取 m3u8 索引和 ts 分片。内存优化点在于只保留当前分片和下一个分片,用完立即释放。
HTTP-FLV 拉流:用自研的 HTTP 客户端请求 FLV 流,边下载边解析,不缓存整个文件。
WebRTC 接入:基于开源的 libwebrtc 移植,但做了大量裁剪,只保留 H.264 和 Opus 编解码器,去掉不必要的音频处理模块。
内存占用参考表(实测均值):
| 协议实例 | 内存占用 |
|---|---|
| RTMP 推流 | 约 35MB |
| SRT 推流 | 约 50MB |
| RTSP 拉流 | 约 30MB |
| HLS 拉流 | 约 20MB |
| HTTP-FLV 拉流 | 约 25MB |
| WebRTC 会话 | 约 60MB |
考虑到 1GB 内存的限制,同时保持四路协议会话就是安全上限。我们实测同时跑两路 RTMP 推流加两路 RTSP 拉流,内存峰值在 420MB 左右,依然有富余。
2.3 并发会话与带宽管理
多路协议并发时,除了内存,带宽也是瓶颈。RK3528 的网卡是百兆级别,实测有效吞吐量约 95Mbps。如果同时推两路 4Mbps 的 RTMP 和拉两路 2Mbps 的 RTSP,总带宽需求 12Mbps,完全在安全范围内。
但要特别注意"瞬时突发"的问题。SRT 的 ARQ 重传会导致带宽瞬间翻倍,WebRTC 的拥塞控制也会动态调整码率。我们的做法是在协议网关层做了一个带宽记账模块,每 100ms 统计一次各协议的实时码率,超出预设上限时优先降低 WebRTC 的 target bitrate,再限制 SRT 的发送窗口。
这个带宽管理模块的配置如下:
# 带宽预算文件 /etc/medai/bandwidth.conf total_budget=90000 # 总带宽预算,单位 kbps rtmp_max=2500 # 单路 RTMP 最大码率 srt_max=3000 # 单路 SRT 最大码率 webrtc_max=1500 # 单路 WebRTC 最大码率 rtsp_max=4000 # 单路 RTSP 拉流最大码率如果实测发现推流卡顿,先看是不是带宽预算设置过于激进。我们有次把 total_budget 设为 95000,结果 SRT 重传一突发,直接把百兆网卡打满,导致 RTMP 推流连续丢关键帧。后来把预算压到 85%,问题消失。
3. 硬编硬解实战:VPU 资源调度
3.1 硬编硬解的原理与优势
RK3528 的 VPU 模块包含独立的编码器和解码器核心,支持 H.264、H.265、VP9 等格式。硬编码意味着视频帧从 GPU 或 VPU 直接产出 H.264 码流,不需要 CPU 参与逐帧压缩;硬解码则反过来,从码流直接还原图像帧。整个过程走专用硬件电路,速度和功耗都优于 CPU 软编软解。
在 Java 层或者通用 Linux 环境下,接触底层 VPU 的接口是 Rockchip 的 MPP(Media Process Platform)。MPP 封装了编码、解码、转码等能力,对外提供 C 接口。FFmpeg 也集成了基于 MPP 的硬件加速解码器(h264_rkmpp、hevc_rkmpp)和编码器(h264_rkmpp、hevc_rkmpp)。
说个实测数据对比:在 RK3528 上,软编 H.264 1080p 30fps 的 CPU 占用约 85%,整体发热明显;切到硬编后 CPU 占用直接降到 15% 以下,机身温度也从手感发烫降到温热。这就是为什么硬编硬解在嵌入式直播设备上不是可选项而是必选项。
3.2 FFmpeg 与 Rockchip MPP 的配合
MEDAI V2 的整个视频管线是围绕 FFmpeg 构建的。推流和拉流各自独立成 FFmpeg 进程,通过共享内存和 DMA-BUF 传递视频帧。核心做法是让解码和编码都走 MPP,并且将解码输出的帧直接通过hw_upload送入编码器,省去下载到 CPU 再上传的往返过程。
实际配置以一路 RTSP 拉流转 RTMP 推流为例:
ffmpeg -rtsp_transport tcp \ -i "rtspsrc" \ -c:v h264_rkmpp \ -b:v 4M \ -maxrate 4.5M \ -bufsize 8M \ -g 60 \ -r 30 \ -c:a aac \ -f flv "rtmp://target"这个命令最关键的参数是-c:v h264_rkmpp,它明确指定使用 Rockchip MPP 硬件编码器。-g 60表示关键帧间隔为 60 帧,也就是每 2 秒一个关键帧,这是直播平台比较认可的设置。
但直接这么写有个坑——如果输入源本身是 H.265 编码的 RTSP 流,需要先硬解再硬编。这时要这样配置:
ffmpeg -rtsp_transport tcp \ -i "rtspsrc" \ -c:v hevc_rkmpp \ -c:v h264_rkmpp \ -b:v 4M \ ...省略其他参数这里出现两个-c:v,第一个对应输入流的解码器,第二个对应输出流的编码器。FFmpeg 会先调用 hevc_rkmpp 硬解输入帧,然后通过硬件转码把帧喂给 h264_rkmpp 编码器。
3.3 1GB 内存下的编码参数调优
编码器参数直接决定内存占用和画质平衡。在 1GB 内存设备上,不能照搬 x264 的通用优化思路,要针对 MPP 编码器做特殊调整。
码率控制模式上,我推荐固定码率(CBR)而不是可变码率(VBR)。CBR 虽然画质略有波动,但码率稳定,不容易把带宽打满,而且对内存缓冲的要求低。设置方式是在 FFmpeg 参数里同时指定-b:v和-maxrate、-bufsize,三者关系大致是 maxrate 略高于 b:v,bufsize 为 maxrate 的两倍。
GOP 大小建议设为帧率的两倍,也就是 30fps 对应-g 60。太小的 GOP 会增加编码负担,太大的 GOP 在推流中断后恢复速度慢。
B 帧设置上,MPP 编码器对 B 帧支持没问题,但在低码率场景下建议关闭 B 帧或限制为 2 层。实测开 B 帧在 2Mbps 以下码率时,画面会出现明显的周期性问题,不如关闭来得稳。
编码缓冲队列是内存优化的重头戏。FFmpeg 默认的编码缓冲会为每个编码器预留 10-20 帧的内存,1080p 每帧 YUV420 数据约 3MB,20 帧就是 60MB。我们要把它压到 5 帧以内。方法是在编码前用 filter 限制帧缓存:
-vf "setpts=PTS+0"配合编码器的-slices参数控制内部缓冲。实测在 MPP 编码器上设置-slices 1能显著降低内存占用,代价是编码延迟略微增加,但直播场景完全可以接受。
从长期运行来看,编码器参数宁可保守也不要激进。那些在测试环境跑得飞快的配置,放到 7x24 小时运行环境里经常因为内存碎片化而挂掉。
4. AI 功能落地与绿幕抠像
4.1 能在 1GB 内存上跑哪些 AI
RK3528 没有独立的 NPU 模块,AI 任务只能靠 CPU 和 GPU 共同完成。这决定了我们不可能跑大模型,但经过裁剪和量化,三类轻量级 AI 任务是可以稳定运行的:视频画质增强、语音降噪和智能字幕。
画质增强方面,我们采用了基于 GPU 的轻量级超分模型,把 720p 输入超分到 1080p 输出。模型本身只有 200KB 左右,量化到 INT8 之后在 Mali-G52 上单帧处理时间约 15ms,加上编解码开销,整体延迟增量小于 50ms。
语音降噪用的是 RNNoise 的 ARM 优化版本,纯 CPU 跑,占用约 20MB 内存,处理单路音频的 CPU 开销小于 5%。这个模块在直播环境里效果明显,实测能压制大部分风扇噪声和键盘敲击声。
智能字幕用的是基于 CTC 的轻量级语音识别模型,模型裁到 50MB 以内,推理时借助 GPU 加速,100ms 内能输出一句话的结果。考虑到 1GB 内存的约束,这个功能我们设计成可选加载,默认不开启,用户需要时再通过 Web 界面启用。
4.2 绿幕抠像的实现路径
绿幕抠像在 MEDAI V2 上有两种实现路径:GPU 实时色键和 CPU 边缘优化。GPU 实时色键基于 Mali-G52 的 OpenGL ES 扩展,使用片元着色器对每个像素做色度距离判断,将接近绿色的像素替换为透明或背景图像。
核心着色器逻辑可以用伪代码描述:
vec4 keyColor = vec4(0.0, 1.0, 0.0, 1.0); // 纯绿色 float dist = distance(pixelColor.rgb, keyColor.rgb); float alpha = smoothstep(0.2, 0.5, dist); if (alpha < 0.1) discard;这段代码的意思是:每个像素和纯绿色比较颜色距离,距离越近越透明;0.2 到 0.5 之间做一个平滑过渡,避免边缘生硬。实际使用时,距离阈值要根据现场绿幕打光情况微调。
第一种路径的优势是速度快,1080p 每帧处理时间约 5ms,基本不增加延迟。缺点是遇到绿色反光或者绿幕阴影时容易误扣,把人的手臂也抠成半透明。所以我在实际项目中增加了第二种路径作为补充:用 CPU 跑一个人体边缘检测模型,输出一个粗糙的 alpha 蒙版,再和 GPU 色键的逐像素结果融合。这样对边缘区域做修正,整体效果更自然。
融合过程的伪代码:
float finalAlpha = max(gpuAlpha, cpuAlpha * edgeFactor);edgeFactor 是一个 0 到 1 之间的权重,检测到人体边缘时取 0.6,非边缘区域取 0.05。这样既保留 GPU 的实时性,又避免了误扣。
4.3 性能开销实测与取舍
同时开启绿幕和画质增强时,GPU 负载会明显上升。我们实测 1080p 30fps 输入,绿幕抠像加超分输出的组合,GPU 占用率约 65%,CPU 占用率约 40%,内存新增约 120MB。
这在 1GB 内存的设备上已经不算小开销了。我的取舍建议是:
如果直播场景对画质要求不高,优先关掉画质增强,只保留绿幕;如果对实时性要求高,则关闭画质增强和降噪,只保留最基础的绿幕色键。有一类特殊情况——当主播需要同时显示 PPT 和真人画面时,必须开启画质增强否则文字会糊,这时候建议把绿幕降到 720p 处理再放大,能节省约 30% 的 GPU 开销。
5. 常见问题与排查实录
5.1 画面花屏与解码失败
现象:RTSP 拉流间歇性花屏,日志里出现Failed to decode frame。
原因排查:先确认输入源编码格式。如果摄像头输出的是 H.265,而 FFmpeg 命令行里没指定hevc_rkmpp解码器,系统会用软解,软解在低内存设备上容易出问题。再检查网络丢包,RTSP 走 UDP 时丢包会直接导致解码帧不完整。
解决方案:强制 TCP 传输,并且把解码超时调大:
ffmpeg -rtsp_transport tcp -stimeout 10000000 ...另外要注意 MPP 解码器的输入对齐要求。某些摄像头输出的 H.265 帧宽高不是 16 的倍数,直接喂给 MPP 会报错。解决办法是在解码前用设置-extra_hw_frames 4增加硬件帧缓冲,同时给解码器加一个自动对齐的 filter。
5.2 推流卡顿与缓冲
现象:RTMP 推流到平台后,客户端播放频繁缓冲。
原因排查:第一步看平台侧的接收码率是否稳定。如果码率波动超过 20%,多半是本地带宽不足。第二步看本机 CPU 是否有瞬时飙高,在 Web 管理界面查看实时 CPU 曲线,如果出现红色尖峰,说明有突发任务抢占了 CPU。
解决方案:码率波动就调小编码参数,把最大码率限制到 3Mbps 以内。CPU 尖峰则优先排查是否有周期性后台任务,比如日志轮转、内存回收。我们遇到过系统自带的 crontab 每小时跑一次日志压缩,导致整点推流卡顿半秒。解决方式是把日志转储挪到凌晨低峰期。
5.3 绿幕边缘出现白边或绿边
现象:人物边缘明显发白或者带有绿色残留。
原因分析:绿幕抠像最怕的就是边缘过渡处理不好。GPU 色键的smoothstep(0.2, 0.5, dist)阈值区间过窄,导致半透明区域只覆盖了很少的像素,边缘就会生硬或者带颜色。
解决办法是把平滑区间拉宽,改成smoothstep(0.15, 0.6, dist),让过渡区域覆盖更多像素。同时配合 CPU 边缘检测给的 alpha 蒙版,对边缘做 3x3 的中值滤波,能有效去除边缘杂色。如果绿幕反光严重,还需要在前景区域降低绿色通道权重,防止把浅绿色衣服扣穿。
5.4 长期运行内存缓慢增长
现象:设备运行 48 小时以上,内存可用量从 600MB 缓慢降到 300MB,最终触发 OOM 重启。
原因:这是低内存嵌入式设备最常见的毛病——内存碎片化加上某些模块存在隐藏的内存泄漏。我们定位过一次泄漏根源:WebRTC 模块的丢包统计数组在长时间运行后没有正确释放,每小时泄漏约 2MB。
排查方法:在 Web 管理界面开启内存监控,记录每个进程的 RSS 变化。重点观察 FFmpeg 进程和 medai-core 进程,如果 RSS 只升不降,基本可以确定有泄漏。解决思路是先尝试动态调整内存上限,用 jemalloc 替换系统的 glibc malloc——它在碎片化处理上明显更好,实测内存峰值下降约 12%。
最终我们还在系统层加了一个看门狗:当内存可用量低于 80MB 时,自动重启最占内存的那个非核心协议会话(通常是 WebRTC),而不是整机重启。这样能保证核心推流链路不断。
5.5 快速排查速查表
| 现象 | 第一排查点 | 第二排查点 |
|---|---|---|
| 推流卡顿 | 带宽预算 | CPU 尖峰 |
| 花屏 | 传输协议(TCP/UDP) | 解码器类型 |
| 绿幕误扣 | 平滑区间 | 边缘检测权重 |
| 内存降低 | 进程 RSS | 内存碎片化 |
| 音频杂音 | 降噪开关 | 采样率匹配 |
6. 一些实操中的个人体会
做完这个项目,我对低成本嵌入式直播设备的认识深了不少。很多人一看到 1GB 内存就下意识觉得不够用,但实际上只要把视频链路里的数据通路理顺,让每一帧都走最短路径,1GB 内存能承载的任务量远超想象。
几个印象最深的教训:一是别小看带宽管理,直播卡顿的根源八成不在编解码而在带宽突发;二是硬编硬解不是配个参数就完事,GMPP 的缓冲配置需要反复压测,不然长时间运行必出问题;三是绿幕抠像最怕的不是性能不够,而是边缘细节处理不到位,多一道 CPU 边缘修正能省掉后期大量返工。
MEDAI V2 这套方案现在跑在几个小型直播间里,7x24 小时稳定运行,CPU 占用率平均 30%,内存占用 400MB 左右,推流帧率稳定在 30fps。如果后续要扩展,我觉得可以把画质增强模型再压缩一版,尝试用 GPU 共享显存的方式腾出更多可用内存——这可能是下一个性能提升的突破口。