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

C 侧建字典、塞键值、释放;Python 侧只要一个 dict。 省掉了内存错误,也丢掉了校验——错键被静默忽略。

📝 本节和前面几节的关系

5.3 讲字节怎么切,这一节讲参数怎么传。 下一篇 5.5 讲这些键到底是什么。

一、两侧的用法对照

这是 C 与 Python 差得最明显的一处。 步骤 C 侧 Python 侧


建 av_dict_alloc 写个 {} 塞 av_dict_set,看返回码 d[k] = v 用 传指针 options=d 释放 av_dict_free 不用管

省掉的是一整类错误:忘了释放、释放两次、塞的时候没判重复键。这些在 C 侧都是常见 bug。 但 av_dict_set 的返回码是有用的:它能告诉你「这个键已经有值了,要不要覆盖」。 Python 侧直接覆盖,方便但少了这个信息。

二、没有校验,这是选项法的通病

传一个拼错的键,不报错,静默忽略。 本机实测:传两个错键(一个是中文瞎写的,一个是把 protocol 拼成了 protocl),照样打开成功。 传了什么 结果


正确的键 生效 拼错的键 静默忽略 类型不对的值 可能忽略,也可能中途失败

为什么会这样:选项是一张很大的表,库只在表里查名字,查不到就当没有。它不知道你想干什么。 排查办法是把日志开到 DEBUG:生效的选项通常会在日志里留一行。 没出现就是没生效——这是 5.2 那个工具的正当用途。

三、三个层级,别传错地方

av.open 接三个不同的参,各管一段。 参数 作用范围 典型键


options 容器与流都传 timeout container_options 只给容器 probesize stream_options 只给各路流 编解码相关

传错层级也不报错,只是不生效。 把 probesize 塞进 stream_options,它会被无声忽略。 这条坑很隐蔽:明明参数写对了、文档也这么写,就是不生效。遇到这种情况先怀疑层级。

四、PyAV 还留了一个 Dictionary 类

av.dictionary.Dictionary 是 AVDictionary 的薄封装。 能力 普通 dict Dictionary


下标读写 有 有 键名列表 有 keys 批量更新 update update 能传给 av.open 能 需要转换

日常用普通 dict 就够。 需要按键名有序遍历、 或者要与 C 侧的 AVDictionary 语义严格对齐时才用它。 注意它不在 av 顶层:av.AVDictionary 不存在,得 import av.dictionary。 名字里带 AV 的东西,PyAV 大多没往外导。

五、动手 Demo:字典——传选项的唯一通道

传对的键、传错的键,看有没有区别。

import av

good = {"rtsp_transport": "tcp", "timeout": "5000000"}
c = av.open("_media32/tiny.mp4", options=good)
print(c.format.name)
c.close()

bad = {"protocl_whitelist": "typo"}
c = av.open("_media32/tiny.mp4", options=bad)
print(c.format.name)
c.close()

实跑输出:

--------------------------------------------------------------------
字典——传选项的唯一通道
--------------------------------------------------------------------

**① C 侧要建字典、塞键值、用完释放,Python 侧只要一个 dict**

  步骤     C 侧                        Python 侧
  --------------------------------------------------
  建       av_dict_alloc               写个 {}
  塞       av_dict_set(看返回码)     d[k] = v
  用       传指针进去                  options=d
  释放     av_dict_free                不用管

**省掉的是一整类错误**:忘了释放、释放两次、塞的时候没判重复。
这些在 C 侧都是常见 bug,Python 侧结构性地不存在。

**② 但少了一样东西:没有校验**

传两个正确的键:打开成功,格式 mov,mp4,m4a,3gp,3g2,mj2。

传两个**拼错的键**:同样打开成功,格式 mov,mp4,m4a,3gp,3g2,mj2,一声不响。

**这就是选项法的通病:错的键被静默丢弃。** C 侧其实也一样,但 av_dict_set 至少返回一个码,
有经验的人会去判。

**排查办法是把日志开到 DEBUG**,有效的选项会在日志里出现一行。
没出现就是没生效——这是 5.2 那个工具的正当用途。

**③ 三个层级,别传错地方**

  参数                  作用范围                 典型键
  -------------------------------------------------------------
  options               全部(容器与流都传)     timeout
  container_options     只给容器                 probesize
  stream_options        只给各路流               codec 相关

**传错层级不会报错,只是不生效。** 比如把 probesize 塞进 stream_options,它会被无声忽略。

**④ PyAV 还留了一个 Dictionary 类**

av.dictionary.Dictionary 是 AVDictionary 的薄封装,支持下标、keys、update、pop、copy。
**日常用普通 dict 就够**,需要「按键名有序遍历」时才用它。

**注意它不在 av 顶层**:av.AVDictionary 不存在,得 import av.dictionary。
名字里带 AV 的东西,PyAV 大多没往外导。

两次都成功,第二次的错键被静默丢弃。 这就是选项法没有校验的证据。

30 秒实验

  1. 把 probesize 传给 stream_options,看有没有区别。
  2. import av.dictionary as D; d = D.Dictionary(); d["a"] = "1" 看它的 keys。
  3. hasattr(av, "AVDictionary") 确认它在不在顶层。

常见误区

  1. 以为传了选项就生效。 拼错、传错层级都不报错。
  2. 在 av 顶层找 AVDictionary。 得 import av.dictionary。
  3. 什么键都往 options 里塞。 容器选项与流选项分三层。
自测三问(点开对答案) 1. 错键为什么不会报错? —— 库在一张大表里查名字,查不到就当没有。它不知道你想干什么。 2. container_options 与 stream_options 差在哪? —— 前者只给容器,后者只给各路流。传错层级不会报错,只是不生效。 3. 生效有没有办法验证? —— 把日志开到 DEBUG,生效的选项通常会在日志里留一行。

相关笔记