本节摘要:硬件之外的性能空间主要在并行。本节讲清 FFmpeg 的并行层次——帧级并行、滤镜并行、管道并行,给出 -threads、线程队列等参数的正确用法,并给出一套「先测速、再定位、后优化」的流程。
阅读完本节,你应当能够:
一台 16 核服务器,软转码默认只跑 4 线程,CPU 占用 25%——这是很多人第一次 top 时的惊讶。FFmpeg 的默认线程数远小于物理核数,原因有三:一是开线程有开销,二是编码器内部的并行收益有上限,三是无脑加线程反而引发内存竞争。所以「并行」不是越猛越好,而是「在哪并行、并多少」的问题。
编码器内部可以并行处理帧,-threads 控制线程数:
ffmpeg -i input.mp4 -c:v libx264 -threads 8 output.mp4
要点:
-threads 时,编码器按核数自动选(x264 默认接近核数)-threads,线程数是硬件管的某些滤镜(scale、yadif 去隔行)支持内部多线程,-filter_threads 控制滤镜图的线程数。处理 4K 缩放这类重滤镜时,提线程有明显收益:
ffmpeg -i 4k.mp4 -vf "scale=1920:1080" -filter_threads 4 output.mp4
多输入场景(比如同时读两个摄像头),一个输入慢了会堵住另一个。-thread_queue_size 给每个输入留缓冲队列:
ffmpeg -i cam1.mp4 -thread_queue_size 512 -i cam2.mp4 -filter_complex \ "[0:v][1:v]hstack=2" output.mp4
-thread_queue_size 512 让慢输入排队,快的输入不至于被拖死。
先测速再优化是本节最重要的方法。三步:
time ffmpeg -i input.mp4 -f null NUL(输出丢弃,只测处理速度)top 看 CPU 是否打满,nvidia-smi 看 GPU 占用,找出空闲的那一侧# 测速:丢弃输出,只看处理速度 time ffmpeg -i input.mp4 -c:v libx264 -f null NUL
输出里会显示速度,如 speed=2.5x——意思是比实时快 2.5 倍。直播要求 ≥1x,批量转码越快越好。
-c copy 的尽量 copy,别重编码-preset 换速度(第 5 章讲过)iostat 看磁盘占用线程数、队列数不是越大越好:
用一张图总结三种并行层次与适用场景:

编解码并行管「压缩引擎内部」,滤镜并行管「加工工位」,管道并行管「多路输入调度」。优化的总顺序是「先测速 → 再定位 → 后优化」,避免凭感觉乱调。
⚠️ 常见坑:硬编不吃 -threads(线程由硬件控制);多输入忘记 -thread_queue_size 会导致「一路卡、全路卡」;
-f null NUL在 Windows 上必须是 NUL,Linux 是 /dev/null,写反会真的写文件。
💡 关键直觉:并行的目的是「把闲置资源用起来」,不是「把参数调大」。先确认哪一侧空闲,再决定加什么,才是高效的优化路径。
某转码服务处理 1080p 视频一直只有 0.8x 的速度,也就是转码比播放还慢。排查发现 CPU 只用了 30%,磁盘 IO 却几乎打满。问题不在编码,而在输入输出:一边从慢速磁盘读原文件,一边往同一块磁盘写多个输出文件,读写互相抢道。
解法不是加线程,而是把「读、转、写」拆开:输入放 SSD 或内存盘,输出先写临时文件,全部完成后再移动到最终存储。改完之后速度直接提到 2.5x。这个案例的启示是:性能瓶颈往往不在你以为的地方,top 看到 CPU 空闲,不代表机器闲着——磁盘、内存、锁都可能是瓶颈。先测速、再定位、后优化,这条路径在任何性能问题上都适用。
在讨论任何优化方案之前,先给自己的机器建一个「基准分」。方法很简单:
# 看机器有多少核,作为并行的上限参考 nproc # 给一个标准转码任务计时,作为性能基线 /usr/bin/time -v ffmpeg -i input.mp4 -c:v libx264 -crf 23 -f null NUL 2>&1 | grep -E "Elapsed|Maximum resident"
记下这个数字。以后每次改参数、加线程、换编码器,都跑同一个任务对比时间——提升或恶化一目了然。这个「同任务对比」的习惯,比任何优化技巧都重要:它让你告别「感觉快了」「好像更卡了」的模糊判断,改用数字说话。
优化不是一次性的冲刺,而是持续的小步改进:每次改一个变量,跑一次基准,记录结果,再改下一个。这种工作方式在团队协作里尤其有价值——你可以用基准数据说服同事,而不是靠争论。
下一节,从命令行工具切换到 API——第 8 章 SDK 二次开发。