
1. 项目缘起与整体设计思路1.1 为什么偏偏是 FFmpeg音视频处理这个领域工具链多到让人眼花缭乱但真正能称得上“瑞士军刀”的FFmpeg 说第二没人敢说第一。我做流媒体相关项目差不多有十来年从最早用命令行转个 MP4到后来做直播转码、多路推流、边缘计算盒子绕来绕去最后发现最底层、最可靠、最不挑环境的还是它。FFmpeg 本质上是一套完整的音视频处理框架包含 libavcodec编解码、libavformat封装解封装、libavfilter滤镜、libswscale图像缩放、libswresample音频重采样等核心库外加 ffmpeg、ffprobe、ffplay 三个命令行工具。它的能力覆盖了从采集、解码、滤镜、编码到推流的全链路而且跨平台支持极好Linux、Windows、macOS、各种嵌入式 ARM 平台都能跑。这次项目的核心目标很明确在一台重量只有 118 克的迷你盒子上实现 5 路 RTMP 同时推流。这个需求听起来简单但真正落地时会遇到一堆问题——CPU 算力有限、内存紧张、网络带宽要分配、散热要控制、每路流的参数要独立可调。所以整体设计思路必须围绕“轻量、稳定、可扩展”三个关键词展开。1.2 118 克盒子意味着什么118 克是什么概念大概就是两个鸡蛋的重量。这么小的设备通常是一块 ARM 架构的开发板或者迷你主机CPU 核心数不会太多内存可能只有 1GB 到 4GB存储靠 eMMC 或者 TF 卡。它的优势是功耗低、体积小、可以贴在显示器背面或者塞进弱电箱适合做边缘节点。但劣势也很明显没有独立显卡做硬件编码纯靠 CPU 软编的话5 路 1080p 推流基本不可能。所以方案设计时必须考虑硬件编码器比如很多 ARM 芯片自带的 H.264/H.265 硬编模块通过 FFmpeg 的h264_v4l2m2m、h264_omx或者厂商提供的h264_rkmpp等接口调用。如果硬件编码器不支持那就得把分辨率降到 720p 甚至 480p帧率降到 15 到 20 帧用 x264 的 ultrafast 预设硬扛。这里有个经验不要迷信参数表上的“支持 4K 编码”实际多路并发时硬件编码器的通道数、码率上限、内存带宽都会成为瓶颈。我一般会先跑单路压力测试再逐步加到 5 路观察 CPU 占用、内存增长和温度变化。1.3 MEDAI V2 在架构中的角色MEDAI V2 在这个项目里扮演的是“调度中枢”的角色。它不是一个单纯的推流工具而是一套媒体处理与分发框架负责管理多路输入源、协调 FFmpeg 进程、监控推流状态、处理异常重启并且提供统一的配置接口。为什么不用纯脚本因为 5 路推流涉及进程管理、日志收集、断线重连、资源隔离纯 bash 脚本写到后面会变得难以维护。MEDAI V2 把这些逻辑封装成服务每路流是一个独立的任务单元互不干扰。某一路崩溃了只重启那一路不会影响其他四路。同时它还能做码率自适应根据网络状况动态调整编码参数。整体架构可以理解为输入源摄像头、视频文件、屏幕采集→ MEDAI V2 任务调度 → FFmpeg 编解码与推流 → RTMP 服务器。MEDAI V2 负责前端的配置解析和后端的进程守护FFmpeg 负责真正的音视频处理。2. FFmpeg 核心原理拆解与关键参数解析2.1 从输入到输出FFmpeg 的数据流水线理解 FFmpeg 的工作流程是调优和排错的基础。它的处理链路可以简化为解封装 → 解码 → 滤镜处理 → 编码 → 封装 → 输出。每一步都有对应的库和参数控制。以一路 RTMP 推流为例如果输入是本地摄像头流程是V4L2 采集 → 原始 YUV 帧 → 缩放/裁剪 → H.264 编码 → FLV 封装 → RTMP 推送。如果输入是视频文件则先经过解封装分离出音视频流再分别解码。这里的关键在于FFmpeg 是流水线作业各环节可以并行。比如解码第 N 帧的同时编码第 N-1 帧推流第 N-2 帧。所以 CPU 占用不是简单叠加而是取决于最慢的那个环节。调优时要用ffprobe看输入流信息用-benchmark看各环节耗时找到瓶颈。2.2 编码器选型软编与硬编的取舍编码器是资源消耗大户选型直接决定能跑几路。常见选项有编码器类型优点缺点适用场景libx264软编画质好、参数丰富CPU 占用高路数少、画质优先h264_v4l2m2m硬编CPU 占用低参数受限、兼容性差ARM 盒子多路推流h264_rkmpp硬编瑞芯微平台效率高依赖厂商库特定芯片方案h264_nvenc硬编速度快需要 NVIDIA 显卡x86 服务器在 118 克盒子上首选硬编。如果硬编不可用退而求其次用libx264的ultrafast预设配合-tune zerolatency降低延迟。实测下来4 核 ARM 芯片跑 5 路 720p15fps 的 ultrafast 软编CPU 占用大概在 70% 到 85% 之间勉强能撑住但温度会比较高。2.3 关键参数码率、帧率、GOP 与分辨率这几个参数互相制约调一个就要动其他。码率决定画质和带宽帧率决定流畅度GOP 决定延迟和 seek 性能分辨率决定像素总量。对于 5 路 RTMP 推流我一般这样分配每路 720p、25 帧、码率 1500kbps、GOP 50。这样 5 路总上行带宽约 7.5Mbps普通百兆宽带完全够用。如果网络紧张降到 480p、20 帧、800kbps总带宽 4Mbps。GOP 设置有个技巧RTMP 推流建议 GOP 等于帧率的 2 倍比如 25 帧就设 50。这样关键帧间隔 2 秒既保证秒开又不会因为关键帧太密集而浪费码率。-g 50配合-keyint_min 50可以强制固定 GOP。2.4 滤镜链缩放、裁剪与水印多路推流时不同输入源的分辨率可能不一样需要统一到目标分辨率。用scale滤镜做缩放crop做裁剪drawtext加水印。比如把 1080p 输入缩放到 720p-vf scale1280:720:force_original_aspect_ratiodecrease,pad1280:720:(ow-iw)/2:(oh-ih)/2。这里用pad补边避免画面变形。如果要做画中画可以用overlay滤镜叠加。滤镜链会消耗 CPU尤其是scale和overlay。在盒子上尽量用硬件缩放或者把滤镜放在编码之前让硬编模块处理。实测scale用fast_bilinear算法比默认的bicubic快不少画质损失可接受。3. 五路 RTMP 推流实操全流程3.1 环境准备与依赖安装盒子上通常预装的是精简版 Linux需要先补依赖。以 Debian 系为例sudo apt update sudo apt install -y ffmpeg v4l-utils alsa-utils如果系统自带的 FFmpeg 版本太老不支持某些硬编接口就需要自己编译。编译时开启需要的模块./configure --enable-gpl --enable-libx264 --enable-libfreetype \ --enable-v4l2-m2m --enable-omx --enable-rkmpp --enable-nonfree make -j4 sudo make installMEDAI V2 的安装一般提供一键脚本但要注意它依赖 Python 3.8 以上和psutil、requests等库。安装完后先跑medai --version确认。注意自己编译 FFmpeg 时--enable-nonfree会影响分发许可内部项目无所谓对外发布要留意。3.2 单路推流命令拆解先跑通一路再复制到五路。基础命令ffmpeg -re -stream_loop -1 -i input.mp4 \ -c:v h264_v4l2m2m -b:v 1500k -maxrate 1500k -bufsize 3000k \ -vf scale1280:720 -g 50 -r 25 \ -c:a aac -b:a 128k -ar 44100 \ -f flv rtmp://server/live/stream1逐段解释-re按原始帧率读取避免推流过快-stream_loop -1循环输入-c:v指定编码器-b:v目标码率-maxrate和-bufsize控制码率波动-gGOP 大小-r帧率-c:a音频编码-f flv封装格式最后是推流地址。如果输入是摄像头把-i input.mp4换成-f v4l2 -i /dev/video0并加上-input_format mjpeg或yuyv422指定采集格式。3.3 MEDAI V2 多路任务配置MEDAI V2 的配置文件一般是 YAML 或 JSON。五路任务的核心结构tasks: - name: stream1 input: /dev/video0 output: rtmp://server/live/stream1 encoder: h264_v4l2m2m resolution: 1280x720 bitrate: 1500k fps: 25 - name: stream2 input: /dev/video1 output: rtmp://server/live/stream2 encoder: h264_v4l2m2m resolution: 1280x720 bitrate: 1500k fps: 25每路独立配置互不干扰。MEDAI V2 启动后会为每个任务生成一个 FFmpeg 子进程并监控其状态。如果某路退出码非零自动重启重启间隔可设 3 秒避免频繁重启导致资源耗尽。3.4 资源分配与并发调优5 路并发时资源分配要精细。CPU 方面可以用taskset把不同任务绑到不同核心减少上下文切换。内存方面每路 FFmpeg 大概占 50MB 到 100MB5 路就是 500MB加上系统本身2GB 内存够用。网络方面5 路 RTMP 推流是 5 个 TCP 连接每个连接独立。如果上行带宽有限可以开-maxrate限制峰值或者用-bufsize平滑发送。实测在 10Mbps 上行下5 路 1500kbps 推流很稳偶尔波动也能靠缓冲区扛过去。温度控制也不能忽视。118 克的盒子通常没有风扇靠被动散热。连续推流 2 小时后芯片温度可能到 70 度以上。可以在 MEDAI V2 里加温度监控超过阈值就降帧率或暂停某路。4. 常见问题排查与避坑经验4.1 推流失败与断线重连最常见的问题是推流地址不通或者鉴权失败。先用ffplay rtmp://server/live/stream1测试服务器是否正常。如果服务器要求推流密钥地址要写成rtmp://server/live/stream1?keyxxx。断线重连方面FFmpeg 本身有-reconnect系列参数但只对 HTTP 输入有效RTMP 输出不支持。所以重连逻辑要放在 MEDAI V2 层检测到进程退出就重启。我一般设 3 次快速重试加 1 次慢速重试避免网络抖动时疯狂重启。4.2 音画不同步与延迟累积音画不同步通常是因为音频和视频的时间基不一致或者编码器缓冲不同。解决办法是加-async 1让音频对齐视频或者用-vsync cfr强制恒定帧率。延迟累积多发生在长时间推流后原因是时间戳漂移。可以加-fflags genpts重新生成时间戳或者定期重启进程。实测连续推流 12 小时后延迟可能增加 1 到 2 秒重启后恢复。4.3 硬编接口报错与兼容性硬编接口报错很常见比如h264_v4l2m2m提示Device or resource busy说明设备被占用可能是上一路进程没退干净。用fuser /dev/video0查占用进程杀掉再重启。还有的芯片硬编不支持 B 帧需要加-bf 0。不支持某些分辨率需要缩放到支持的值。这些都要查芯片手册或者用ffmpeg -h encoderh264_v4l2m2m看支持的参数。4.4 常见问题速查表现象可能原因排查方法解决推流失败地址错误/鉴权失败ffplay 测试检查地址和密钥画面卡顿码率过高/网络差看上行带宽降码率或分辨率音画不同步时间基不一致ffprobe 看流信息加 -async 1进程频繁重启资源不足/崩溃看日志和 dmesg降并发或加内存温度过高散热不足读温度传感器降帧率或加散热片提示日志一定要开-loglevel warning不然 5 路日志会把磁盘写满。MEDAI V2 支持日志轮转记得配置。5. 性能实测与扩展思路5.1 五路并发实测数据在某 ARM 四核盒子上实测5 路 720p25fps、1500kbps 硬编推流CPU 平均占用 45%内存占用 680MB芯片温度稳定在 65 度连续运行 24 小时无断流。如果换成软编 ultrafastCPU 占用飙到 90% 以上温度 80 度只能跑 3 路。网络方面5 路总上行 7.5Mbps在 20Mbps 宽带上很轻松。如果宽带只有 10Mbps建议降到 480p 或者 4 路。5.2 从 5 路到更多路的扩展想跑更多路要么换更强的盒子要么降低单路参数。另一个思路是分布式多个盒子各跑几路由中心节点统一调度。MEDAI V2 支持集群模式可以横向扩展。还可以考虑用 SRT 替代 RTMPSRT 抗丢包更好适合不稳定网络。FFmpeg 支持-f mpegts srt://...输出但需要服务器端也支持 SRT。5.3 个人实操体会这个项目踩过的坑不少最大的体会是不要一上来就调 5 路先跑 1 路稳定了再加。每加一路观察 10 分钟看 CPU、内存、温度、网络的变化。参数不要照搬网上的不同芯片、不同系统差异很大必须自己实测。另外MEDAI V2 的配置最好版本化管理每次改动记录清楚出问题能快速回滚。盒子的系统盘要留足空间日志和临时文件定期清理。最后散热真的重要贴个散热片或者加个小风扇稳定性会好很多。