🎬 第一章 FFmpeg入门简介
📄 一句话概括

ffmpeg 转、ffplay 放、ffprobe 看,三个 exe 是同一个内核的三个外壳。 所以它们认识的格式完全一样,区别只在对外的那层。

📝 本节和前面几节的关系

1.2 装完了,这一节看看装到的三个程序各干什么。 1.3.2 往下走一层,看它们调的是哪些库。

一、三个外壳,一个内核

它们的分工可以一句话说完:

工具 输入 输出 压在哪些库上


ffmpeg 文件或流 文件或流 format + codec + filter ffplay 文件或流 一个窗口 上面三个再加 SDL ffprobe 文件或流 文字 主要只用 format

三个都建立在同一套 libav* 上,所以「ffprobe 认得的格式 ffmpeg 一定认得」。 反过来不成立:ffmpeg 能编码,ffprobe 根本不管编码。

这个关系决定了一件事:排障时先用 ffprobe 看清输入,再用 ffmpeg 处理。 跳过第一步直接转,参数猜错的地方就找不出来了。

二、ffmpeg -formats 的那两列

这份清单每行后面有个字母,很多人扫一眼就过,其实信息量很大:

标记 含义 能干什么


D 能解封装(Demux) 能作为输入读进来 E 能封装(Mux) 能作为输出写出去 DE 读写都行 可以做中转,转封装靠它们

所以「mp4 能不能转成 webm」这种问题,看两行的标记就知道: mp4 有 D,webm 有 E,两个都是 DE,走得通。

只有 D 的那些多半是老采集格式,只有 E 的多半是输出专用。 做转封装时两边必须都能读能写,中间那一段才成立。

三、ffplay 不只是播放器

很多人装了 ffplay 从来不用,其实它是最好用的调试工具:

用法 能看出什么


ffplay 文件 最快确认这个文件到底能不能放 ffplay -stats 文件 实时码率、帧率、音视频偏差 ffplay -vf 滤镜 文件 直接预览滤镜效果,不落盘 ffplay -af 滤镜 文件 预览音频滤镜,比如响度归一

第三行是最有价值的:写滤镜链时不用先转一个文件出来看效果,直接预览。 调一次参数只要几秒,比「转一遍再看」快一个数量级。

Windows 上的 ffplay 还带一个隐藏好处:它不依赖任何播放器框架。 系统自带的播放器打不开的怪文件,ffplay 往往能放——因为它用的是 FFmpeg 自己的解码器。

四、ffprobe 的价值是「只看不动」

它是三个里最不显眼、用得最多的一个:

问什么 参数 输出什么


有几条流 默认就够 每个流的类型与编码 每帧多大 -show_frames 逐帧的大小与类型 每个包多大 -show_packets 逐包的时间戳与大小 格式总览 -show_format 时长、码率、元数据

这四个参数基本覆盖了「这个文件是怎么回事」的所有问题。 调不动参数的时候,先 -show_packets 看一眼包的时间戳,问题常常自己就露出来了。

它还有一个别的工具做不到的事:-print_format json。 把输出变成 JSON,程序直接解析,不用去切字符串。 做自动化的时候,这一项比什么都重要。

五、动手 Demo:ffmpeg 转、ffplay 放、ffprobe 看

这一段把三个工具压的库摊开,再把 formats 清单的 D/E 分布数出来。 顺带说清楚 rtmp 为什么不在格式表里。

import av

both = inn = out = 0
for n in av.formats_available:
    f = av.format.ContainerFormat(n)
    if f.is_input and f.is_output:
        both += 1
    elif f.is_input:
        inn += 1
    elif f.is_output:
        out += 1
print(u"只能读", inn, u"只能写", out, u"都能", both)

for n in (u"mp4", u"rtmp"):
    try:
        print(n, av.format.ContainerFormat(n).long_name)
    except Exception as e:
        print(n, u"不在格式表里")

实跑输出:

--------------------------------------------------------------------
三个工具——ffmpeg 转、ffplay 放、ffprobe 看
--------------------------------------------------------------------

