3、视频转码实战:H.264与H.265编码、调整分辨率与帧率、设置码率与质量(CRF)、硬件加速编码(NVENC/VAAPI)
转码,说白了就是把一种视频格式「翻译」成另一种。你可能会问:直接复制文件不就行了?嗯,很多时候我们需要的不只是换封装,而是要改变编码方式、缩小体积、适配不同设备。这一章,我就带你亲手搭建一条完整的转码管道。
本章核心脉络:从软件编码到硬件加速,从参数调优到实战脚本,一条线串下来。
3.1 编码器选择:H.264 还是 H.265?
这是每次转码前都要做的选择题。我个人习惯这样判断:如果目标设备是旧手机、电视盒子或者需要广泛兼容,选 H.264;如果是自己存片、追求同等画质下更小的体积,选 H.265。
| 特性 | H.264 (AVC) | H.265 (HEVC) |
|---|---|---|
| 压缩率 | 基准 | 提升 30%~50% |
| 编码速度 | 快 | 慢(约 2~4 倍时间) |
| 硬件支持 | 几乎所有设备 | 较新设备(2015+) |
| FFmpeg 编码器名 | libx264 |
libx265 |
| 适用场景 | 直播、兼容性优先 | 存档、4K/UHD |
我的经验:有一次给客户做视频平台迁移,源文件全是 H.264 的 MP4,总共有 2TB。我建议转成 H.265 存档,结果压缩到了 800GB,画质几乎看不出区别。但播放兼容性测试时发现,有几台老款智能电视不支持 H.265 硬解……最后只好保留一份 H.264 副本。
3.2 调整分辨率与帧率
分辨率决定了画面的精细度,帧率决定了流畅度。这两个参数改起来简单,但坑不少。
分辨率缩放
FFmpeg 用 -vf scale 滤镜来做。我常用的几种写法:
# 固定宽高(保持比例)
ffmpeg -i input.mp4 -vf scale=1280:720 output.mp4
# 只指定宽度,高度自动计算
ffmpeg -i input.mp4 -vf scale=1280:-1 output.mp4
# 强制拉伸(不推荐,除非你知道自己在做什么)
ffmpeg -i input.mp4 -vf scale=640:480,setdar=4:3 output.mp4
嗯,这里要注意:scale=1280:-1 这种写法,FFmpeg 会自动保持原始宽高比。但如果你原始视频是竖屏的,出来的高度可能不是你想要的。我建议先 ffprobe 看一眼原始分辨率再决定。
帧率转换
帧率用 -r 参数设置。但有个细节:-r 放在 -i 前面和后面效果不一样。
# 放在 -i 前面:先改变输入帧率(丢帧或插帧)
ffmpeg -r 30 -i input.mp4 output.mp4
# 放在 -i 后面:输出帧率(更常用)
ffmpeg -i input.mp4 -r 30 output.mp4
我曾经犯过一个错:把 60fps 的游戏录像转成 30fps,直接用了 -r 30 放在前面,结果画面一卡一卡的。后来才明白,应该用 fps=30 滤镜配合 setpts 来调整时间戳。
# 正确的降帧方式
ffmpeg -i input.mp4 -vf "fps=30,setpts=PTS/2" output.mp4
3.3 码率控制与 CRF
码率控制是转码的核心。说白了,就是决定「每一秒钟的视频用多少数据量」。FFmpeg 提供了三种模式:
| 模式 | 参数 | 特点 | 适用场景 |
|---|---|---|---|
| CBR(固定码率) | -b:v 2M -minrate 2M -maxrate 2M |
码率恒定,画质波动 | 直播、流媒体 |
| VBR(可变码率) | -b:v 2M |
码率浮动,画质稳定 | 本地存储、点播 |
| CRF(恒定质量) | -crf 23 |
画质恒定,码率自动 | 存档、个人收藏 |
CRF 详解
我个人最推荐 CRF 模式。它不像 CBR 那样死板,也不像 VBR 需要你猜码率。CRF 的值范围是 0~51,数值越小质量越高,文件越大。
- H.264:常用 18~28,默认 23。18 接近无损,28 开始有可见劣化。
- H.265:常用 22~32,默认 28。因为压缩率更高,同等画质下 CRF 值可以比 H.264 大 3~5。
# H.264 CRF 23(平衡画质与体积)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
# H.265 CRF 26(比 H.264 省 40% 体积)
ffmpeg -i input.mp4 -c:v libx265 -crf 26 output.mp4
# 追求极致画质(CRF 18,文件会很大)
ffmpeg -i input.mp4 -c:v libx264 -crf 18 output.mp4
避坑指南:CRF 不是万能的。如果你需要精确控制输出文件大小(比如上传到某个限制 500MB 的平台),CRF 就不合适了。这时候得用 2-pass VBR。我曾经给一个客户做批量转码,他要求每个视频控制在 200MB 以内,我用了 CRF 23 结果有的 150MB,有的 350MB……最后老老实实上了 2-pass。
3.4 硬件加速编码:NVENC 与 VAAPI
软件编码质量好,但慢。如果你有一块 NVIDIA 显卡或者 Intel 核显,硬件加速能让你转码速度快 5~10 倍。当然,代价是同等码率下画质稍差,体积稍大。
NVIDIA NVENC(N 卡)
FFmpeg 里用 h264_nvenc 或 hevc_nvenc。我常用的参数组合:
# H.264 硬件编码,质量优先
ffmpeg -i input.mp4 -c:v h264_nvenc -preset p7 -rc vbr -cq 23 -b:v 0 output.mp4
# H.265 硬件编码,平衡模式
ffmpeg -i input.mp4 -c:v hevc_nvenc -preset p4 -rc vbr -cq 26 -b:v 0 output.mp4
参数说明:
-preset:p1~p7,p7 质量最好但最慢(相对硬件编码而言)。-rc vbr:可变码率模式。-cq:类似 CRF 的质量参数,NVENC 里叫 Constant Quality。-b:v 0:让编码器自己决定码率上限。
Intel VAAPI(核显 / 集显)
VAAPI 在 Linux 上用得比较多。需要先确认你的驱动支持:
# 检查 VAAPI 设备
vainfo
# H.264 硬件编码
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 -vf 'format=nv12,hwupload' -c:v h264_vaapi output.mp4
# H.265 硬件编码
ffmpeg -vaapi_device /dev/dri/renderD128 -i input.mp4 -vf 'format=nv12,hwupload' -c:v hevc_vaapi output.mp4
我的经验:VAAPI 有个坑——输入格式必须是 NV12,否则会报错。所以 -vf 'format=nv12,hwupload' 这步不能省。另外,VAAPI 的 H.265 编码在旧款 Intel 核显上可能不支持,建议先跑一小段测试。
3.5 实战:一条完整的转码命令
把上面学到的串起来。假设我有一个 1080p 60fps 的源视频,想转成 720p 30fps 的 H.265,用 CRF 26,优先用 NVENC 加速:
# 检测到 NVIDIA 显卡就用硬件,否则回退软件
if ffmpeg -encoders 2>/dev/null | grep -q h264_nvenc; then
ffmpeg -i input.mp4 \
-c:v hevc_nvenc -preset p7 -rc vbr -cq 26 \
-vf "scale=1280:720,fps=30" \
-c:a aac -b:a 128k \
output.mp4
else
ffmpeg -i input.mp4 \
-c:v libx265 -crf 26 \
-vf "scale=1280:720,fps=30" \
-c:a aac -b:a 128k \
output.mp4
fi
这条命令做了几件事:
- 检测是否有 NVENC 编码器,有就用硬件,没有回退到软件。
- 缩放分辨率到 1280x720,同时降帧到 30fps。
- 音频用 AAC 128kbps,保证音质。
- 输出为 MP4 容器。
核心要点:转码不是简单的「输入→输出」,每一步参数选择都影响最终效果。我个人建议:存档用 CRF + 软件编码,分发用 VBR + 硬件编码。这样既保证质量,又兼顾效率。