🎬 第一章 编译FFmpeg源码并搭建开发环境
📄 一句话概括

VS 里只有三处要动:附加包含目录、附加库目录、附加依赖项。 报 LNK2019 时先别改代码,先查这三处填的是不是同一套工具链的产物。

📝 本节和前面几节的关系

1.4 是 Qt 那条路,这一篇是 VS。 两篇的坑本质相同:路径、顺序、工具链。

一、三处配置,一一对应

位置 填什么 对应 Qt 的哪个


附加包含目录 C:\ffmpeg\include INCLUDEPATH 附加库目录 C:\ffmpeg\lib LIBS 里的 -L 附加依赖项 avcodec.lib 等 LIBS 里的 -l

三处都在「项目属性 → 链接器 / C/C++」下面。 VS 的界面层级比较深,记住一条: 头文件在 C/C++ 页,库在链接器页。 别用绝对路径配到系统环境变量里。 换台机器就全废,用「用户宏」或 CMake 变量管这些路径。

二、用 CMake 更省事

现在的 VS 可以直接打开 CMake 工程,不用建 .vcxproj。 行 作用


set(FFMPEG_ROOT "C:/ffmpeg") 定义根目录 include_directories(${FFMPEG_ROOT}/include) 头文件 link_directories(${FFMPEG_ROOT}/lib) 库目录 target_link_libraries(app avcodec avformat) 库名

CMake 里只写库名,不带 -l,也不带后缀。 这一点跟 .pro 不一样:Qt 那边自己拼 -l,CMake 由它去拼。 写 avcodec.lib 反而会错,CMake 会去找叫 avcodec.lib.lib 的文件。

三、LNK2019 的三种来源

同一个报错,三个不同的病根,得分开看。 情况 病根 怎么改


符号全缺 附加依赖项没填 补库名 符号带 __imp_ 前缀缺 拿 GNU 库喂 MSVC 换 .lib 只有一两个符号缺 库版本与头文件不匹配 重编或换头文件

第二种最容易误判。 报错长这样:无法解析的外部符号 __imp_avcodec_send_packet。 符号明明存在,因为 MSVC 找的是带 __imp_ 的导入符号,而 .dll.a 里存的是另一套名字。 第三种最隐蔽:头文件是新的、库是旧的,只缺几个新接口。 这种错会让人以为「这个函数不能用」,其实是版本对不上。

四、本机的情况

本机没有 Visual Studio,msbuild 也不在 PATH。 所以这一节的三处配置是清单,不是操作记录。 但这三条判断在任何一台 VS 机器上都成立,而且不依赖版本——VS 2015 到 2022, 三处配置的位置与含义都没变。 一条通用建议:先把 Demo 编成一个只调 avcodec_version() 的空程序。 它能跑通, 说明三处都对了;跑不通,就是这三处之一,不用怀疑代码。

五、动手 Demo:VS 开发环境——三处配置,混链是死路

本机没有 VS,所以这一段做的是:摆三处配置、生成 CMake 片段、按文件名判产物归属。 最后那张表是混链判定的全部依据。

files = ["avcodec.lib", "libavcodec.dll.a", "avcodec-60.dll"]
for f in files:
    who = "MinGW" if f.endswith(".dll.a") else "MSVC"
    print(f, who)

实跑输出:

--------------------------------------------------------------------
VS 开发环境——三处配置,混链是死路
--------------------------------------------------------------------

**① VS 里只有三处要动**

  位置             填什么
  ----------------------------------------------------------
  附加包含目录     C:\ffmpeg\include
  附加库目录       C:\ffmpeg\lib
  附加依赖项       avcodec.lib; avformat.lib; avutil.lib

**② 生成的 CMakeLists 写法(VS 也能直接开 CMake 工程)**

`set(FFMPEG_ROOT "C:/ffmpeg")`
`include_directories(${FFMPEG_ROOT}/include)`
`link_directories(${FFMPEG_ROOT}/lib)`
`target_link_libraries(app avcodec avformat avutil swscale swresample)`

**③ 混链的判定:看文件名就知道是谁的产物**

  文件                  谁的产物           能混吗
  ---------------------------------------------------------
  avcodec.lib           MSVC               不能混 MinGW
  libavcodec.dll.a      MinGW              不能混 MSVC
  avcodec-60.dll        运行时(同名)     按工具链选
  libavcodec-60.dll     运行时(同名)     按工具链选
  avutil.lib            MSVC               不能混 MinGW
  libavutil.dll.a       MinGW              不能混 MSVC

**④ 混链的报错长什么样**

`LNK2019: 无法解析的外部符号 __imp_avcodec_send_packet`。这个错最容易骗人:符号明明在库里。
原因是 MSVC 找的是 `__imp_` 前缀的导入符号,而 `.dll.a` 里存的是 GNU 格式的,名字对不上。

**⑤ 一条能省半天时间的规矩**

**Qt、VS、Python 绑定,三样东西必须用同一条工具链编出来的 FFmpeg。**
混用不会有「部分能用」这种中间状态,只有「一个符号都链不上」。

**⑥ 本机实测**:VS 目录(`C:\Program Files\Microsoft Visual Studio`)不在,`msbuild` 也不在 PATH。
所以这一节的三处配置是清单,上面那条 LNK2019 是这类问题最常见的报错文本。

.lib 归 MSVC,.dll.a 归 MinGW,.dll 两家同名但内容不同。 看见目录里两种导入库混着,就说明这里有混链风险。

30 秒实验

  1. where msbuild 与 where cl,看 VS 是不是只在图形界面里存在。
  2. 在 VS 里建一个空的 C++ 控制台工程,把 avcodec_version() 编进去,看链接报什么。
  3. dumpbin /exports avcodec.dll | findstr avcodec_send 看一个 DLL 导出了什么符号。

常见误区

  1. 只填附加库目录不填附加依赖项。 找不到库目录是 LNK1104,缺依赖项是 LNK2019。
  2. 把 .dll 当导入库填。 链接期要的是 .lib,.dll 是运行期的。
  3. 路径写死成绝对路径。 换机器全废,用宏或 CMake 变量。
自测三问(点开对答案) 1. VS 里三处配置分别对应 Qt 的什么? —— 附加包含目录对应 INCLUDEPATH,附加库目录对应 -L,附加依赖项对应 -l。 2. LNK2019 报 `__imp_` 前缀的符号缺失,最可能是什么原因? —— 拿 MinGW 的 .dll.a 给 MSVC 链了。导入符号命名不同,必须换 .lib。 3. 为什么建议先编一个只调 `avcodec_version()` 的空程序? —— 能跑通说明三处配置都对,跑不通就锁定在配置层,不用怀疑自己的代码。

相关笔记