3、视频转码实战:H.264与H.265编码、调整分辨率与帧率、设置码率与质量(CRF)、硬件加速编码(NVENC/VAAPI)

转码,说白了就是把一种视频格式「翻译」成另一种。你可能会问:直接复制文件不就行了?嗯,很多时候我们需要的不只是换封装,而是要改变编码方式、缩小体积、适配不同设备。这一章,我就带你亲手搭建一条完整的转码管道。

本章核心脉络:从软件编码到硬件加速,从参数调优到实战脚本,一条线串下来。

视频转码决策流程 视频转码决策流程 输入源视频 选择编码:H.264 / H.265 / 其他 硬件加速?NVENC / VAAPI / 纯软件 软件编码 硬件编码 设置参数:分辨率 / 帧率 / 码率 / CRF 输出目标视频 💡 提示 硬件编码速度快但体积大 软件编码质量好但速度慢

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

这条命令做了几件事:

  1. 检测是否有 NVENC 编码器,有就用硬件,没有回退到软件。
  2. 缩放分辨率到 1280x720,同时降帧到 30fps。
  3. 音频用 AAC 128kbps,保证音质。
  4. 输出为 MP4 容器。

核心要点:转码不是简单的「输入→输出」,每一步参数选择都影响最终效果。我个人建议:存档用 CRF + 软件编码,分发用 VBR + 硬件编码。这样既保证质量,又兼顾效率。