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 秒实验
len(av.error.__dict__)之外的写法:dir(av.error)数异常类有多少个。- 试着
av.AudioFormat("fltp"),再试一个瞎写的名字看报什么错。 av.video.format.names里找一个你认识的格式,确认它在。
常见误区
- 拿网上的数量核对本机。 数取决于构建配置,不等于环境坏了。
- 以为音频侧也能枚举。 PyAV 没给入口,只能按名字构造。
- 时间用浮点数算。 精度会累积,全程该用整数加有理数。
自测三问(点开对答案)
1. libavutil 在链上还是在链下? —— 链下。它不产生任何产物,是每个环都在用的地基。 2. 为什么音频格式数不出来? —— PyAV 没有导出音频格式与声道布局的枚举清单,只能按名字构造对象。 3. 时间基为什么用分数表示? —— 避免浮点误差。1/25 写成 0.04 会有舍入误差,几十万帧之后会累积成可见的偏移。- ☐ (本节完,下一节 5.2 AVLog 应用案例及剖析)