24、视频压缩与转码:分辨率缩放、码率控制、HDR转SDR、批量转码

视频压缩与转码,说白了就是让视频文件「变小」或者「变兼容」。

你可能遇到过这种情况:用户上传了一个 4K HDR 视频,结果播放器不支持,或者网络带宽扛不住。这时候就需要转码。我个人习惯把转码看作「视频的翻译官」——把一种格式翻译成另一种,同时尽量保持画质。

24.1 分辨率缩放:不只是简单的拉伸

分辨率缩放,听起来简单,就是把 1920x1080 缩到 1280x720 嘛。但这里有个坑——缩放算法选不对,画面会糊成一团。

常见的缩放算法:

  • 最近邻插值:最快,但锯齿严重。适合像素风格游戏录屏。
  • 双线性插值:平滑,但细节丢失。我一般不用它做视频缩放。
  • 双三次插值:质量不错,性能适中。日常转码首选。
  • Lanczos:质量最好,但计算量大。适合离线转码。

核心要点:缩放时一定要保持宽高比。强行拉伸会导致画面变形,用户一眼就能看出来。

在 FFmpeg 中,缩放命令很简单:

# 缩放到 720p,保持宽高比
ffmpeg -i input.mp4 -vf "scale=1280:720" output.mp4

# 自动计算高度,保持宽高比
ffmpeg -i input.mp4 -vf "scale=1280:-1" output.mp4

# 使用 Lanczos 算法
ffmpeg -i input.mp4 -vf "scale=1280:720:flags=lanczos" output.mp4

我曾经在项目中遇到过一个问题:把 4K 视频缩到 1080p,结果画面边缘出现了奇怪的波纹。排查了半天,发现是缩放算法没对齐像素网格。后来加了 pad 滤镜才解决。

24.2 码率控制:平衡画质与体积

码率控制,说白了就是决定「每一秒钟的视频用多少比特来存储」。码率越高,画质越好,文件也越大。

常见的码率控制模式:

模式 说明 适用场景
CBR(固定码率) 码率恒定不变 直播、视频会议
VBR(可变码率) 码率根据画面复杂度动态变化 本地存储、点播
CRF(恒定质量) 固定质量,码率自动调整 归档、高质量转码
CQP(固定量化参数) 固定量化步长 专业调优

我个人最常用的是 CRF 模式。为什么呢?因为它省心。你只需要告诉编码器「我要多高质量」,剩下的它自己搞定。

CRF 值参考:

  • CRF 18:视觉无损,适合归档
  • CRF 23:默认值,画质与体积平衡
  • CRF 28:体积小,画质可接受
# CRF 模式转码
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4

# 二遍 VBR,追求极致压缩
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -f mp4 /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 output.mp4

嗯,这里要注意:二遍 VBR 虽然压缩效率高,但耗时翻倍。我一般只在发布正式版本时才用。

24.3 HDR 转 SDR:色彩映射的艺术

HDR 视频的色彩范围比 SDR 大得多。直接播放 HDR 视频在 SDR 显示器上,画面会发灰、过曝。所以需要做色调映射(Tone Mapping)。

为什么 HDR 转 SDR 这么麻烦?

你想想看,HDR 能显示 0.0001 到 10000 尼特的亮度,而 SDR 只能显示 0.1 到 100 尼特。这中间的差距,需要靠算法来「压缩」。压缩不好,亮部细节全丢,暗部一片死黑。

FFmpeg 中常用的 HDR 转 SDR 方案:

# 使用 zscale 滤镜进行色调映射
ffmpeg -i input_hdr.mp4 \
  -vf "zscale=transfer=linear, zscale=primaries=bt709, zscale=transfer=bt709" \
  -c:v libx264 -crf 23 output_sdr.mp4

# 使用 tonemap 滤镜(更简单)
ffmpeg -i input_hdr.mp4 \
  -vf "tonemap=hable:desat=0" \
  -c:v libx264 -crf 23 output_sdr.mp4

避坑指南:我曾经用默认参数转了一个 HDR 风光片,结果天空过曝成一片白。后来发现是色调映射算法没选对。Hable 算法适合高对比度场景,Reinhard 算法适合柔和场景。建议根据内容类型选择。

另外,HDR 转 SDR 时,色彩空间也要转换。HDR 通常用 BT.2020 色域,SDR 用 BT.709。不转换的话,颜色会偏绿或偏紫。

24.4 批量转码:自动化才是王道

单个文件转码谁都会,但面对几百个视频时,手动操作会累死人。批量转码的核心是「脚本化」和「并行化」。

批量转码的常见策略:

  • 串行处理:简单,但慢。适合小批量。
  • 并行处理:利用多核 CPU,速度快。但要注意内存和 I/O 瓶颈。
  • 队列管理:控制并发数,避免系统过载。

我写过一个简单的批量转码脚本,分享给你:

#!/bin/bash
# 批量转码脚本:将当前目录下所有 .mp4 文件转成 720p H.264

for file in *.mp4; do
  output="720p_${file}"
  ffmpeg -i "$file" -vf "scale=1280:720" -c:v libx264 -crf 23 "$output"
done

如果想并行处理,可以用 GNU Parallel

# 同时处理 4 个文件
ls *.mp4 | parallel -j 4 ffmpeg -i {} -vf "scale=1280:720" -c:v libx264 -crf 23 720p_{}

批量转码的注意事项:

  • 先做小规模测试,确认参数没问题
  • 监控 CPU 和内存使用,别把服务器搞崩
  • 输出文件命名要有规律,方便后续处理

我曾经在批量转码时犯过一个低级错误:忘了检查磁盘空间。结果转了一半,磁盘满了,所有输出文件都损坏了。从那以后,我每次批量转码前都会先跑 df -h 看一眼。

24.5 本章知识体系

下面这张图总结了视频压缩与转码的核心流程:

视频压缩与转码核心流程 原始视频文件 分辨率缩放 码率控制(CRF/VBR/CBR) HDR 转 SDR(色调映射) 转码后视频文件 批量转码 串行 / 并行 队列管理 磁盘空间检查 命名规范 小规模测试

从图中可以看到,转码流程是线性的:原始视频 → 分辨率缩放 → 码率控制 → HDR 转 SDR → 输出。而批量转码则贯穿整个流程,负责管理多个任务的执行。

好了,这一章的内容就到这里。视频压缩与转码是音视频开发中的基本功,掌握了这些,你就能应对大部分转码需求了。


公众号:蓝海资料掘金营,微信deep3321