🎬 第五章 AVUtil通用工具层理论及案例实战
📄 一句话概括

八级日志,每级差 8;默认 INFO 太安静,排错先开 VERBOSE。 没日志不等于没事,可能压根没进到那层。

📝 本节和前面几节的关系

5.1 说 libavutil 管日志,这一节把日志用起来。 下一篇 5.3 换一个工具:解析器。

一、八个级别,数值是 C 侧的原样

级别之间有严格的包含关系:设成 VERBOSE,VERBOSE 及更严重的都打。 级别 数值 什么时候看


PANIC 0 进程要死了 FATAL 8 致命错误 ERROR 16 出错了 WARNING 24 有隐患 INFO 32 默认,信息很少 VERBOSE 40 排错第一档 DEBUG 48 看清每步 TRACE 56 内部细节

每级正好差 8,这是 C 侧的原始取值。记住 16、24、32 三个够用。 设置有两个函数:set_level 管 PyAV 自己的日志,set_libav_level 管底层库的。 一般用前者就够。

二、抓日志的三个要素

Capture 抓到的每条是三样东西:级别、来源、正文。 要素 例子 有什么用


级别 48 过滤噪音 来源 AVFormatContext 看是谁在说话 正文 Opening '…' for reading 真正的内容

「来源」这一栏比想象中有用。 写着 AVFormatContext 的是容器层, 写着具体格式名(mov,mp4,m4a…)的是那个解复用器。一眼看出问题出在哪一层。 设成 WARNING 之后,八级的噪音就压掉了六成:本机读这个小文件 DEBUG 有 98 条, 只留 WARNING 以上就只剩几条。排错与日常运行该用不同级别。

三、日志里能看出什么

举三条本机抓到的真话。 日志正文 读出来的意思


Setting default whitelist… 白名单默认就开着 probed with size=2048 and score=100 猜格式猜得很确定 Unknown dref type 0x206c7275 容器里有个不认识的引用

第一条纠正了一个常见误解:以为协议白名单要显式传才生效,其实默认就有一套。 第二条是猜格式的关键线索:score 满分是 100,分数低说明猜得不确定,格式可能认错。 遇上「明明是这个格式却打不开」,先看这一行的分数。 第三条说明「有不认识的东西」不等于「打不开」:这个文件照样读得好好的。 日志里有些是噪音,要学会跳过去。

四、一个反直觉的实测

打开一个不存在的文件,Capture 抓到 0 条日志。 按直觉该有一条 ERROR 说「文件不存在」,实际一条也没有。 因为 PyAV 在 Python 层就把路径挡住了,根本没走到 libavformat。 这条实测值一个结论:没日志不等于没事。 错误可能发生在更上层,那一层不用 FFmpeg 的日志系统。 排错顺序因此该是:先确认错误在哪一层(看异常类型与栈),再决定要不要去调日志级别。 反过来做会白折腾。

五、动手 Demo:打开 DEBUG,看 FFmpeg 自己在说什么

八级各是什么、抓一次真实日志、再制造一次错误看日志是否出现。

import av
import av.logging

av.logging.set_level(av.logging.DEBUG)
with av.logging.Capture() as cap:
    c = av.open("_media32/tiny.mp4")
    for p in c.demux(c.streams.video[0]):
        pass
    c.close()
av.logging.set_level(av.logging.WARNING)
print(len(cap))
print(cap[0])

实跑输出:

--------------------------------------------------------------------
打开 DEBUG,看 FFmpeg 自己在说什么
--------------------------------------------------------------------

**① 八个级别,每级差 8**

  级别        数值     什么时候看
  -----------------------------------------
  PANIC       0        进程要死了
  FATAL       8        致命错误
  ERROR       16       出错了
  WARNING     24       有隐患但不致命
  INFO        32       默认档,信息很少
  VERBOSE     40       排错第一档
  DEBUG       48       看清每一步
  TRACE       56       连内部细节都打

**每一级正好差 8**,这是 C 侧的原始取值,不是 PyAV 编的。
记住 16 是 ERROR、24 是 WARNING、32 是 INFO 就够用。

**② 抓一次真实的 DEBUG 日志**

打开并读完这个小文件,一共抓了 **98** 条。

**每条是三样东西:级别、来源、正文。** 头四条原文:

[0] 级别 48 / 来源 AVFormatContext
      Opening '_media32/tiny.mp4' for reading
[1] 级别 48 / 来源 file
      Setting default whitelist 'file,crypto,data'
[2] 级别 48 / 来源 mov,mp4,m4a,3gp,3g2,mj2
      Format mov,mp4,m4a,3gp,3g2,mj2 probed with size=2048 and score=100
[3] 级别 48 / 来源 mov,mp4,m4a,3gp,3g2,mj2
      ISO: File Type Major Brand: isom

**来源那一栏很有用**:写着 AVFormatContext 的是容器层,写着具体格式名的是那个解复用器。
**一眼看出这话是谁说的。**

**③ 日志里藏着有用的线索**

上面第二条写着 Setting default whitelist 'file,crypto,data'。
这说明**协议白名单默认就开着**,不是只有显式传才生效。

第三条写着 probed with size=2048 and score=100,说的是「拿前 2048 字节猜格式,猜得很确定」。
**猜错格式的时候,这一行会变成低分**,那就是线索。

**④ 一个反直觉的实测:Python 层拦下的错,FFmpeg 根本没说话**

打开不存在的文件,抛的是 **ArgumentError**。

而这次 Capture 抓到 **0** 条日志。

**是 PyAV 在 Python 层就把路径挡住了,没走到 libavformat。**
所以日志是空的。**没日志不等于没事,可能压根没进到那一层。**

**这条实测能省很多冤枉路**:调不出日志时先确认错误发生在哪一层,别一门心思调日志级别。

每条是三元组:级别数字、来源名、正文。 把级别设回 WARNING 很重要,否则后面的运行全是噪音。

30 秒实验

  1. 把 set_level 换成 av.logging.INFO,看抓到的条数少多少。
  2. 打开一个不存在的文件名,看 Capture 抓到几条。
  3. av.logging.get_skip_repeated() 看重复日志是否被折叠。

常见误区

  1. 以为没日志就是没事。 Python 层拦下的错,FFmpeg 不说话。
  2. 一直开着 TRACE。 性能会明显下降,日志量能把磁盘写满。
  3. 只看正文不看来源。 来源栏告诉你哪一层在说话,省一半排查时间。
自测三问(点开对答案) 1. 八个级别的数值为什么是 0、8、16…? —— 每级差 8,是 C 侧 AV_LOG_* 的原始取值。设某一级,比它严重的都会打。 2. 打开不存在的文件为什么抓不到日志? —— PyAV 在 Python 层就拦住了,没进到 libavformat,所以库没说话。 3. 日志里 score 那一行有什么用? —— 表示猜格式的确定程度,满分 100。分数低说明格式可能被认错。

相关笔记