1. 编解码基础与性能瓶颈分析
各位同学好,我是老张。做多媒体系统优化这行快十五年了,今天咱们聊聊编解码这件事儿的底层逻辑。
很多人一上来就问我:「怎么让编码更快?」我的回答通常是——你先搞清楚慢在哪。这就像修车,你得先听发动机异响在哪,不能上来就换零件。
1.1 编解码流程:H.264/H.265 到底在干什么
说白了,视频编码就是「找重复 + 扔掉不重要的」。H.264 和 H.265 的核心流程差不多,但后者在「找重复」这件事上更狠。
我习惯把编码流程拆成四个阶段:
- 帧内预测——用当前帧里已经编好的像素,猜还没编的像素。H.265 支持 35 种预测模式,H.264 只有 9 种。
- 帧间预测——用前面或后面的帧来猜当前帧。这里涉及运动估计,说白了就是找「这块图像之前在哪出现过」。
- 变换与量化——把像素值转到频域,扔掉人眼不敏感的高频细节。DCT 变换是核心,H.265 用了更大的 32x32 块。
- 熵编码——把前面产生的符号压缩成比特流。H.264 用 CAVLC/CABAC,H.265 只用 CABAC,因为压缩率更高。
关键差异:H.265 在相同画质下码率能省 30%-50%,但计算量是 H.264 的 2-3 倍。这不是白给的,得拿算力换。
我当年在做一个 4K 直播项目时,团队坚持用 H.264 软编码,结果服务器 CPU 直接飙到 95%。后来切到 H.265,码率降了一半,但 CPU 负载反而更高了——因为运动估计的搜索范围大了好几倍。嗯,这就是代价。
1.2 CPU 编解码的性能瓶颈:三个拦路虎
你想想看,CPU 做编解码为什么慢?不是它算得慢,是它「等数据」等得慢。我总结了三座大山:
1.2.1 内存带宽——最容易被忽视的瓶颈
编解码是典型的内存密集型任务。处理一帧 1080p 图像,你需要读入原始像素、参考帧数据、运动矢量、变换系数……这些数据来回倒腾,内存带宽很快就吃满了。
| 分辨率 | 单帧原始数据量 | 编码所需总带宽(估) |
|---|---|---|
| 1080p (1920x1080) | ~6 MB (YUV420) | ~200 MB/s |
| 4K (3840x2160) | ~24 MB | ~800 MB/s |
| 8K (7680x4320) | ~96 MB | ~3.2 GB/s |
我曾经踩过的坑:在 ARM 平台上做 4K 解码,DDR 带宽只有 12.8 GB/s,看起来够用对吧?但别忘了,系统里还有 GPU、显示控制器、NPU 在抢带宽。实际分给解码器的不到 4 GB/s,结果就是频繁掉帧。后来我不得不把参考帧从 16 帧砍到 4 帧,画质牺牲了不少。
1.2.2 缓存命中率——局部性决定一切
编解码的访存模式非常「不友好」。运动估计要随机访问参考帧的不同位置,这导致缓存命中率极低。L1 缓存命中率可能不到 50%,L2 也好不到哪去。
为什么会这样?因为视频数据是二维的,而缓存是按一维地址组织的。你访问像素 (x, y) 时,相邻行可能隔了很远。
我建议在做运动估计时,把搜索窗口的数据先搬到局部内存里。这招在 GPU 上叫 shared memory,在 CPU 上就是手动做 cache blocking。
1.2.3 指令集利用率——SIMD 用好了是神器
现代 CPU 都有 SIMD 指令集(SSE、AVX2、AVX-512),一条指令能同时处理 8 个 32 位整数。但很多编解码实现并没有充分利用这一点。
// 糟糕的实现:逐像素处理
for (int i = 0; i < width * height; i++) {
dst[i] = (src[i] + offset) >> shift;
}
// 好的实现:使用 SIMD
__m256i vec_src = _mm256_loadu_si256((__m256i*)&src[i]);
__m256i vec_offset = _mm256_set1_epi16(offset);
__m256i vec_result = _mm256_srai_epi16(
_mm256_add_epi16(vec_src, vec_offset), shift);
_mm256_storeu_si256((__m256i*)&dst[i], vec_result);
上面这个例子,SIMD 版本比逐像素版本快了将近 8 倍。但要注意,AVX-512 虽然更宽,但频率会降,有时候反而更慢。我习惯先测一下再决定用哪个。
1.3 为什么需要 GPU 加速?
好,现在你知道了 CPU 的瓶颈在哪。那 GPU 为什么适合干这个?
- 并行度碾压:CPU 最多 16-32 个核心,GPU 有几千个 CUDA 核心。运动估计、DCT 变换这些操作天然可并行。
- 内存带宽优势:高端 GPU 的显存带宽超过 1 TB/s,是 CPU DDR 的 10 倍以上。这对编解码这种带宽饥渴型任务简直是雪中送炭。
- 专用硬件单元:NVIDIA 的 NVENC、Intel 的 QSV、AMD 的 VCE,这些硬编码器把整个编码流水线固化在芯片上,功耗只有 CPU 软编码的十分之一。
我的经验:不是所有场景都适合 GPU。如果视频分辨率低(比如 720p 以下),或者延迟要求极高(比如远程手术),CPU 软编码反而更灵活。GPU 加速在 4K/8K 批量转码、直播推流这些场景下优势最明显。
我记得有一次给某视频平台做转码集群优化,原来用 200 台 CPU 服务器,每天处理 10 万小时视频。后来换成 40 台带 GPU 的服务器,功耗降了 60%,吞吐量反而提升了 3 倍。这就是 GPU 加速的价值。
1.4 本章知识体系
下面这张图是我自己画的,把编解码的核心流程和性能瓶颈串起来了。你多看几遍,后面章节都会围绕这张图展开。
这张图把本章的核心逻辑串起来了:原始视频帧经过预测、变换、量化、熵编码四个阶段变成码流。在这个过程中,CPU 会遇到三个主要瓶颈——内存带宽、缓存命中率、SIMD 利用率。而 GPU 通过并行计算、高带宽显存和专用硬件,正好能绕过这些瓶颈。
后面的章节,我会带你一步步深入每个环节的优化细节。咱们先从 CPU 侧的优化讲起,再过渡到 CPU-GPU 协同。别急,路要一步一步走。