01-ffmpeg 基础:安装与工作原理
📝 笔记摘要:ffmpeg 基础,安装与工作原理
ffmpeg 是一个命令行工具,一个 ffmpeg.exe 把格式工厂、剪辑软件、录屏工具、推流工具全揽了。它难的地方不在命令多,而在于参数是按内部那条五步流水线分类的——分错了步,参数就会互相打架,比如写了滤镜却发现画面一点没变。
这篇先把 ffmpeg 装明白,再把它的工作原理拆开:文件进去之后到底经历了什么、每一类参数管哪一段、查能力该敲哪条命令。理清这条流水线,后面的转码、剪辑、录屏、推流就都是往里填参数。
ffmpeg 系列 共 3 篇,这是第 1 篇
01-ffmpeg 基础 安装与工作原理 ← 本篇
02 ffmpeg 转码与剪辑实战 容器、编码、滤镜与画质
03 ffmpeg 录制与直播 录屏、摄像头与推流
1. 装 ffmpeg
1.1 Linux
Linux 上装 ffmpeg 有两条路:发行版仓库直接装,或者源码编译。源码编译那套(依赖清单、编译选项、装完怎么验收)单独写过一篇:CentOS 环境安装 ffmpeg,要自己编译就去看那篇。
只是想用,仓库版本最快:
# Debian / Ubuntu
sudo apt install ffmpeg
# CentOS / RHEL / Rocky
sudo dnf install ffmpeg
仓库版本一定落后
发行版打包跟着自己的节奏走,Debian 12 里的版本可能还停在 6.x
要新版本就源码编译,或者去 BtbN 拿静态构建
静态构建在官网只有 BtbN 一家——ffmpeg.org 的 Linux Static Builds 段落就列了他一个链接
仓库版本有个坑
发行版为了合规经常砍掉libx264、libx265、fdk-aac
装完先敲ffmpeg -hide_banner -encoders | grep libx264确认一下
查不到就是没有,这时候-c:v libx264会直接报 Unknown encoder
静态构建适合塞进容器
自带全部依赖库,同架构的机器上扔过去就能跑
做 CI 里的视频处理,不用在镜像里装一堆--enable-*依赖
1.2 Windows
官网的 Windows 段落点进去只有两个链接:gyan.dev 和 BtbN。它们不是官方,但打包得比官方还整齐——官方只提供源码,exe 全靠社区自己编译。gyan.dev 上有两种构建:essentials 体积小、日常够用,full 多带一堆冷门库。
解压出来是一个目录,里面有个 bin,要加进 PATH 的是 bin 这一层,不是它的上级目录。加错了目录,在任何地方敲 ffmpeg 都会得到「不是内部或外部命令」。
不想手动解压就走包管理器:
winget install "FFmpeg (Essentials Build)"
scoop install ffmpeg-essentials
choco install ffmpeg
PATH 改完要重开终端
当前窗口还拿着旧的环境变量,敲ffmpeg照样报「不是内部或外部命令」
这是装完第一件会怀疑人生的事——明明加了路径为什么还不行
.7z要用 7-Zip 解
Windows 自带的解压支持不了 7z 格式
gyan.dev 的 essentials 同时提供.zip版本,选它省事
解压出来是三个 exe,不是一个
ffmpeg.exe转码、剪辑、推流的主力
ffprobe.exe只读分析,不改任何像素
ffplay.exe简易播放器,偶尔用来预览
要烧字幕就选 essentials
libass在 essentials 构建里才有,full 里当然也有
但libvmaf、whisper这些只有 full 才有,按需选
1.3 版本现状
ffmpeg.org 的下载页顶上就是完整的 release 分支列表,不用凭印象记版本号——大版本大约每半年一个,凭印象写的号基本都是错的。
当前最新的几个分支
9.0.2 "Lei" 2026-09-18 发布,9.0 分支 2026-06-26 从 master 切出 ← 当前主线
8.1.3 "Hoare" 2026-09-21 发布,8.1 分支 2026-03-08 切出
8.0.3 "Huffman" 2026-06-18 发布,8.0 分支 2025-08-09 切出
7.1.5 "Péter" 2026-06-20 发布,7.1 分支 2024-09-24 切出
6.1.6 "Heaviside" 2026-06-20 发布,6.1 分支 2023-10-29 切出
5.1.10 "Riemann" 2026-06-21 发布,5.1 分支 2022-07-13 切出
4.4.8 "Rao" 2026-06-21 发布,4.4 分支 2021-04-08 切出
8.1.3 比 9.0.2 还晚三天发布
这不是笔误——大版本发布之后,维护分支还会继续拿安全补丁
生产环境守旧分支是有道理的:老分支拿到的只有修复,没有新功能带来的行为变化
官网明确说 release 分支是给发行版和系统集成商用的
真正做开发的应该盯 master 分支,那是开发者唯一在动的分支
安全补丁进 release 分支最快,所以「用旧版本」不等于「用不安全版本」
版本表下面还有一段容易被人略过的内容:所有 release 都带密码学签名。
# 导入官方公钥
curl https://ffmpeg.org/ffmpeg-devel.asc | gpg --import
# 校验源码包
gpg --verify ffmpeg-9.0.2.tar.xz.asc ffmpeg-9.0.2.tar.xz
签名密钥指纹要认准
FCF986EA15E6E293A5644F10B4322F04D67658D8rsa2048,2011-04-26 建立
git tag 用的是另一把 EdDSA 密钥DD1EC9E8DE085C629B3E1846B18E8928B3948D64
新版本还带了一份后量子签名
.pq.asc文件里有 ML-DSA-87+Ed448 和 SLH-DSA-256s 两份签名
GnuPG 验不了这个,要用 sequoia-pgp 的sq1.4 以上版本
并且需要一个支持这些算法的加密后端(OpenSSL 3.5 或 RustCrypto)
两份签名都必须验证通过才算数
Windows 的第三方构建不用这招
gyan.dev 在每个包旁边放的是.sha256文件,校验文件完整性,不是来源真实性
校验 sha256 至少能挡住下载损坏和中间篡改,顺手验一下不亏
1.4 一个必须知道的安全问题
CVE-2026-64831 是 FFmpeg 8.0 到 8.1.2 的一个栈缓冲区溢出,位置在 Vulkan HEVC 硬件解码器的 vk_hevc_end_frame 函数里。
CVSS 3.1 打分 8.8,评级 HIGH
CWE-121,基于栈的缓冲区溢出
攻击面是网络:攻击者构造一个特制的 HEVC / H.265 码流就能触发
不需要权限,不需要复杂条件,但需要用户交互(打开那个文件)
可能造成任意代码执行
原理说白了就一句话
码流里的vps_num_hrd_parameters可以塞一个超过HEVC_MAX_SUB_LAYERS的值
这个值直接写进了栈上的数组,越界就把返回地址和相邻栈帧一起覆盖掉
修复版本
8.1.3 和 9.0.2 都不受影响——修复提交92737390已经合进去
openEuler 在 24.03 LTS 的各个 SP 版本已于 2026-08-30 打出修复包
这个漏洞只影响开了 Vulkan 硬解的用户
绝大多数人根本没开 Vulkan,用软件解码的完全碰不到
但如果你在跑-hwaccel vulkan,或者机器里有独显并且启用了 Vulkan 硬解,那就必须升
为什么值得专门提
ffmpeg 常常被塞进各种服务里——视频转码接口、媒体处理流水线、直播网关
这类场景里「用户交互」这个前置条件可能根本不成立,攻击者直接发一个文件过来就行
2. ffmpeg 到底在干什么
一个视频文件丢进 ffmpeg,它会走完五步:
demuxer 拆包
把 mp4 / mkv / flv 这个容器拆开,取出里面的视频轨、音频轨、字幕轨
这一步不碰画面,只是把轨道取出来,所以画质零损失
decoder 解码
把 H.264 这类编码的码流还原成一帧一帧的原始像素
常见的结果是 yuv420p 格式的无压缩数据
filter 滤镜
缩放、裁剪、加水印、调色、混字幕、改帧率,都发生在这一步
改的是原始帧,改完再交给编码器重新压
encoder 编码
把原始帧重新压成 H.264 / H.265 / AAC
这一步才可能有画质损失,也是唯一有损失的一步
muxer 封装
把编码好的新码流装进一个新的容器,写成输出文件
容器选 mp4 还是 mkv,只影响这一层
有两件事必须掰清楚,不然参数怎么写都会绕。
mp4、flv、mkv 是容器,不是编码
编码是 H.264、H.265、VP9、AV1、AAC 这些
「把 mp4 转成 flv」这句话本身不成立
同一个 H.264 码流可以直接装进 mp4 也可以装进 flv,那叫转封装
要真的把 H.264 变成 H.265,那才叫转码
转封装不损失画质,转码才损失
这条分界线决定了后面所有的参数选择
只需要换容器 → 加-c copy,秒级完成,画质分毫不动
需要改分辨率、加水印、换编码 → 必须去掉-c copy,走完五步
-c copy是条捷径
加上它之后 decoder、filter、encoder 全部不执行
码流从 demuxer 直接进 muxer,快到几乎不花时间
代价是滤镜彻底失效——你写了-vf它也不报错,只是画面毫无变化
3. 三个 exe 各管什么
ffmpeg 干活的那个。转码、剪辑、录屏、推流都靠它
ffprobe 只读分析,一个像素都不改
ffplay 简易播放器,偶尔用来预览,不常用
剪辑前先 ffprobe 一下,比瞎试快得多
ffprobe -v error -show_format -show_streams in.mp4看时长、分辨率、编码、码率
ffprobe -v error -select_streams v:0 -show_entries frame=pts_time,pict_type in.mp4看关键帧在哪
知道关键帧位置,裁剪的时候心里才有数
4. 查能力:ffmpeg 自带的说明书
ffmpeg 自带的能力查询命令,比翻文档快,比猜参数准。
是
-decoders和-encoders
不是-decodecs、-encodecs这两个是常见的手误
敲错不会报「命令不存在」——ffmpeg 把它当成未知选项,直接打印一堆帮助然后退出
判断办法:输出里出现 help 就说明敲错了,正常输出是一张表
加-hide_banner输出干净一半
默认那段版本横幅又长又占地方,加了这个参数就没了
ffmpeg -hide_banner -encoders | grep libx264
写-c:v libx264之前先查一下
查得到、才敢写——发行版的包经常砍掉 x264、x265、fdk-aac
不查就是等下转码时才发现,白白等一遍
-pix_fmts里的格式名是 yuv 不是 yua
实际看到的名字长这样:yuv420p、yuv422p、yuv444p、rgb24
这一项决定了「编出来别人播不了」的绝大多数情况
-formats里的字母要认
D 能解、A 能编、E 两者都能
-devices是录屏前的第一步
先看这台机器上有哪些设备类型可用,再去拼采集命令
5. 一条命令的结构
ffmpeg 的命令行看着长,其实是一个固定骨架:
ffmpeg [全局选项] [输入选项] -i 输入文件 [输入选项] [输出选项] 输出文件
选项的位置决定它管哪一段——这是最需要记住的一条规则。
-i之前的是输入选项
管的是「怎么读这个文件」:-ss、-t、-r、-f
-i之后的是输出选项
管的是「怎么写这个文件」:-c、-b:v、-vf、-movflags
写错了不会报错,只会没效果
把-vf写到-i前面,ffmpeg 会当成输入选项忽略掉
画面一点没变,而你以为滤镜没生效
-ss放前放后,行为完全不同
放在-i前面:快速跳转,直接跳到那个时间点再解码,快
放在-i后面:精确裁剪,从头解到那个点再丢掉,准但慢
这是 ffmpeg 里最经典的一个「差一点」,裁剪章节会展开
一个文件可以当多个输入
-i写几次就有几个输入,滤镜图里用[0][1]编号引用
输出也可以有多个,最后列几个文件名就分几个
💡 补充几个容易忽略的:
一定要加-y
输出文件已存在时,ffmpeg 会停下来问你「Overwrite? [y/N]」
在脚本里这等于卡死——它等着一个永远不会来的输入
-y直接覆盖,-n直接不写
进度信息走的是 stderr
frame= 1280 fps= 45 q=28.0 time=00:00:28.64这些是标准错误输出
要接进日志系统,别去 stdout 捞
-v error只留错误
配合-hide_banner,输出干净得能直接当日志
-progress pipe:1是机器可读的进度
输出 key=value 的结构化数据,写脚本监控的时候比解析那堆frame=靠谱
ffmpeg 能往 stdout 吐数据
-f rawvideo -就是往标准输出写裸视频
在管道里记得加-nostdin,不然它会抢你的标准输入
官方滤镜文档是ffmpeg-filters.html
在 ffmpeg.org/documentation.html 里,是查滤镜参数最权威的地方
每个滤镜的文档都列了它接受哪些选项,比记忆靠谱
🔥 一句话总结:ffmpeg 的参数是按「拆包 → 解码 → 滤镜 → 编码 → 封装」这条五步流水线分类的,
-i前面的选项管输入、后面的管输出,位置写错不报错只是没效果;Windows 上 exe 从 gyan.dev 拿、解压后把 bin 那一层加进 PATH 并重开终端,当前主线是 9.0.2(维护分支 8.1.3 还在拿安全补丁),CVE-2026-64831 影响 8.0~8.1.2 的 Vulkan HEVC 硬解,8.1.3 和 9.0.2 已修;查能力用-decoders、-encoders、-pix_fmts(不是-decodecs),输出里冒出 help 就是名字敲错了;记住-c copy会让滤镜彻底哑火。
