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

libavutil 不在链上,在链下面——每个环都在用它。 视频能穷举、音频只能点名,这个不对称会一直跟着你。

📝 本节和前面几节的关系

第四章讲完整条链,从这一章开始拆链下面的地基。 这一节先看它给了什么,5.2 起逐个用起来。

一、它管四件事

第二章提过一遍,这里说清具体给了什么。 类 东西 谁在用


内存 av_malloc、AVBuffer 所有库 结构 AVRational、AVDictionary 传参数、表示时间 日志 av_log 八级 排错时唯一的信息源 枚举 像素格式、采样格式 swscale 与 swresample

四件事里,前两件在 Python 侧基本被藏起来了。 内存不用管,AVRational 与字典还在。 日志与枚举是还能直接用的两样。 这一章剩下的四节就是讲日志、解析、字典、选项。

二、能数出来的五个量

这五个数是同一个构建的指纹,换台机器就会变。 条目 从哪数


编解码器 av.codecs_available 封装格式 av.formats_available 滤镜 av.filter.filters_available 像素格式 av.video.format.names 比特流过滤器 av.bitstream_filters_available

本机这五个数是 557、414、468、267、49。 对不上别人报的数,说明装的不是同一个构建,不是代码写错了。这一条在排错时省很多时间。

三、两个数不出来的,是 PyAV 的缺口

视频侧能列 267 种像素格式,音频侧却一个枚举入口都没有。 想数的 能不能数 怎么替代


视频像素格式 能 av.video.format.names 音频采样格式 不能 按名字构造 AudioFormat 声道布局 不能 按名字构造 AudioLayout

所以音频格式只能「点名」:写 av.AudioFormat('s16')、av.AudioFormat('fltp')。 名字写错才报错,事先查不到全集。 这个不对称会一直跟着你:第八章讲编解码、第十章讲重采样时,音频侧总有些东西查不到,只能试。 知道这是库的缺口,就不会以为是自己的问题。

四、时间基用分数存,不用小数

这是 libavutil 里最该理解的一个设计。 东西 值 含义


av.time_base 1000000 一秒分成一百万格 AVRational(1, 25) 1/25 25 帧率的刻度 pts 整数 第几格

1/25 写成 0.04 就有误差,乘上几十万帧之后误差会累积。 用分数存,换算全是整数乘除,一位不丢。 看见浮点数出现在时间计算里,就该警惕。 正确做法是全程整数,只在显示给人看的那一步才换成秒。

五、动手 Demo:libavutil 到底给了什么

数一数能数的,再确认哪两个数不出来。

import av
import av.filter

print("codecs", len(av.codecs_available))
print("formats", len(av.formats_available))
print("filters", len(av.filter.filters_available))
print("pix fmts", len(av.video.format.names))
print("bsf", len(av.bitstream_filters_available))
print("time_base", av.time_base)
print("rational", av.AVRational(1, 25))

实跑输出:

--------------------------------------------------------------------
libavutil 到底给了什么
--------------------------------------------------------------------

**① 能数出来的五个量**

  条目             数量     从哪数
  ------------------------------------------------------------
  编解码器         557      av.codecs_available
  封装格式         414      av.formats_available
  滤镜             468      av.filter.filters_available
  像素格式         267      av.video.format.names
  比特流过滤器     49       av.bitstream_filters_available

**这五个数是同一个构建的指纹。** 换一台机器、换一次编译配置,五个数都可能变。

**② 有两个数不出来,这是 PyAV 的缺口**

视频侧能列 **267** 种像素格式,音频侧却一个枚举入口都没有:
av.audio.format 里只有 AudioFormat 这个类,没有 names。

**所以音频格式只能按名字构造**:av.AudioFormat('s16')、av.AudioFormat('fltp')。
写错名字才报错,事先查不到全集。

**声道布局也一样**,AudioLayout 没有 names。
**视频能穷举、音频只能点名**——这个不对称在处理音频时会反复遇到。

**③ libavutil 里最常用的两样:时间基与有理数**

  东西                     值          干什么用
  ---------------------------------------------------------
  av.time_base             1000000     微秒那一档的刻度
  AVRational(1, 25)        1/25        用分数表示时间基
  AVRational(1, 12800)     1/12800     视频流的时间基

**时间基用分数存不用小数**,是为了不丢精度。1/25 写成 0.04 就有误差,乘上几十万帧之后误差会累积。

**这个设计在整条链上到处可见**:pts 是整数、时间基是分数、换算全靠整数乘除。
看见浮点数出现,就该警惕精度问题。

**④ libavutil 还是个错误码的大仓库**

av.error 里有 **68** 个名字,全是异常类。
它们按成因分家:找不到解码器、格式不对、协议不支持、数据坏了……

**分开捕获能给出更准的提示。** 一律 except Exception,界面上就只能显示「出错了」,
用户不知道该怎么办。

五个数与 2.1、2.9 报的一致,因为是同一台机器同一个构建。 av.AVRational(1, 25) 打出来是 1/25,不是 0.04。

30 秒实验

  1. len(av.error.__dict__) 之外的写法:dir(av.error) 数异常类有多少个。
  2. 试着 av.AudioFormat("fltp"),再试一个瞎写的名字看报什么错。
  3. av.video.format.names 里找一个你认识的格式,确认它在。

常见误区

  1. 拿网上的数量核对本机。 数取决于构建配置,不等于环境坏了。
  2. 以为音频侧也能枚举。 PyAV 没给入口,只能按名字构造。
  3. 时间用浮点数算。 精度会累积,全程该用整数加有理数。
自测三问(点开对答案) 1. libavutil 在链上还是在链下? —— 链下。它不产生任何产物,是每个环都在用的地基。 2. 为什么音频格式数不出来? —— PyAV 没有导出音频格式与声道布局的枚举清单,只能按名字构造对象。 3. 时间基为什么用分数表示? —— 避免浮点误差。1/25 写成 0.04 会有舍入误差,几十万帧之后会累积成可见的偏移。

相关笔记