2. 编解码器基础

各位好,我是老张。今天咱们聊聊编解码器的基础。说实话,很多做容器化部署的朋友,最后踩的坑往往不是K8s配置不对,而是对编码器本身的理解不够深。你想想看,如果连H.264和H.265的区别都说不清楚,怎么给容器配参数?

这一节我会从编码原理讲起,然后带大家过一遍FFmpeg的常用命令。嗯,都是我在生产环境里摸爬滚打总结出来的东西。

2.1 H.264/H.265 编码核心原理

先说H.264,也叫AVC。它为什么能压得那么小?说白了就四个字:帧间预测。

视频里相邻帧之间,大部分像素是不动的。比如一个人坐在那里说话,背景墙根本不变。H.264的做法是:只记录变化的部分,不变的部分直接复用前一帧的数据。这就是所谓的「P帧」和「B帧」。

  • I帧(关键帧):完整的一帧图像,不依赖其他帧。解码的起点。
  • P帧(前向预测帧):只记录与前一帧的差异。
  • B帧(双向预测帧):参考前后两帧,压缩率最高。

核心概念:GOP(Group of Pictures)

GOP就是一组连续的帧,以I帧开头。GOP越长,压缩率越高,但seek(跳转播放)越慢。我在做直播项目时,GOP设成了2秒,既保证压缩率,又保证观众拖进度条时不卡太久。

H.265(HEVC)呢?它是在H.264的基础上做了「暴力升级」。最核心的变化是:编码树单元(CTU)替代了宏块。

H.264的宏块最大16x16像素,而H.265的CTU最大64x64。大块适合平坦区域,小块适合纹理复杂区域。H.265会自适应地切分,说白了就是「哪里复杂切哪里,哪里简单就合并」。同样的画质,H.265能比H.264省30%~50%的码率。

我的经验: 在边缘设备上,如果CPU不够强,别硬上H.265。我曾经在树莓派上试过H.265实时编码,结果CPU直接飙到90%,帧率掉到15fps。后来换回H.264,稳如老狗。

下面这张图展示了H.264和H.265在编码块划分上的核心差异:

H.264 宏块 vs H.265 CTU 对比 H.264 宏块 vs H.265 CTU 编码块划分对比 H.264:固定 16x16 宏块 每个宏块大小固定,无法自适应 H.265:自适应 CTU(最大 64x64) 平坦区域用大块,复杂区域用小块

2.2 FFmpeg 命令行工具实战

FFmpeg这东西,我用了快十年了。它就是个「瑞士军刀」,什么格式都能切,什么参数都能调。但正因为太强大,很多人反而不知道怎么用。

我个人习惯把FFmpeg命令拆成三部分:输入 → 处理 → 输出。你只要记住这个结构,大部分命令都能自己拼出来。

ffmpeg [输入选项] -i input.mp4 [处理选项] [输出选项] output.mp4

2.2.1 常用转码命令

先来几个最常用的。这些命令我在生产环境里天天用:

场景 命令 说明
H.264 转码 ffmpeg -i input.mp4 -c:v libx264 output.mp4 软件编码,兼容性最好
H.265 转码 ffmpeg -i input.mp4 -c:v libx265 output.mp4 压缩率更高,但编码慢
硬件加速(NVIDIA) ffmpeg -i input.mp4 -c:v h264_nvenc output.mp4 GPU编码,速度快,画质略差
提取音频 ffmpeg -i input.mp4 -vn -c:a copy audio.aac 只取音频流,不重新编码
截取片段 ffmpeg -i input.mp4 -ss 00:01:00 -t 30 output.mp4 从第1分钟开始,截取30秒

注意: 用 -ss 时,如果放在 -i 前面,是「关键帧精准」截取,速度快但可能不准。放在 -i 后面,是「帧精准」截取,速度慢但精确。我一般先放前面快速定位,再放后面做精确裁剪。

2.2.2 常用编码参数解析

参数这东西,每个都有它的脾气。我挑几个最关键的说说:

  • -crf (Constant Rate Factor):质量控制参数。范围0~51,越小质量越高。H.264一般用18~28,H.265用24~34。我个人习惯:存档用18,在线分发用23。
  • -preset:编码速度预设。可选值:ultrafast、superfast、veryfast、faster、fast、medium、slow、slower、veryslow、placebo。越慢压缩率越高。我一般用medium或slow,placebo就算了,收益太小。
  • -profile:v:H.264档次。baseline(低端设备)、main(主流)、high(高清)。直播用baseline,点播用high。
  • -tune:调优模式。film(电影)、animation(动画)、grain(胶片)、fastdecode(快速解码)。选对了能明显提升画质。

我的避坑指南: 曾经有个项目,视频在Chrome上播放正常,但在Safari上黑屏。查了半天,发现是用了-profile:v high10,Safari不支持10bit。后来改成-profile:v high,问题解决。所以,兼容性优先于画质。

2.3 编码参数对比表

下面这张表,是我自己整理的。每次做编码方案时,我都会拿出来对照一下:

参数 H.264 (libx264) H.265 (libx265) 建议值
CRF 18~28 24~34 存档18,分发23
Preset medium/slow medium/slow 生产用medium
Profile baseline/main/high main/main10 点播用high
码率控制 ABR/CBR/CRF ABR/CBR/CRF 直播用CBR
GOP大小 10~300帧 10~300帧 直播2秒,点播5秒

2.4 实战:一条完整的转码命令

最后,我给大家一条「生产级」的转码命令。这条命令我在多个项目里验证过,兼顾了画质、兼容性和编码速度:

ffmpeg -i input.mp4 \
  -c:v libx264 \
  -preset medium \
  -crf 23 \
  -profile:v high \
  -level 4.1 \
  -pix_fmt yuv420p \
  -c:a aac \
  -b:a 128k \
  -movflags +faststart \
  output.mp4

解释一下几个关键点:

  • -level 4.1:限制解码复杂度,保证在大多数设备上都能播放。
  • -pix_fmt yuv420p:最通用的像素格式,兼容性最好。
  • -movflags +faststart:把moov元数据移到文件头部,这样视频可以边下载边播放。做Web分发时必加。

总结一下: 编码这件事,没有银弹。你得根据场景选参数。直播追求低延迟,点播追求高压缩率,存档追求无损。理解了原理,再配合FFmpeg的参数,你就能做出适合自己业务的编码方案。