10
0
0

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 安装 ffmpeg 的六步流程图:从 ffmpeg.org/download 官网的 Windows 段落进入 gyan.dev 或 BtbN 第三方构建页,下载 .7z 或 .zip 压缩包,解压得到 bin 目录,把 bin 这一层加进 PATH 环境变量,最后用 ffmpeg -version 验证;下方两张卡片说明官网只提供源码不给 exe 二进制、gyan.dev 的 essentials 与 full 两种构建怎么选,左下角是解压后的目录结构树,右侧代码块列出验证命令,底部给出 winget、scoop、choco 三种包管理器安装方式

官网的 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

签名密钥指纹要认准
  FCF986EA15E6E293A5644F10B4322F04D67658D8 rsa2048,2011-04-26 建立
  git tag 用的是另一把 EdDSA 密钥 DD1EC9E8DE085C629B3E1846B18E8928B3948D64
新版本还带了一份后量子签名
  .pq.asc 文件里有 ML-DSA-87+Ed448 和 SLH-DSA-256s 两份签名
  GnuPG 验不了这个,要用 sequoia-pgp 的 sq 1.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 拆包得到码流,decoder 解码得到原始帧,filter 滤镜做缩放裁剪水印,encoder 编码得到新码流,muxer 封装成新的输出文件;下方两张卡片分别解释容器层 demuxer 和 muxer 管怎么装、编码层 decoder 和 encoder 管怎么压,最下方绿色虚线框说明加 -c copy 之后中间三步全部跳过直接旁路

一个视频文件丢进 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 自描述信息查询命令表:按容器层、编码层、滤镜像素、其他四组分类列出 -version、-buildconf、-demuxers、-muxers、-formats、-decoders、-encoders、-codecs、-filters、-pix_fmts、-sample_fmts、-layouts、-colors、-devices、-protocols、-bsfs 共十几条命令及各自用途;下方两张卡片说明 ffprobe 与 ffplay 的定位、以及 decoders 和 encoders 两个名字的正确拼写与敲错后的现象

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 会让滤镜彻底哑火。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!