卡顿的定义:什么算启动卡顿,衡量指标
到底什么是"启动卡顿"
做 MediaCodec 优化这么多年,我见过最多的问题就是——"这算卡顿吗?"
不同团队对卡顿的理解差太多了。产品经理觉得"转圈超过1秒就是卡",测试同学说"掉帧就算",开发往往认为"只要没 ANR 就不算卡"。嗯,这里面其实有个共识问题。
启动卡顿,说白了就是用户从点击播放到看到流畅画面之间的"不舒服体验"。
从技术角度看,我习惯把它拆成两段:
- 第一段:等待期 —— 用户点了播放,画面还没出来。这段时间是"黑屏"或"转圈",属于延迟范畴。
- 第二段:适应期 —— 画面出来了,但一顿一顿的,帧率不稳。这属于帧率范畴。
我在项目中遇到过这样一个案例:一个短视频 App,首帧出来只要 200ms,但前 3 秒一直在掉帧。用户照样觉得"卡得要死"。你看,光快没用,还得流畅。
核心定义:启动卡顿 = 首次画面呈现延迟 + 初始播放阶段的帧率不稳定。两者缺一不可。
延迟指标:用户等多久才算"卡"
延迟是最直观的。你想想看,点完播放按钮,屏幕一直黑着,超过 500ms 大多数人就开始焦躁了。
我常用的延迟指标有两个:
首次帧显示时间(FFDT)
从 MediaCodec 调用 start() 到第一帧渲染到 Surface 的时间差。这是最核心的启动延迟指标。
测量方式很简单:
// 测量首次帧延迟
long startNs = System.nanoTime();
MediaCodec codec = MediaCodec.createByCodecName(mimeType);
codec.configure(format, surface, null, 0);
codec.start();
BufferInfo info = new BufferInfo();
while (!isFirstFrameRendered) {
int index = codec.dequeueOutputBuffer(info, 10000);
if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// 格式变化,继续
} else if (index >= 0) {
// 首次输出缓冲区,算第一帧
long ffdt = System.nanoTime() - startNs;
Log.d("Latency", "首次帧延迟: " + ffdt / 1_000_000 + "ms");
codec.releaseOutputBuffer(index, true);
isFirstFrameRendered = true;
}
}
我建议:FFDT 的基准线设在 300ms 以内。超过 500ms 用户就能明显感知到"卡"了。
启动总耗时
从用户点击到画面稳定播放的完整时间。包含:
- MediaCodec 创建 + 配置耗时
- 首帧解码 + 渲染耗时
- 前 N 帧的缓冲区填充耗时
这个指标更贴近用户真实感受。我一般取"从点击到第 3 帧显示"的时间作为总耗时。
| 延迟等级 | FFDT | 启动总耗时 | 用户感知 |
|---|---|---|---|
| 优秀 | < 100ms | < 500ms | 几乎无感 |
| 良好 | 100~300ms | 500~1000ms | 轻微等待 |
| 可接受 | 300~500ms | 1000~2000ms | 明显等待 |
| 严重 | > 500ms | > 2000ms | 焦躁、退出 |
我曾经踩过这个坑:只盯着 FFDT 看,忽略了总耗时。有一次 FFDT 优化到了 80ms,但用户还是抱怨卡。一查发现后面几帧间隔了 400ms,总耗时超过 1.5s。所以别只看单点,要看完整链路。
帧率指标:画面多流畅才算"不卡"
延迟解决了"有没有画面"的问题,帧率解决的是"画面稳不稳"的问题。
我常用的帧率指标有三个:
平均帧率(Average FPS)
启动后前 N 秒的平均帧率。一般取前 3 秒或前 5 秒的数据。
计算公式:
平均帧率 = 总帧数 / 总时长(秒)
对于 30fps 的内容,平均帧率低于 20fps 就算卡。对于 60fps 的内容,低于 40fps 就不及格。
帧率抖动(Jank)
帧间隔时间的标准差。这个指标比平均帧率更敏感。
举个例子:
- 场景 A:帧间隔均匀 33ms,平均 30fps → 流畅
- 场景 B:大部分帧 20ms,突然跳一帧 80ms,平均也是 30fps → 明显卡顿
平均帧率看不出 B 的问题,但帧率抖动能。我个人习惯把抖动超过 10ms 的帧标记为 Jank 帧。
掉帧率(Frame Drop Rate)
掉帧是最直观的卡顿表现。我一般统计"实际帧数 / 期望帧数"的比值。
掉帧率 = (期望帧数 - 实际帧数) / 期望帧数 × 100%
举个例子,30fps 的内容,3 秒内期望 90 帧,实际只渲染了 60 帧,掉帧率就是 33%。超过 20% 用户就能明显感知到卡了。
关键结论:帧率指标不能只看平均值。Jank 率和掉帧率才是反映"卡顿感"的核心指标。
综合评判:怎么定量衡量卡顿
讲完指标,问题来了——这些数据怎么组合起来判断是否卡顿?
我自己的经验是:延迟指标做筛选,帧率指标做分级。
- 第一步:看 FFDT 是否超过 500ms。超过的直接判定为"严重卡顿"。
- 第二步:如果 FFDT 达标,看前 3 秒的 Jank 帧占比。超过 30% 就算"中度卡顿"。
- 第三步:再看掉帧率。低于 10% 算流畅,10%~20% 算轻度卡顿,超过 20% 算中度以上。
我建议你在工程中这样做:把 FFDT、Jank 率、掉帧率三个指标合成一个"卡顿指数",权重可以设为 4:3:3。指数低于 30 算流畅,30~60 算轻度,60~80 算中度,80 以上算严重。
提醒一下:不同场景的容忍度不一样。短视频用户对延迟更敏感,长视频用户对帧率稳定性更敏感。别拿一套标准套所有场景。
回到实际工作里,我习惯用这张图来跟团队对齐"什么是卡顿"。它把延迟和帧率两条线串起来了,也给出了最终的判定逻辑。
说白了,定义卡顿不是为了学术研究,是为了让团队有个统一的标准去排查和优化。没有标准,你说卡我说不卡,根本没法干活。
拿我自己的项目来说,自从定了"FFDT < 300ms + Jank率 < 20%"这个标准,测试和开发的扯皮少了一大半。数据说话,比感觉靠谱多了。
一句话总结本章:启动卡顿 = 延迟超标 + 帧率不稳。衡量它,盯紧 FFDT、Jank 率、掉帧率这三个数就够了。