3、效率评估指标:编码速度、CPU/GPU利用率、内存占用、编码延迟
聊完质量,咱们得聊聊「效率」。说白了,就是你的机器为了转出这个视频,到底付出了多少代价。
我见过不少团队,一上来就追求最高画质,结果一条4K片子转了一天一夜。客户问「好了没?」你只能说「还在跑...」这种尴尬,我经历过太多次了。
所以这一章,咱们把效率拆开来看。四个核心指标:编码速度、CPU/GPU利用率、内存占用、编码延迟。你把这四个吃透了,调优才有方向。
3.1 编码速度:到底有多快?
编码速度最直观。FFmpeg里有两个常用参数:-benchmark 和 -benchmark_all。
ffmpeg -i input.mp4 -c:v libx264 -preset medium -benchmark output.mp4
跑完之后,你会看到类似这样的输出:
bench: utime=125.3s stime=8.7s rtime=134.2s
bench: maxrss=142352kB
这里 rtime 就是实际耗时(real time)。utime 是用户态CPU时间,stime 是内核态CPU时间。如果 rtime 远小于 utime+stime,说明你的CPU多核利用率很高——这是好事。
我个人习惯用 fps(每秒帧数) 来衡量速度。FFmpeg默认会打印fps信息:
frame= 1234 fps= 45 q=28.0 size= 5120kB time=00:00:41.13 bitrate=1019.3kbits/s speed=1.51x
这里的 speed=1.51x 表示编码速度是实时播放速度的1.51倍。如果speed小于1,说明你的机器跑不动这个转码任务——嗯,该升级硬件或者降低参数了。
-benchmark 记录rtime,同时看fps。两个数据互相印证,不容易被单次波动误导。
3.2 CPU/GPU利用率:资源有没有吃满?
光看速度还不够。你得知道资源用到了什么程度。
CPU利用率,我一般用 top 或 htop 实时看。FFmpeg是多线程的,如果CPU利用率只有30%-40%,说明有瓶颈——可能是磁盘I/O,可能是内存带宽,也可能是编码器本身没开够线程。
举个例子:
ffmpeg -i input.mp4 -c:v libx264 -preset ultrafast -threads 4 output.mp4
-threads 控制线程数。默认是auto,但auto不一定最优。我在项目中遇到过,某些老版本FFmpeg在auto模式下只开了1个线程,白白浪费了16核的机器。后来我改成 -threads 8,速度直接翻倍。
GPU利用率呢?用 nvidia-smi 看:
nvidia-smi -l 1
重点关注 GPU-Util 和 Encoder/Decoder Utilization。如果GPU-Util只有20%,但Encoder Util已经99%,说明编码器单元是瓶颈。这时候加更多GPU核心也没用,得换更强的编码器或者降低编码复杂度。
3.3 内存占用:别让内存成为瓶颈
内存占用容易被忽略。但一旦爆了,系统开始用swap,速度直接崩盘。
FFmpeg的 -benchmark 会输出 maxrss,就是最大常驻内存集。单位是kB。比如 maxrss=142352kB 就是大约139MB。
哪些操作会吃内存?
- 高分辨率+高比特率:4K、8K视频,每帧数据量大,内存占用自然高。
- 长GOP:参考帧多,需要缓存更多帧。
- 多路并行转码:每个进程独立占内存,叠加起来很可观。
- 复杂滤镜链:比如多个
scale、overlay、fps串联,每个滤镜都可能缓存帧。
我建议你在生产环境里,给FFmpeg进程预留至少2倍于 maxrss 的内存空间。为什么?因为 maxrss 是峰值,但系统还需要给操作系统、其他服务留余量。
-preset medium,内存占用通常在200-400MB。4K H.265转码,-preset slow,可能飙到1.5-3GB。如果你用 libx265 的 -x265-params pools=... 开大量线程,内存占用还会更高。
3.4 编码延迟:实时场景的生命线
编码延迟,指的是从输入一帧到输出这一帧的编码结果,所花的时间。对于直播、视频会议、远程桌面这些场景,延迟是硬指标。
FFmpeg里可以用 -tune zerolatency 来优化:
ffmpeg -i input.mp4 -c:v libx264 -tune zerolatency -preset ultrafast output.mp4
但代价是什么?码率会飙升,画质会下降。说白了,就是用空间换时间。
延迟的测量,我一般用 -progress 参数输出时间戳,然后自己算差值:
ffmpeg -i input.mp4 -c:v libx264 -tune zerolatency -progress pipe:1 output.mp4 2>&1 | grep "out_time="
或者更直接,用 ffmpeg 的 -stats_period 控制日志输出频率,观察每一帧的处理时间。
影响延迟的关键因素:
- GOP大小:GOP越大,B帧越多,延迟越高。zerolatency模式下通常只用IDR帧和P帧,不用B帧。
- Lookahead:某些编码器(如x265)的lookahead功能会提前分析多帧,增加延迟。实时场景建议关闭。
- 线程同步:多线程编码时,帧之间的依赖关系会导致等待。
-tune zerolatency会限制线程间的同步开销。
-tune zerolatency 但延迟还是高。查了半天,发现是音频编码器 libfdk_aac 的帧大小设成了1024,导致音频缓冲延迟叠加。换成 -frame_size 256 后,延迟从800ms降到了200ms。所以,延迟优化要音视频一起看。
3.5 四个指标的权衡关系
这四个指标不是孤立的。它们之间互相影响,甚至互相矛盾。我画了一张图,帮你理清关系:
从图上你能看到,这四个指标形成了一个闭环。你优化其中一个,往往会影响到另外几个。比如:
- 提高编码速度(用ultrafast),CPU利用率下降,内存占用减少,延迟降低,但画质和码率会变差。
- 降低延迟(zerolatency),编码速度可能下降(因为限制了B帧和lookahead),CPU利用率反而可能升高(因为每帧都要独立处理)。
- 增加线程数,CPU利用率上升,编码速度提升,但内存占用也会增加(每个线程需要独立的缓冲区)。
3.6 实战:如何用FFmpeg收集这些指标
最后,给你一个我常用的「效率评估三板斧」脚本。每次调参前,先跑一遍这个,拿到基线数据:
#!/bin/bash
# 效率评估脚本 - 输出编码速度、CPU利用率、内存占用、延迟
INPUT="input.mp4"
OUTPUT="output.mp4"
PRESET="medium"
# 1. 编码速度 + 内存占用
echo "=== 编码速度 & 内存占用 ==="
ffmpeg -i $INPUT -c:v libx264 -preset $PRESET -benchmark -y $OUTPUT 2>&1 | grep "bench:"
# 2. CPU利用率(后台运行,同时用top采样)
echo "=== CPU利用率(采样5秒) ==="
ffmpeg -i $INPUT -c:v libx264 -preset $PRESET -y $OUTPUT &
PID=$!
top -b -n 5 -p $PID | tail -n 10 | awk '{print $9}' | paste -sd+ | bc
wait $PID
# 3. 编码延迟(用zerolatency对比)
echo "=== 编码延迟(zerolatency) ==="
ffmpeg -i $INPUT -c:v libx264 -tune zerolatency -preset ultrafast -progress pipe:1 -y output_zl.mp4 2>&1 | grep "out_time=" | tail -n 1
这个脚本虽然简陋,但够用。你可以在自己的机器上跑一遍,看看不同preset下四个指标的变化。数据会说话。