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 秒实验
- 把
probesize传给stream_options,看有没有区别。 import av.dictionary as D; d = D.Dictionary(); d["a"] = "1"看它的 keys。hasattr(av, "AVDictionary")确认它在不在顶层。
常见误区
- 以为传了选项就生效。 拼错、传错层级都不报错。
- 在 av 顶层找 AVDictionary。 得 import av.dictionary。
- 什么键都往 options 里塞。 容器选项与流选项分三层。
自测三问(点开对答案)
1. 错键为什么不会报错? —— 库在一张大表里查名字,查不到就当没有。它不知道你想干什么。 2. container_options 与 stream_options 差在哪? —— 前者只给容器,后者只给各路流。传错层级不会报错,只是不生效。 3. 生效有没有办法验证? —— 把日志开到 DEBUG,生效的选项通常会在日志里留一行。- ☐ (本节完,下一节 5.5 AVOption 应用案例及剖析)