编码器基础:编码器的工作流程
编码器这东西,说白了就是个流水线。采集、预处理、编码、封装,四个环节串在一起。哪个环节慢了,整个延迟就上去了。我刚开始做低延迟直播的时候,总以为编码器就是“把画面压小一点”,后来踩了不少坑才明白——每个环节都有门道。
1. 采集:第一道关卡
采集是编码器的入口。摄像头、屏幕录制、或者从网络流里拿数据,都算采集。这里有个关键点:采集的格式和帧率,直接决定了后续环节的压力。
举个例子。我遇到过一位客户,摄像头输出的是 4K 60fps 的 YUV 4:4:4 数据。一秒钟的数据量有多大?算一下:3840×2160×60×3 ≈ 1.5 GB/s。这还没编码呢,光采集就把 PCIe 带宽吃掉了大半。后来我建议他换成 YUV 4:2:0,数据量直接砍半,延迟也降下来了。
采集的延迟通常很小,几毫秒到十几毫秒。但要注意:如果采集设备和编码器不在同一个物理设备上(比如通过网络传),那延迟就不可控了。我建议尽量把采集和编码放在同一台机器上,或者至少用同一个 PCIe 总线。
2. 预处理:别小看这一步
预处理是编码前的一道“美容”工序。缩放、裁剪、色彩空间转换、降噪、去隔行……这些操作看起来简单,但做不好会引入额外延迟。
我个人最常踩的坑是色彩空间转换。比如从 BT.709 转到 BT.2020,如果用的是纯 CPU 计算,一帧 1080p 的画面可能要花 5-8 毫秒。你想想看,如果帧率是 60fps,每帧只有 16.6 毫秒的预算,预处理就占掉一半,编码还怎么玩?
预处理还有一个容易被忽略的点:帧缓冲。有些预处理算法需要参考前后帧(比如时域降噪),这就会引入至少一帧的延迟。如果你做的是实时通信,这种延迟是致命的。我建议在低延迟场景下,关掉时域滤波,只用空域降噪。
3. 编码:核心中的核心
编码是整个流程里最耗时的环节。H.264、H.265、AV1……不同的编码器,不同的预设,延迟差异巨大。这里我直接给一张表,方便你对比:
| 编码器 | 预设 | 单帧编码延迟(1080p) | 适用场景 |
|---|---|---|---|
| x264 | ultrafast | 2-4 ms | 实时通信、直播 |
| x264 | medium | 8-15 ms | 点播、非实时 |
| x265 | ultrafast | 5-10 ms | 实时通信(高压缩率) |
| NVENC H.264 | P1(最快) | 0.5-1 ms | 低延迟直播、云游戏 |
| NVENC H.265 | P1 | 1-2 ms | 低延迟直播(高画质) |
看到没?硬件编码器的延迟比软件编码器低一个数量级。但硬件编码器也有缺点:码率控制不够灵活,有时候画面复杂了会突然飙码率。我建议在码率敏感的场景下,用软件编码器配合 CBR(恒定码率)模式。
编码环节还有一个关键参数:GOP(Group of Pictures)结构。GOP 越长,压缩率越高,但延迟也越大。为什么?因为 B 帧需要参考后面的帧,编码器必须等未来帧到了才能处理当前帧。我个人的经验是:低延迟场景下,只用 I 帧和 P 帧,关掉 B 帧。这样每帧都是独立编码,延迟只取决于当前帧的处理时间。
4. 封装:最后的打包
封装是把编码后的视频流、音频流、字幕等打包成一个容器格式。常见的容器有 MP4、TS、FLV、MKV 等。封装本身的计算量很小,但封装方式会影响“首帧延迟”。
举个例子。MP4 的 moov box 通常放在文件末尾,播放器必须下载完整个文件才能开始播放。这显然不适合直播。所以直播场景下,我们通常用fragmented MP4(fMP4)或者TS(Transport Stream)。fMP4 把 moov box 放在前面,播放器拿到第一个 fragment 就能开始播。
我遇到过一个问题:用 FFmpeg 封装 TS 流时,默认的 muxer 会缓存 7 个包才输出。这意味着封装环节引入了 7 个包的延迟。后来我加了 muxdelay=0 参数,才把延迟降下来。
// 低延迟封装示例(FFmpeg)
ffmpeg -i input.h264 -c copy -f mpegts -muxdelay 0 output.ts
封装环节的延迟通常可以控制在 1 毫秒以内,前提是你别用那些“智能”的 muxer 参数。记住:封装越简单,延迟越低。
整体流程:一张图看懂
下面这张 SVG 图展示了编码器的工作流程,以及每个环节的典型延迟范围。你可以看到,编码环节是最大的瓶颈,预处理和封装相对可控。
避坑指南:我踩过的几个坑
- 采集分辨率不匹配:摄像头输出 1080p,编码器却设成 720p,结果预处理环节多了一次缩放,延迟翻倍。我建议采集和编码用同一分辨率,或者用硬件缩放器。
- 预处理链路过长:有人喜欢在预处理里做一堆滤镜——降噪、锐化、色彩增强……每个滤镜加 1-2ms,加起来就 10ms 了。我建议只做必要的操作,其他的交给编码器。
- 编码器预设选错:用 x264 的 placebo 预设做直播?那延迟能到 100ms 以上。记住:实时场景只用 ultrafast 或 superfast。
- 封装格式选错:用 MP4 做直播?播放器要等整个文件下载完才能播。用 fMP4 或 TS,首帧延迟能降到 1 秒以内。
ffmpeg -benchmark 看每个环节的耗时。如果发现某个环节异常,就用 -profile:v baseline 之类的参数逐步排查。记住:数据不会骗人,但直觉会。