**① 三个 exe,分工是三句话**

  工具        干什么                     压在哪些库上
  ------------------------------------------------------------------
  ffmpeg      转码、转封装、加滤镜       format + codec + filter
  ffplay      播出来,带窗口与波形       上面三个再加 SDL
  ffprobe     只看不转,把信息打出来     只需要 format

**三个工具是同一份库的三个外壳,所以它们认识的格式完全一样。**
**ffprobe 能读出来的东西,ffmpeg 一定也能读;区别只在 ffmpeg 顺手把它转了。**

**② ffmpeg -formats 那两列 D 和 E,在这儿能数出来**

  能力           格式数     对应标记     是什么
  ----------------------------------------------------------------------
  只能解封装     232        d            能读不能写,多是老采集格式
  只能封装       46         e            能写不能读,多是输出专用
  读写都行       136        de           mp4、flv、ts 这类主力
  合计           414        —            就是 ffmpeg -formats 的行数

**能读的 368 个、能写的 182 个——读的比写的多一倍。**
**做转封装时「从什么转到什么」,可行性就在这两列里:**
**两边都得能读能写,中间才走得通。**

**③ 顺手把一个常踩的坑说清:rtmp 不在这张表里**

  名字       在格式表里吗     它其实是什么
  ------------------------------------------------------
  mp4        在               封装格式,管文件怎么排
  flv        在               封装格式,管文件怎么排
  mpegts     在               封装格式,管文件怎么排
  rtmp       不在             传输协议,管流怎么送

**格式管「码流怎么摆进文件」,协议管「字节怎么走上网络」,是两层东西。**
**所以查不到 rtmp 不代表不能用——它是被登记在协议表里的。**
**上一门课栽过的那个坑就是这个:库能编出 flv 封装,但没编进 rtmp 协议,**
**open 照样返回成功,一个字节都不发。**

第一张表把三个工具的分工和它们依赖的库对应起来。 ffprobe 只用 format 层,所以它最轻、也最快。

第二张表是 D/E 标记的量化:能读的 368 个,能写的 182 个。 读的比写的多一倍——所以「什么都能打开,但不是什么都能存」。

第三张表点出一个常踩的坑:rtmp 不在格式表里。 格式管「码流怎么摆进文件」,协议管「字节怎么走上网络」,是两层东西。

上一门课栽过的坑就是这个:库能编出 flv 封装,但没编进 rtmp 协议。 open 照样返回成功,一个字节都不发——「能打开」不等于「能工作」。

30 秒实验

  1. 数标记:ffmpeg -formats | grep "^ DE" 数出读写都行的格式。这个数是你能做转封装的格式对数。
  2. 先看再转:拿一个不认识的文件,先 ffprobe 文件 看有几条流、什么编码,再决定用什么参数转。这个顺序能省掉一半的试错。
  3. 预览滤镜:ffplay -vf scale=320:-1 文件,把 320 换成别的数值,直接看效果,不产生任何临时文件。

常见误区

  1. 以为装了 ffmpeg 就有 ffplay。三个 exe 是一起发的,但有些精简包会删掉 ffplay 省体积。where ffplay 查一下就知道。
  2. 以为 ffprobe 只能看信息所以没用。它是唯一能给出「逐帧逐包」细节的工具,调参数时离不开它。
  3. 把「能打开」当成「能工作」。协议缺失时 open 可能成功但一个字节都不发。判断标准是真跑一次,看输出有没有增长。
自测三问(点开对答案) 1. ffprobe 能不能把一个 mp4 转成 flv? —— 不能。它只解封装、不解码也不编码,更不封装输出。转封装要用 ffmpeg,加上 `-c copy`。 2. `ffmpeg -formats` 里某一行标着 `D`,说明什么? —— 这个格式可以作为输入读进来。没有 E 就不能作为输出写出去,所以它做不了目标格式。 3. 为什么 rtmp 不在格式表里,却能用 `-f flv rtmp://...`? —— rtmp 是传输协议不是封装格式。`-f flv` 指定的是封装,rtmp:// 那部分交给协议层处理。两层各管各的。

相关笔记