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

教材给一条 gcc 命令,它藏着三个前提:编译器、pkg-config、头文件。 本机三个全没有,所以这一节能落地的只有「流程」。

📝 本节和前面几节的关系

3.6 排了函数表,这一节是把它编成一个能跑的程序。 下一章 4.1 转去讲框架流程,也就是责任链设计模式。

一、教材的命令串,拆成三段

教材原文大概是这一句: gcc -o demux demux.c $(pkg-config --libs libavformat libavcodec libavutil) 拆开看是三段活儿。 段 干什么 需要什么


gcc 把 .c 编成可执行文件 编译器 pkg-config 查出 -I 与 -L 与 -l pkg-config 与 .pc 文件 libav* 链接时找到符号 开发包,含 .so 与 .h

三段任意一段缺了都编不出。 报错长得完全不一样:缺 gcc 是 command not found, 缺 pkg-config 是空字符串,缺开发包是一堆 undefined reference。 这三种错误要能一眼分清,否则会往错的方向查半天。

二、三个前提逐个查,全部落空

本机是个纯运行环境,不是开发环境。 要的东西 本机 说明


gcc/g++ 没有 没有编译器 cl/msbuild 没有 也没有 MSVC make/cmake 没有 没有构建工具 pkg-config 没有 查不出库参数 ffmpeg/ffprobe 没有 命令行工具也没有 git/bash 有 来自 PortableGit

有 git 不等于能编译。 这两个是沙箱自带的版本控制工具,跟工具链没关系。 这说明一件事:PyAV 的轮子是预编译好的,装它不需要编译器。 所以这个环境跑得动 PyAV,编不动一行 C。

三、头文件也没有,这一条最要紧

av.get_include() 返回一个路径,但那个目录不存在。 PyAV 把 libav 静态编进了 .pyd 文件里,运行时该有的全有,编译时该有的一个没有。 所以「拿 PyAV 的环境去编 C 程序」这条路是堵死的*,不是缺一个包的问题——就算装上 gcc, 也没有 avcodec.h。 需要的 PyAV 提供吗


运行时 .pyd 提供 .h 头文件 不提供 .lib/.dll 导入库 不提供 .pc 文件 不提供

要编 C 就得另装一套开发版的 FFmpeg,与 PyAV 完全独立。 两套并存没问题,注意别让它们的库混到一起去。

四、Windows 上怎么落地这一节

四行里三行做不到,只剩最后一行。 教材的做法 本机的等价事


apt install 开发包 装不了 gcc 编 demux.c 改写成 Python pkg-config 找库 用不上 ./demux 跑起来 Python 脚本直接跑

这不是偷懒。 这一节的产物本来就只有一句话:把 C 的五步流程走出来。 流程走通了,用哪种语言写是次要的。 但有一件事必须按 C 的规矩记住:出错要一层层往回退,第 4 步失败要释放第 3 步的资源, 第 3 步失败要关第 1 步的文件。这叫 goto fail 链。 Python 的 with 语句做的是同一件事。 写法变了,责任没变:谁开的谁关,先开的后关。 不合格的写法在 C 侧泄漏内存,在 Python 侧静默回收——后果不同,规矩一样。

五、动手 Demo:Ubuntu 编译清单,在本机逐条对一遍

把教材那条命令的前提逐个查,看差在哪。

import os
import shutil

import av

for t in ("gcc", "make", "pkg-config", "ffmpeg"):
    print(t, shutil.which(t))

inc = av.get_include()
print(inc, os.path.isdir(inc))

实跑输出:

--------------------------------------------------------------------
Ubuntu 编译清单,在本机逐条对一遍
--------------------------------------------------------------------

**① 教材 3.7 的做法:在 Ubuntu 上编译一个解封装程序**

命令大概是这一串(教材原文):

    gcc -o demux demux.c $(pkg-config --libs libavformat libavcodec libavutil)

这一句里藏着三个前提:有 gcc、有 pkg-config、有开发包(头文件)。逐个查本机有没有。

**② 逐个查,全部落空**

  要的东西       本机     来自哪里
  ---------------------------------------
  gcc            没有     —
  g++            没有     —
  cl             没有     —
  make           没有     —
  cmake          没有     —
  pkg-config     没有     —
  ffmpeg         没有     —
  ffprobe        没有     —
  git            有       PortableGit
  bash           有       PortableGit

10 个里只有 2 个在:git 与 bash,都来自 PortableGit。

git → D:\WorkBuddy\resources\vendor\PortableGit\mingw64\bin\git.EXE
bash → D:\WorkBuddy\resources\vendor\PortableGit\usr\bin\bash.EXE

**这两个是沙箱自带的版本控制工具,不是编译工具链。** 有 git 不等于能编译。

**③ 头文件也没有——这一条最要紧**

av.get_include() 返回:

    C:\Users\admin\.workbuddy\binaries\python\envs\default\Lib\site-packages\av\..\include

这个目录存在吗:**不存在**。

**PyAV 只发轮子,不发头文件。** 它把 libav* 静态编进了 .pyd,运行时该有的全有,
编译时该有的一个没有。

**所以「拿 PyAV 的环境去编 C 程序」这条路是堵死的**,不是缺一个包的问题。

**④ 那这一节在 Windows 上怎么落地**

  教材的做法             本机能做的等价事
  ----------------------------------------------------
  apt install 开发包     没有 apt,装不了
  gcc 编译 demux.c       没有编译器,改写成 Python
  pkg-config 找库        没用,库静态在 pyd 里
  ./demux 跑起来         Python 脚本直接跑

**四行里三行做不到,只剩最后一行。** 这不是偷懒,是这一节的产物本来就只有一句话:
**把 C 的五步流程走出来**。流程走出来,用哪种语言写是次要的。

**⑤ 但有一件事必须按 C 的规矩记住**

C 侧写这五步,出错要一层层往回退:第 4 步失败要释放第 3 步的资源,第 3 步失败要关第 1 步的文件。
这叫 goto fail 链,教材的例子里有。Python 侧 with 语句替你做了同样的事。

**写法变了,责任没变**:谁开的谁关,先开的后关。
这条规矩在两边都成立,只是 Python 侧不合格时静默回收,C 侧不合格时内存泄漏。

四个 None 加一个 False,就是这一节的全部结论。 第一条 gcc 是 None,走 gcc --version 会抛 WinError 2。

30 秒实验

  1. shutil.which("cl") 看 MSVC 在不在。
  2. av.get_include() 打出来,用资源管理器去看看那个目录在不在。
  3. 在别的机器(有 MSYS2 的)上跑同一段,对比四个返回值。

常见误区

  1. 以为装 PyAV 就有编译环境。 轮子只有运行时,没有头文件。
  2. 把「command not found」当代码错。 那是工具链没装。
  3. 跳过收尾顺序。 C 侧必须倒着释放,顺序错了会泄漏或崩。
自测三问(点开对答案) 1. `gcc -o demux demux.c $(pkg-config --libs …)` 里 pkg-config 干什么? —— 查出 -I 头文件路径与 -L -l 库路径库名,塞进命令行。 2. 为什么 av.get_include() 返回的目录不存在? —— PyAV 只发预编译轮子,把库静态编进 .pyd,不带头文件。 3. 这一节在 Windows 上唯一能落地的是什么? —— 流程本身。五步走出来,用 Python 写等价代码。

相关笔记