🎬 第三章 FFmpeg三大常用工具及应用选项详解
📄 一句话概括

ffprobe 只做一件事:把文件的信息打出来,但做得最细。 输出永远是三段,附加段要哪个就加哪个参数。

📝 本节和前面几节的关系

3.1 讲了三个工具的分工,3.2 讲完了 ffplay,这一节轮到 ffprobe。 3.3.1 到 3.3.6 逐个讲它的六个 show_* 参数。

一、三个工具的能力边界

三个工具里,ffprobe 是唯一「只读不写」的:

工具 读文件 写文件 显示


ffmpeg 能 能 不显示 ffplay 能 不能 显示 ffprobe 能 不能 打印文本

第三行那个「不能写」是它最大的优点:拿它做检查,跑一百遍也不会改坏文件。 ffmpeg 就不行——参数写错一个字母,输出文件就可能覆盖掉原文件。

所以「先看再动」这个习惯,工具层面上就是「先 ffprobe,再 ffmpeg」。 两分钟能看清的东西,比事后从备份恢复便宜得多。

二、输出永远是三段

认清结构再看内容,不然几千行输出里找不到想要的那句:

段 以什么开头 讲什么


输入段 Input #0, 容器名、时长、码率、元数据 流段 Stream #0:0 每条流的编码、分辨率、时间基 附加段 其他 show_* 的内容 包、帧、章节、程序

第二段的编号规则要记住:#0:0 是「第 0 个输入的第 0 条流」。 有多个输入时第一个数字会变成 0、1、2,第二个数字是该输入内的流序号。

这个编号和 -map 里的编号是同一套。 所以 ffprobe 看到的 #0:1,就是 -map 0:1 指的那一条——两边能直接对上。

三、六个 show_* 参数

不加任何参数时,ffprobe 只打前两段。附加段要你主动要:

参数 问的是 典型用途


-show_format 整个文件 时长对不对、码率多少 -show_streams 每条流 编码支持的了吗 -show_packets 每个包 时间戳从几开始 -show_frames 每一帧 解出来的画面正常吗 -show_chapters 章节 有没有分章 -show_programs 节目 TS 流里的多节目

前四个是日常用的,后两个只在特定封装格式里才有内容。 尤其 -show_programs,普通 mp4 上跑它什么都不输出——不是坏了,是本来就没有。

「越问越细、越问越慢」这个规律要记住: 前两个几乎瞬间返回,-show_frames 要把整片解一遍。 所以排障顺序是从上往下,不要一上来就问最细的。

四、动手 Demo:它只做一件事,但做得最细

这一段把「三段结构」在库这一层复现一遍,确认每一段对应哪个对象。 同时验证:不加 show_* 参数时,确实只有前两段。

import av

c = av.open(u"src3.mp4")

# 输入段
print(u"容器 %s" % c.format.name)
print(u"时长 %.2f 秒" % (float(c.duration) / 1000000))
print(u"流数 %d" % len(c.streams))

# 流段
for s in c.streams:
    cc = s.codec_context
    print(u"#0:%d  %s  %s" % (s.index, s.type, cc.name))

# 附加段:要了才有
npk = sum(1 for pk in c.demux(video=0) if pk.size)
print(u"包数 %d(这一步对应 -show_packets)" % npk)
c.close()

实跑输出:

--------------------------------------------------------------------
ffprobe 工具简介——它只做一件事,但做得最细
--------------------------------------------------------------------

**① 三个工具的能力边界**

  工具        读文件     写文件     显示
  ----------------------------------------------
  ffmpeg      能         能         不显示
  ffplay      能         不能       显示
  ffprobe     能         不能       打印文本

**ffprobe 是三个里唯一「只读不写」的,所以拿它做检查最安全——跑一百遍也不会改坏文件。**

**② 它的输出永远是三段,先认清结构再看内容**

  段         以什么开头             讲什么
  ------------------------------------------------------------------
  输入段     Input #0,              容器名、时长、码率、元数据
  流段       Stream #0:0            每条流的编码、分辨率、时间基
  附加段     其他 show_* 的内容     包、帧、章节、程序

**第二段的编号规则要记住:`#0:0` 是「第 0 个输入的第 0 条流」。**
**有多个输入时(比如同时开两个文件),第一个数字会变成 0、1、2。**

**③ 本机这份素材的三段内容**

  段         本机实测到的内容
  -----------------------------------------------------
  输入段     容器 mov,mp4,时长 5.0 秒,1 条流
  流段       h264,160x90,时间基 1/12800
  附加段     要不要看,取决于你加了哪个 show_* 参数

**注意:不加任何 `-show_*` 参数时,ffprobe 只打前两段。**
**附加段是你主动要的,要哪一段就加哪个参数——这也是它「越问越细」的原因。**

**④ 六个 show_* 参数,按「问什么」排**

  参数               问的是       典型用途
  --------------------------------------------------------
  -show_format       整个文件     时长对不对、码率多少
  -show_streams      每条流       编码支持的了吗
  -show_packets      每个包       时间戳从几开始
  -show_frames       每一帧       解码出来的画面正常吗
  -show_chapters     章节         有没有分章
  -show_programs     节目         TS 流里的多节目

**前四个是日常用的,后两个只在特定封装格式里才有内容。**
**3.3.1 到 3.3.4 逐个讲前四个,3.3.5 讲输出格式,3.3.6 讲怎么挑流。**

三段在这里对应三个层次:c.format 是输入段、c.streams 是流段、 c.demux() 出来的包才是附加段。不加 -show_packets 时,ffprobe 连这一步都不做。

最后那行注释很重要:包数是「主动去读」才有的。 所以 ffprobe 文件 能秒回,ffprobe -show_packets 文件 就要顺着读一遍。

还有一个细节:-show_frames 比 -show_packets 还慢一层, 因为它不光要读包,还要解码。码率越高、分辨率越大,差距越明显。

30 秒实验

  1. 只看流:ffprobe -show_streams 片子.mp4,重点看 time_base、pix_fmt、bit_rate。
  2. 只看格式:ffprobe -show_format 片子.mp4,重点看 duration 有没有变成 N/A。
  3. 干净输出:ffprobe -v error -print_format json -show_format -show_streams 片子.mp4,直接可以喂给程序。

常见误区

  1. 以为 -show_programs 会打出东西。普通 mp4 上它什么都不输出,因为本来就没有节目这个概念。
  2. 一上来就跑 -show_frames。它最慢,而且大部分问题在 format 和 stream 两层就能看清。
  3. 拿 ffmpeg 当检查工具。它写文件,参数一错就可能覆盖原文件。检查用 ffprobe。
自测三问(点开对答案) 1. `Stream #0:1` 是什么意思? —— 第 0 个输入的第 1 条流。第一个数字是输入序号,第二个数字是该输入内的流序号。 2. 为什么 `ffprobe 文件` 能秒回,而 `-show_frames` 很慢? —— 前者只读容器头和流信息,后者要把每一帧都解码出来。慢的是解码,不是读取。 3. 三个工具里哪个最适合做「文件体检」? —— ffprobe。它只读不写,反复跑也不会改坏文件,而且输出可以转成 JSON 给程序解析。

相关笔记