FFmpeg 9.0「Lei」深度拆解:从二十年架构重写到 Vulkan 全矩阵,一个多媒体框架的自我革命
2026年8月4日,FFmpeg 社区正式发布了 FFmpeg 9.0,代号「Lei」。这不仅是 FFmpeg 历史上技术动作最大的一次版本更新,更因为它选择了一个非科学家、非数学家的名字作为代号而引发全球开发者的情感共鸣。
但今天,我们不只谈情怀。这篇文章从工程视角出发,深度剖析 FFmpeg 9.0 的架构级变化、GPU 加速体系重塑、HDR 专业管线升级,以及作为下游开发者必须掌握的 ABI 破坏性变更和迁移路径。
一、背景:为什么 9.0 不是一个普通的大版本
从版本号看,9.0 不过是 8.x 的自然延续。但数字背后的工程量,远超常规:
- 2200+ 次提交,1781 个文件被修改
- 净增约 52000 行代码
- 7 个核心库的 ABI 全部破坏性升级:libavutil 60→61、libavcodec 62→63、libavformat 62→63、libavdevice 62→63、libavfilter 11→12、libswscale 9→10、libswresample 6→7
这意味着什么?意味着所有依赖 FFmpeg 动态库的下游应用,都必须重新编译。没有任何豁免。
而且 9.0 与上一个版本 8.1 "Hoare" 之间只隔了四个半月。能在如此短周期内完成如此大规模的重构,靠的是社区的高度共识:是时候解决那些年积累下来的历史债务了。
二、swscale 二十年架构重写:最重磅的工程变更
2.1 旧架构的问题
libswscale 负责像素格式转换和缩放,是 FFmpeg 中调用最频繁的库之一。二十年来,它积累了大量格式特定的转换代码——每新增一种像素格式,就需要手写一条特殊处理路径。
Niklas Haas 在重构提案中描述了一个令人窒息的现实:到了 9.0 周期初,swscale 维护者每加一个格式,就要写 8-12 个特殊分支,其中大部分是手写的汇编。维护成本已经高到不可持续。
2.2 新架构设计:算子图 + 可插拔后端
新架构的核心思想是:将每一种像素格式转换分解为一系列基础操作,由优化器分析后,编译为最优的内核链。
旧架构:input → if_rgb32 → if_yuv420p → special_path → if_nv12 → output(8-12个硬编码分支)
新架构:
input (read) → swizzle → linear_transform → scale → pack (output)
↓ ↓ ↓
C 后端参考实现 x86 SIMD后端 NEON后端 Vulkan后端
这个分解过程由一个**优化器(Optimizer)**完成,它会:
- 分析操作列表
- 按平面(plane)拆分,减少单个内核循环的复杂度
- 选择最优后端组合
- 生成对应的内核链
2.3 五个后端,各司其职
| 后端 | 说明 | 适用场景 |
|---|---|---|
| C 参考实现 | 基于模板的通用实现 | 正确性基准,所有后端的参照标准 |
| 快速 memcpy | 无需格式转换的直通场景 | 直接拷贝 |
| x86 SIMD | NASM 宏生成的链式内核,含 AVX2 调色板读取 | Intel/AMD 桌面/服务器 |
| AArch64 NEON | rasm 汇编框架生成的链式内核 | ARM 移动/嵌入式 |
| Vulkan SPIR-V | 将操作图编译为 GPU 计算着色器 | 8K+ 高分辨率处理 |
2.4 Vulkan 后端:同一代码,CPU/GPU 双运行
这是最有战略意义的部分。开发者写一套转换操作图,既可以在 CPU 上用 SIMD/NEON 执行,也可以在 GPU 上用 Vulkan 着色器执行。硬件不再绑定代码路径。请求 SWS_BITEXACT 时,Vulkan 后端通过 SPIR-V 的 NoContraction 装饰禁止 GPU 的融合乘加(FMA)优化,确保 CPU 和 GPU 输出的结果逐 bit 一致,这对专业视频制作管线至关重要。
2.5 正确性工程:常量数学与 bit-exact
新架构解决了 swscale 多年的一个隐患:常量数学计算从浮点近似改为 64 位有理数精确计算,消除了一系列溢出检查错误。
2.6 稳定版本注意事项
新架构当前仍受 SWS_UNSTABLE 宏门控。在 9.0 稳定版中,默认行为仍使用旧代码。要启用新架构,需要在包含 swscale.h 之前定义 #define SWS_UNSTABLE 1,不建议在生产环境中启用。
三、libavcodec:700+ 次提交,全面开花
3.1 动画 WebP 解码器:关闭了 11 年的 ticket
FFmpeg 对 WebP 的支持始于 2015 年,但只支持静态 WebP。动态/动画 WebP 的解码和解封装(demuxer)一直缺失,对应的 ticket #4907 悬而未决 11 年。9.0 终于补全了这块短板:
# 解码动画 WebP 为帧序列
ffmpeg -i animated.webp frame_%04d.png
# 将帧序列重新打包为动画 WebP
ffmpeg -i frame_%04d.png -loop 0 output.webp
# 从视频提取动画 WebP(封面图)
ffmpeg -i video.mp4 -vf "select=eq(n\,0)" -frames:v 1 cover.webp
新增的 WebP 解码器处理 RGB 和 YUV 两种色彩空间,由 Josef Zlomek 发起、Ramiro Polla 完成。
3.2 HE-AAC 960:数字广播的盲区被填补
常规 AAC 使用 1024 采样帧,但欧洲 DAB+ 数字广播使用的是 960 采样帧的 HE-AAC。在 9.0 之前,FFmpeg 无法正确解码这类内容——音频会听起来音调偏高或出现解码错误:
# 解码 DAB+ 广播流(9.0 新支持)
ffmpeg -i dabplus_stream.ts -c:a aac audio.aac
# 解码并重采样为标准 PCM
ffmpeg -i dabplus_stream.ts -c:a pcm_s16le audio.wav
3.3 Playdate 编码器:复古掌机的视频支持
Playdate 是 Panic! Inc. 推出的复古风格手持游戏机,使用 1-bit 400×240 分辨率显示屏。9.0 新增了对该设备的原生视频编码支持,输出使用 delta 编码和 zlib 压缩:
ffmpeg -i input.mp4 \
-vf "scale=400:240:flags=neighbor" \
-c:v libplaydate \
-compression_level 5 \
output.pdv
3.4 新 API:avcodec_receive_frame_flags
9.0 新增的 avcodec_receive_frame_flags() 支持 AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS 标志,让低延迟消费者(如实时通信场景)绕过帧线程队列延迟:
#include <libavcodec/avcodec.h>
// 9.0 新增 API:支持同步帧接收,绕过帧线程延迟
int avcodec_receive_frame_flags(AVCodecContext *avctx, AVFrame *frame, int flags);
// 使用场景:WebRTC、游戏直播等需要立即得到解码结果的场景
if (low_latency_mode) {
ret = avcodec_receive_frame_flags(avctx, frame,
AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS);
} else {
ret = avcodec_receive_frame(avctx, frame);
}
3.5 NVENC 改进:AV1 分层 B 帧 + 12位输入
9.0 的 NVENC 改进包括 AV1 编码支持分层 B 帧参考模式(改善压缩效率)、兼容 Video Codec SDK 13.1,以及接受 12 位输入格式(内部截断为 10 位):
# 9.0 NVENC AV1 编码:启用分层 B 帧参考模式
ffmpeg -i input.mp4 \
-c:v hevc_nvenc \
-preset p4 \
-tune hq \
-rc vbr \
-rc-lookahead 32 \
-bf 7 \
output.hevc
# 12位输入自动截断为10位
ffmpeg -i input_12bit.yuv \
-c:v hevc_nvenc \
-pix_fmt p010le \
output.hevc
3.6 FFV1 Bayer:传感器直出无损压缩
专业相机传感器的 Bayer 色彩滤镜阵列(CFA)数据,以前必须先去马赛克(Demosaic)才能用 FFV1 压缩——这个过程不可逆,会损失信息。9.0 新增 FFV1 Bayer 支持:
# 编码 Bayer CFA 数据(保留全部原始传感器信息)
ffmpeg -f rawvideo -pix_fmt bggr16le -s 4096x3072 -i raw_bayer.raw \
-c:v ffv1_bayer \
-level 3 \
-slicecrc 1 \
output.mkv
# 解码回 Bayer 格式用于后期处理
ffmpeg -i output.mkv -pix_fmt bggr16le decoded_bayer.raw
Lynne 还实现了 Vulkan GPU FFV1 编解码器——完整编解码管线在 GPU 上运行,部分工作由 Sovereign Tech Fund 赞助。
四、Vulkan GPU 加速:全面铺开
9.0 最突出的技术主题,是 Vulkan 加速体系的系统化扩展。FFmpeg 正在摆脱对单一厂商 SDK 的依赖,构建跨平台的 GPU 加速基础设施。
4.1 v360_vulkan:8K 全景视频不再噩梦
360° 全景视频的投影格式转换(ERP、CubeMap、Equiangular Cubemap 等)计算量巨大,CPU 处理 8K 球面内容极其缓慢:
# CPU 方式(慢,适合小分辨率)
ffmpeg -i input_equi.mp4 -vf v360=equirect:equiangular output.mp4
# Vulkan 方式(快,8K 毫无压力)
ffmpeg -i input_equi.mp4 -vf v360_vulkan=equirect:equiangular output.mp4
4.2 APV Vulkan:Samsung 专业制作 Codec 的 GPU 加速
APV(Advanced Professional Video)是 Samsung 开发的专业制作编解码器,8.0 首次引入 FFmpeg,9.0 新增 Vulkan GPU 加速解码器。
4.3 运行时 GLSL 编译被移除
所有 Vulkan 着色器在构建时预编译为 SPIR-V,不再需要运行时 GLSL 编译器。构建产物更小,启动更快:
# scale / nlmeans / blackdetect 滤镜已移植到新 Vulkan 架构
ffmpeg -i input.mp4 -vf "scale_vulkan=1280:720" output.mp4
ffmpeg -i input.mp4 -vf "nlmeans_vulkan=s=10" denoised.mp4
4.4 NVIDIA CUDA 新滤镜
# transpose_cuda:画面旋转全程在 GPU 完成,无需 CPU 拷贝
ffmpeg -i input.mp4 -vf "transpose_cuda=dir=2" output.mp4
# 完整的 10/12 位 4:2:2 管线(NVDEC → CUDA 滤镜 → NVENC)
ffmpeg -c:v h264_cuvid -i input.mp4 \
-c:v hevc_nvenc -preset p4 -profile:v main10 \
-rc:v vbr -tune:v hq \
output_hevc.mp4
4.5 AMD AMF 增强
frc_amf:硬件辅助帧率转换(插帧)vqe_amf:视频质量增强(去噪、超分)vpp_amf新增完整 HDR 能力,含 HDR 元数据与 AMF 表示互译的公开 helpers
4.6 Apple VideoToolbox:ProRes RAW 硬件解码
在支持 VideoToolbox 的 Apple 芯片上直接硬件解码 ProRes RAW:
ffmpeg -c:v prores_videotoolbox -i prores_raw.mov \
-c:v prores_aw -profile:v 4444 \
output.mov
五、ONNX Runtime:将 AI 推理引入滤镜图
这是 9.0 中最具前瞻性、但最容易被忽视的变化。
FFmpeg 的 DNN 滤镜现在支持 ONNX Runtime GPU 执行提供者,涵盖:
- NVIDIA CUDA
- Windows DirectML(跨厂商 GPU)
- AMD Ryzen AI NPU(通过 VitisAI 执行提供者)
结合 8.0 引入的 Whisper 语音识别滤镜,现在可以构建这样的管线:
GPU解码 → Vulkan着色器处理 → ONNX超分辨率模型(GPU) → 编码输出
帧数据全程不碰 CPU。滤镜图正在从「像素处理工具」演变为一个 AI-native 的媒体处理层:
# 运行 ONNX 超分辨率模型(GPU 加速)
ffmpeg -i input_480p.mp4 \
-vf "hwupload_cuda,scale_onnx=model=espcn.onnx:device=gpu:ep=cuda" \
-c:v h264_nvenc output_1080p.mp4
# 结合 Whisper 进行语音识别 + 字幕生成(全程 GPU)
ffmpeg -i video.mp4 \
-vf "hwupload_cuda,scale_onnx=model=real_esrgan.onnx:ep=cuda" \
-c:v h264_nvenc \
-c:a pcm_s16le -f s16le - | \
ffmpeg -f s16le -ar 16000 -ac 1 -i - \
-c:a libwhisper -model medium -language zh \
subtitles.srt
六、HDR 与 Dolby Vision:专业化管线
6.1 Dolby Vision Profile 7 比特流过滤
Dolby Vision Profile 7(UHD 蓝光格式)将完整增强层 HEVC 比特流和 RPU 元数据交织在基础层流内部。9.0 新增 dovi_split 比特流过滤器:
# 从 Dolby Vision 流中分离基础层(向后兼容,标准播放器可播放)
ffmpeg -i dolby_vision.mkv \
-c:v copy -bsf:v 'dovi_split=mode=base' \
base_layer.mkv
# 专业后期处理:分离所有层
ffmpeg -i dolby_vision.mkv \
-c:v copy -bsf:v 'dovi_split=mode=full' \
-map 0:v:0 base.mkv \
-map 0:v:1 enhanced.mkv \
-map 0:v:2 rpu.mkv
6.2 SMPTE 2094-50 动态 HDR 元数据
新增对 HDR10+ 之外另一个 SMPTE 2094 格式的完整支持:解析、写入、透传,支持 libaom 和 libvpx 编码、Matroska block additions、ffprobe 输出。
6.3 统一 T.35 元数据处理
整个 ITU-T T.35 动态元数据体系(HDR10+、中国 HDR Vivid、AOM film grain、Active Format Description)现在通过一套统一的 helpers 处理,不再逐个编解码器重新实现:
# CLI 修正携带错误静态 HDR 元数据的文件
ffmpeg -i input.mp4 \
-mastering_display "red=x=0.680y=0.320:blue=x=0.148:y=0.060:green=x=0.265:y=0.690:white=x=0.3127:y=0.3290:max_lum=1000:min_lum=0.0010" \
-content_light "max=1000:avg=200" \
output.mp4
七、大清理:告别历史包袱
9.0 完成了一次彻底的历史债务清理:
| 移除项 | 说明 |
|---|---|
| OpenMAX 编码器 | 完全移除 |
| NPP 滤镜全家 | scale_npp、scale2ref_npp、sharpen_npp、transpose_npp 全部移除;transpose_cuda 接替,不再需要 libnpp |
| v308/v408/v410 | 这些奇特 packed-YUV 格式的专用编解码器移除 |
| NVENC 旧支持 | 旧 preset 别名、旧速率控制模式、SDK 11.1 以下全部移除 |
| 独立 CELT 解码器 | 自 2014 年损坏,十一年无人察觉。不影响 Opus(Opus 内含自己的 CELT) |
| Sonic 编解码器 | Michael Niedermayer 2000 年代初的实验性编解码器家族 |
TLS 证书验证:最容易被忽视的行为变更
FFmpeg 9.0 默认验证 TLS 证书。这是 8.0 预告过、9.0 正式落地的安全修复。如果服务器证书有问题,9.0 将无法连接:
# 开发环境下临时绕过(仅用于测试)
ffmpeg -tls_verify 0 -i https://bad-cert.example.com/stream.m3u8 ...
八、汇编与 SIMD 优化
x86(约 200 次提交)
Andreas Rheinhardt 主持了最底层 DSP 代码的现代化运动:
- 半像素运动补偿代码(hpeldsp 和 fpel,源自 MMX 时代)移植到 SSE2
- H.264 帧内预测增加 AVX2 水平预测器
- pp7 后处理 DCT 和 mpegvideoenc 中的最后 MMX 残余被清理
- 运动估计比较函数获得 SSSE3 版本的 median SAD
ARM(约 100 次提交)
- NEON yuv2rgb 路径重构为一次处理两行(覆盖 packed RGB、planar GBR、16-bit RGB、yuva420p、大端 16-bit)
- HEVC 帧内角度模式 10 和 26 获得 NEON 实现
- AAC SBR 和 float DSP 循环重新展开以更好填充现代流水线
- Ramiro Polla 构建了 rasm 汇编框架 —— 指令级 IR + builder API,在构建时生成链式 NEON 内核
RISC-V
持续跟进:RVV 优化 hevc_add_res 和 pixelutils SAD。大部分 RISC-V 向量能量投入了 dav1d,FFmpeg 通过 dav1d 的 AV1 解码免费获得性能提升。
九、libavformat:近 400 次提交,协议与封装进化
9.0 在格式层引入了多项重量级改进:
Demuxer 命令 API:新增 avformat_send_command() / avformat_receive_command_reply(),让应用与运行中的 demuxer 实时对话。首个用户为 RTSP(暴露 SET_PARAMETER),交互式摄像头控制不再需要带外连接。
shared: 协议并发块缓存:线程安全且跨进程,多个 FFmpeg 实例读取同一远程流可共享单个缓存文件。内存映射,流完全读取后缓存文件即为可用的本地副本。由 Niklas Haas 开发。
IAMF 动态参数:mix gain、demixing 信息、recon gain 作为正规帧侧数据暴露,ffprobe 和 showinfo 滤镜可打印。
Dolby Vision 流组模型(AVStreamGroupLayeredVideo,系 LCEVC 流组的泛化):支持在 MP4、MPEG-TS 和 Matroska 中 demux 时检测,mux 到 MP4 或 Matroska 时写出(含 hvcE 增强层配置)。
十、版本速查表
| 库 | 旧版 8.x soname | 新版 9.0 soname |
|---|---|---|
| libavutil | 60 | 61 |
| libavcodec | 62 | 63 |
| libavformat | 62 | 63 |
| libavdevice | 62 | 63 |
| libavfilter | 11 | 12 |
| libswscale | 9 | 10 |
| libswresample | 6 | 7 |
ABI 完全破坏,所有动态链接的下游必须重新编译。
十一、开发平台迁移:一个重要信号
FFmpeg 开发已正式迁移到自建的 Forgejo 实例 code.ffmpeg.org,与邮件列表并存。GitHub 上的 Pull Request 从 9.0 起 "will be ignored"。
这不是一次普通的技术迁移,而是 FFmpeg 社区对开源基础设施独立性的一次明确表态:代码托管平台的选择权,应该在社区自己手中。
本周期还有一个特殊贡献者——一个自动化 bug 发现机器人,提交了 9 个被接受的 demuxer 和协议安全加固补丁。AI 正在成为开源软件质量保障的重要力量。
十二、总结:自我革命的下限与上限
FFmpeg 9.0「Lei」做了两件重要的事:
向过去告别:清理了 NPP、OpenMAX、CELT、Sonic、MMX 汇编这些十多年未维护的历史包袱,TLS 证书默认验证,CLI 大量废弃选项移除。一个多媒体框架变大的同时,也在变干净。
向未来投资:swscale 二十年架构重写、Vulkan GPU 加速体系全矩阵铺开、Dolby Vision 完整管线、ONNX Runtime 将 AI 推理引入滤镜图——这些基础设施的搭建,为 FFmpeg 的下一个十年铺平了道路。一个「解码→滤镜→AI推理→编码」全程 GPU 化的管线正在从愿景走向现实。
而那个代号,让这次发布多了一层意义。
FFmpeg 的版本代号史上写满了牛顿、傅里叶、香农、霍夫曼——改变人类知识边界的名字。而这一次,它选择记住一个让知识跨越语言障碍的人。
十年了,雷神的博客还在教人写代码。他的名字,现在刻进了一个每天被数亿设备运行的、世界上最重要的多媒体框架里。
这是开源世界对知识传播者最深的敬意。