🎬 第三章 夯实FFmpeg基础:重要数据结构及API
📄 一句话概括

教材写的是 C,本机跑的是 Python,先要有一张名字对照表。 名字变了、合并了,但五步流程一步没少。

📝 本节和前面几节的关系

第二章把八个库分清了,这一节开始进 API。 下一篇 3.1.2 把这些 API 串成一条能跑通的流程。

一、API 是按层分的,不是按功能分的

翻开 FFmpeg 的头文件,会发现函数名里都带层名。 前缀 属于 举例


avformat_ libavformat avformat_open_input avcodec_ libavcodec avcodec_send_packet avfilter_ libavfilter avfilter_graph_create_filter sws_ libswscale sws_scale swr_ libswresample swr_convert av_ libavutil av_malloc、av_log

看前缀就知道该加哪个库。 这一点在链接阶段很有用——报未定义符号 avformat_open_input, 缺的就是 libavformat,不用猜。 只有 libavutil 用的是最短的 av_ 前缀,因为它是最底层,名字里不必再重复自己管什么。

二、C 的名字在 Python 里长什么样

PyAV 不是 FFmpeg 的 Python 版重写,是一层薄封装。 底下还是那七个库, 只是把 C 的调用风格改成了对象。 C 侧的名字 Python 侧 变化


avformat_open_input av.open 合并两步 av_read_frame demux 变成迭代器 avcodec_send_packet packet.decode 收在包上 avcodec_receive_frame decode 的返回 合成一步 sws_scale to_ndarray 并进帧上

合并带来一个副作用:出错分不清是哪一步。 C 侧每步都返回错误码,坏了立刻能定位; Python 侧抛异常,栈里只有 av.open 或 decode 那一层,中间五步糊成一团。 排错思路要改:不问「哪一步错了」,问「哪一层的输入不对」。

三、av_register_all 已经不存在了

教材上手第一句就是 av_register_all()。 这一句在 4.0 废弃、5.0 之后彻底删掉, 本机的 8.1.2 里找不到它。 注册早就自动化了:只要链接进来,所有编解码器与格式就在表里,一个函数都不用调。 照书抄会得到「未定义标识符」,不是环境坏了。 教材这一版是 5.0,书里很多写法停在 5.0 的边界上。 看见「找不到符号」,先想「是不是这个函数已经删了」。

四、本机的三个数:557 / 414 / 468

这三个数是构建出来的,不是常量。 同一份源码,configure 时关掉几个外部库,数就变了。 条目 数量 从哪数


编解码器 557 av.codecs_available 封装格式 414 av.formats_available 滤镜 468 av.filter.filters_available 像素格式 267 av.video.format.names

别人的数是别人的。 网上教程里说「FFmpeg 有 300 多个编解码器」,那是他那台机器的数。 拿这个数去核对自己的环境,才有意义。 对不上说明装的是不同构建,不是代码写错了。这一条在排错时省很多时间。

五、动手 Demo:给 C 的名字配一张 Python 的对照表

先真跑一遍,看本机到底有哪些东西。

import av
import av.filter

print("版本", av.ffmpeg_version_info)
print("编解码器", len(av.codecs_available))
print("封装格式", len(av.formats_available))
print("滤镜", len(av.filter.filters_available))

实跑输出:

--------------------------------------------------------------------
C 的名字在 Python 里长什么样
--------------------------------------------------------------------

**① 教材写的是 C,本机跑的是 Python,得先有一张对照表**

  C 侧的名字                Python 侧的名字          差在哪
  -------------------------------------------------------------------
  avformat_open_input       av.open                  合并两步
  av_read_frame             container.demux          变成迭代器
  avcodec_send_packet       packet.decode            收在包自身
  avcodec_receive_frame     packet.decode 的返回     与上一步合并
  sws_scale                 frame.to_ndarray         并进帧对象

**合并是好事,也是坑。** 合并之后调用少了,
但「哪一步出错」这件事被藏起来了——报错只告诉你某个方法抛了异常。

**② 顶层导出了哪些类**

本机 av 顶层挂着 **103** 个可以直接用的类型。挑十六个常用的列在这里:

Codec、CodecContext、Packet、AudioFifo、AudioFormat、AudioFrame、AudioLayout、AudioResampler、
ContainerFormat、VideoFormat、VideoFrame、VideoStream、DeviceInfo、BitStreamFilterContext、
AVRational、FFmpegError。

**③ 三个数再报一遍,后面各章都会用到**

  条目         数量     从哪数
  -----------------------------------------------------
  编解码器     557      av.codecs_available
  封装格式     414      av.formats_available
  滤镜         468      av.filter.filters_available

**④ 教材的 av_register_all 已经没了**

教材 1.2 节让初学者第一句就写 av_register_all()。
这个函数在 FFmpeg 4.0 就废弃、5.0 之后彻底删掉,本机的 8.1.2 里找不到它。

**注册这件事早就自动化了**:链接进来就注册好了,什么也不用写。
照书抄会得到一个「函数未定义」,不是环境坏了,是那一句过时了。

三个数与 2.1 那一篇报的一致,因为是同一台机器同一个构建。 版本 8.1.2 比教材的 5.0 高三个大版本,这是全课反复要提的前提。

30 秒实验

  1. python -c "import av; print(av.ffmpeg_version_info)" 看版本。
  2. 数一数 av.codecs_available 里带 libx264 的条目有几个。
  3. hasattr(av, "protocols_available") 看协议层有没有枚举入口。

常见误区

  1. 照书抄 av_register_all。 这个函数在 5.0 之后已删除,编译直接失败。
  2. 以为 PyAV 是重新实现的 FFmpeg。 它只是封装,底下还是那七个库。
  3. 拿网上的数量核对本机。 数量取决于构建配置,不等于环境坏了。
自测三问(点开对答案) 1. 看见 `undefined reference to avformat_open_input`,缺哪个库? —— libavformat。函数前缀就写着它属于哪一层。 2. 为什么 Python 侧五个步骤只剩三四行? —— PyAV 把 open 与 find_stream 合并、把 send 与 receive 合并、把 sws_scale 并进 to_ndarray,调用少了但层没少。 3. `av_register_all` 为什么可以删掉? —— 注册在链接时就完成了。删除它不影响任何功能,只是让老代码编不过。

相关笔记