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 秒实验
- 只看流:
ffprobe -show_streams 片子.mp4,重点看time_base、pix_fmt、bit_rate。 - 只看格式:
ffprobe -show_format 片子.mp4,重点看duration有没有变成 N/A。 - 干净输出:
ffprobe -v error -print_format json -show_format -show_streams 片子.mp4,直接可以喂给程序。
常见误区
- 以为
-show_programs会打出东西。普通 mp4 上它什么都不输出,因为本来就没有节目这个概念。 - 一上来就跑
-show_frames。它最慢,而且大部分问题在 format 和 stream 两层就能看清。 - 拿 ffmpeg 当检查工具。它写文件,参数一错就可能覆盖原文件。检查用 ffprobe。
自测三问(点开对答案)
1. `Stream #0:1` 是什么意思? —— 第 0 个输入的第 1 条流。第一个数字是输入序号,第二个数字是该输入内的流序号。 2. 为什么 `ffprobe 文件` 能秒回,而 `-show_frames` 很慢? —— 前者只读容器头和流信息,后者要把每一帧都解码出来。慢的是解码,不是读取。 3. 三个工具里哪个最适合做「文件体检」? —— ffprobe。它只读不写,反复跑也不会改坏文件,而且输出可以转成 JSON 给程序解析。- ☐ (本节完,下一节 3.3.1 show_packets)