📹 第三章 FFmpeg二次开发采集并预览本地摄像头
📄 一句话概括

Linux 上配环境反而最简单:没有「找 DLL」这回事, 包管理器装完、pkg-config 一给参数就能编。

📝 本节和前面几节的关系

前两节讲了 Windows 和 Qt,这一节补上 Linux。 三平台的差别其实只有三处:依赖从哪来、编时怎么找、跑时怎么找。 看清这三处,跨平台就不再神秘。 沙箱是 Windows,所以这一节的命令没法真跑,能给的是清单加平台判断代码。

一、装什么

SDL2 一个包,FFmpeg 五个包。

包 给什么
libsdl2-dev SDL2 头文件与库
libavformat-dev 容器与协议
libavcodec-dev 编解码器
libavutil-dev 工具函数与时间基
libswscale-dev 像素格式转换
libswresample-dev 音频重采样

注意都是 -dev 包:不带 -dev 的那个只能跑不能编,报错是「找不到 avformat.h」。 这个错很常见,因为运行时包通常已经预装了——于是你以为是「没装 FFmpeg」,其实是「没装头文件」。

二、编译不用手写一堆 -l

pkg-config 就是「库的说明书查询工具」。

命令 给什么 用在哪
--cflags -I… 头文件路径 编译
--libs -l… 链接参数 链接
--modversion 版本号 验证装没装对

一句 pkg-config --modversion sdl2 就能确认装没装对,比翻 /usr/lib 快得多。 而且它给的是「这台机器上正确的路径」,不用管是 x86 还是 arm。

三、三个平台的差别就三行

同一份源码,三个平台只差这三件事:

Windows Linux
依赖从哪来 手动下 zip 放固定目录 apt 装到系统路径
编时怎么找 项目属性里填路径 pkg-config 自动给
跑时怎么找 DLL 放 exe 旁边 so 在 /usr/lib,不用管

第二、三行是新手最容易翻车的地方:Windows 上「编过了」和「跑得起来」是两件事, Linux 上一般是一件。 这也解释了为什么很多开源项目在 Linux 上装完就能跑,到了 Windows 要配半天。

四、平台判断该写在哪

要写平台相关代码时,别用「编译器宏」,用 SDL 自己的函数。

写法 好处 坏处
SDL_GetPlatform() SDL 已经判断过了 要在 SDL 初始化后调
#ifdef _WIN32 编的时候就定了 一堆宏,容易漏
sys.platform(Python) 简单 只到操作系统级

第一行最省事:D31 实测返回 Windows,Linux 上返回 Linux,macOS 上返回 macOS。 注意它是运行时的——同一个二进制不会跨平台,但同一个源码要能编出三个二进制, 这时候第一行和第三行都行。

五、动手 Demo:查平台、列依赖、对比三平台

先让 SDL 自己报平台名,再把 Linux 上要装的东西列清,最后把三平台的差别摆成一张表。 沙箱是 Windows,所以这一节只验「平台判断」,装包的部分只能照做。

import sdl2
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
print(sdl2.SDL_GetPlatform())        # b"Windows"

# Linux 上要装(照抄即可)
# sudo apt install libsdl2-dev
# sudo apt install libavformat-dev libavcodec-dev libavutil-dev
# sudo apt install libswscale-dev libswresample-dev

# 编译:交给 pkg-config
# gcc main.c -o main $(pkg-config --cflags --libs sdl2 \
#      libavformat libavcodec)

实跑输出:

--------------------------------------------------------------------
Linux 上配 SDL2,一条 apt 加一个 pkg-config
--------------------------------------------------------------------
**Linux 反而最简单:没有「找 DLL」这回事,包管理器装完就能编。**

  本机是 Windows,`SDL_GetPlatform()` 会告诉我们:

    当前平台:**Windows**

  **这个函数在跨平台代码里很有用**:同一个二进制不可能跨平台,但同一份源码可以,靠它分支。

**Linux 上要装的东西:**
    sudo apt install libsdl2-dev
    sudo apt install libavformat-dev libavcodec-dev libavutil-dev
    sudo apt install libswscale-dev libswresample-dev

**编译命令不用手写一堆 `-l`,交给 pkg-config:**

    gcc main.c -o main $(pkg-config --cflags --libs sdl2 libavformat libavcodec)

  **`--cflags` 给头文件路径,`--libs` 给链接参数**,一起给就是完整的编译行。
  验证装没装对,只要一句 `pkg-config --modversion sdl2`。

**三个平台真正的差别就这三处:**

                 Windows                    Linux
  --------------------------------------------------------------------
  依赖从哪来     手动下 zip,放固定目录     apt 装到系统路径
  编时怎么找     项目属性里填路径           pkg-config 自动给
  跑时怎么找     DLL 放 exe 旁边            so 在 /usr/lib,不用管

  **第二行和第三行是新手最容易翻车的**:Windows 上「编过了」和「跑得起来」是两件事,
  Linux 上一般是一件。

SDL_GetPlatform() 返回的是 Windows,不是 win32 也不是 Windows 10。 它只有四个值:Windows/Linux/macOS/iOS/Android。 所以它只能用来选「用哪套 API」,不能用来判断版本。

pkg-config 那一条是 Linux 侧的万能钥匙:它的输出直接拼进 gcc 命令就行,不用背任何路径。 而且它会把依赖的库也带上——比如 sdl2 会自动带 -lpthread -ldl -lm,漏了这几个符号就找不到。

三平台那张表最后一行最值钱:Windows 上「跑不起来」的九成原因是 DLL 没放对, Linux 上基本不会遇到这个问题。知道这一点,排查方向就定了。

30 秒实验

  1. 在 Linux 上跑 pkg-config --libs sdl2,看它到底带出了几个库——比你想的多。
  2. 试着用 pkg-config --exists sdl2 && echo yes 判断装没装,这个写法常出现在 configure 脚本里。
  3. 把 SDL_GetPlatform() 的返回值和 sys.platform 对比,想想各自的适用场景。

常见误区

  1. 以为装了 libavformat 就能编。 那是运行时库,编代码要装 libavformat-dev, 否则找不到头文件。
  2. 以为 pkg-config 只是省事。 它还负责带上间接依赖(pthread、dl、m), 漏了就是一堆「未解析的符号」。
  3. 以为 Windows 和 Linux 的配置思路一样。 Windows 要管「跑时找 DLL」,Linux 不用。 所以 Windows 上「编过了」不等于「能跑」。
自测三问(点开对答案) 1. `libavformat-dev` 和 `libavformat` 有什么区别? —— `-dev` 带头文件和链接用的符号链接,用来编译;不带的只有运行时 so,只能跑不能编。 2. `pkg-config --libs sdl2` 会带出哪些额外库? —— SDL 自己的依赖:pthread、dl、m 等。漏了它们链接会报未解析符号。 3. 为什么 Windows 上「编过了」不等于「能跑」? —— 因为 DLL 是在加载期找的,找不到时程序直接退出,编译链接阶段完全看不出来。 Linux 的 so 在系统路径里,不会遇到。

环境三节讲完,回到代码:用 SDL2 直接播一段裸 YUV,把「SDL 只管像素」这句话验证一遍。

相关笔记