C/C++ 项目有两种编译方式,MinGW 跟 MSVC,如下:

1,《​​MinGW编译静态库​​》

2,《​​MSVC编译静态库​​》

但是 MinGW 编译的静态库,是不能给 MSVC 的链接器使用的,虽然两者编译器生成的 .o 跟 .obj 目标文件是 ABI 兼容的,但是他们的链接器不通用。

而 静态库 实际上就是把 目标文件 打包在一起,所以 MinGW 编译的静态库,只能给 MinGW 编译方式的项目使用。MSVC 同理。


下面来讲一下 qt creator 如何引入 用 MinGW 方式编译出来的 FFmpeg 动态库。

MinGW 编译 FFmpeg 请参考 《​​用msys2与mingw编译FFmpeg​​》,编译完成之后,目录如下:

Qt使用FFmpeg的动态库_Qt

上图中,这些 lib 并不是静态库,而是动态库的导入库。而 dll 文件就是动态库,使用 FFmpeg 的库的时候,还需要按需引入一些头文件,哪些头文件后面会讲到。

实际上 ffmpeg-n4.4.1-mingw 目录,是有两种导入库的,一种是 xxx.lib ,一种是 xxx.dll.a ,如下:

Qt使用FFmpeg的动态库_Qt_02

可以这么理解这两种导入库,lib 是给 msvc 链接器用的,.a 的导入库是给 MinGW 链接器用的。MinGW 跟 MSVC 对于格式的处理有点不一样,所以需要分开。

这里提醒一下,虽然 dll 是用 MinGW 的 gcc 编译出来的,但是 dll 也可以给 MSVC 用的。他们是兼容的。

不过,我实际测试后发现,qt creator 的 MinGW 可以用 lib 导入库,也可以用 .a 导入库,都可以。但是 qt creator 的 MSVC 只能用 lib 导入库 ,用 .a 导入库来定位就会报错。


打开 Qt Creator,点击菜单栏的 New File or Project,选择 Non-Qt Project ,选择 Plain C Application。

Qt使用FFmpeg的动态库_Qt_03

项目名称填 ffmpeg-shared-libs-use,编译工具选 qmake,如下:

Qt使用FFmpeg的动态库_Qt_04

勾选编译环境 Kit ,Qt 5.15.2 MinGw 64-bit

Qt使用FFmpeg的动态库_Qt_05


然后把 ​​C:\msys64\home\loken\ffmpeg\build64​​ 这个目录拷贝到 ffmpeg-qt-version 项目目录下,如下:

Qt使用FFmpeg的动态库_FFmpeg_06

Qt使用FFmpeg的动态库_FFmpeg_07

然后 修改 ffmpeg-shared-libs-use.pro 的内容,修改为以下内容:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
#定义 DLL 的导入库的类型
#DLL_IMPORT_TYPE = msvc
DLL_IMPORT_TYPE = mingw

#HEADERS += xxx.h
SOURCES += main.c

contains(QT_ARCH, i386) {
message("32-bit")
}

contains(QT_ARCH, x86_64) {
message("64-bit")
message($$DLL_IMPORT_TYPE)

contains(DLL_IMPORT_TYPE, mingw) {
INCLUDEPATH += $$PWD/build64/ffmpeg-n4.4.1-mingw/include
LIBS += $$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libavformat.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libavcodec.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libavdevice.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libavfilter.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libavutil.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libpostproc.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libswresample.dll.a \
$$PWD/build64/ffmpeg-n4.4.1-mingw/lib/libswscale.dll.a
}

contains(DLL_IMPORT_TYPE, msvc) {
INCLUDEPATH += $$PWD/build64/ffmpeg-n4.4.1-mingw/include
LIBS += $$PWD/build64/ffmpeg-n4.4.1-mingw/bin/avcodec.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/avdevice.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/avfilter.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/avformat.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/avutil.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/postproc.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/swresample.lib \
$$PWD/build64/ffmpeg-n4.4.1-mingw/bin/swscale.lib
}
}

提示:gitbook 生成 html 的时候 改乱了 上面的代码,请按照下图进行修改:

Qt使用FFmpeg的动态库_Qt_08

然后把 main.c 的内容也修改一下,创建项目的时候只是输出了一个 hello world,我们现在在 main.c 里面调一下 FFmpeg 的一些 API 函数,如下:

#include <stdio.h>
#include "libavcodec/avcodec.h"
#include "libavdevice/avdevice.h"
#include "libavfilter/avfilter.h"
#include "libavformat/avformat.h"
int main()
{
printf("avcodec version is %u \n",avcodec_version());
printf("avdevice version is %u \n",avdevice_version());
printf("avfilter version is %u \n",avfilter_version());
printf("avfilter version is %u \n",avformat_version());
return 0;
}

上面的代码打印了 4 个库的版本号,我为什么知道有这 4个函数可以用,可以用以下命令查看 dll 提供了哪些函数可以调用。

dumpbin /EXPORTS ./avcodec-58.dll > avcodec-58.txt

Qt使用FFmpeg的动态库_FFmpeg_09

然后去 FFmpeg-n4.4.1 的源码里面搜这个函数的定义,有哪些参数,返回值就行了。一般在 头文件里面,所以我上面引入了 4个头文件。

Qt使用FFmpeg的动态库_Qt_10

也可以查官网的文档手册来看 API 函数的调用。


上面这样改好之后,点 qt creator 编译运行的时候会报找不到 一些dll,这时候需要把 这些缺失的 dll 复制到 exe 的同目录下,因为 我们的 FFmpeg 动态库在 MinGW 环境下编译的,所以依赖一些 MinGW的库,也需要把这些库复制过来,例如 ​​libiconv-2.dll​​ ,​​liblzma-5.dll​​ 等等。

这些库一定要复制对,不要把 32位的 复制过来,推荐 Everything 搜索,如下:

Qt使用FFmpeg的动态库_动态库_11

复制完之后如下:

Qt使用FFmpeg的动态库_动态库_12

这样,再次运行,就可以正常打印出 信息,如下:

Qt使用FFmpeg的动态库_动态库_13


下面再使用 qt creator 的 MSVC 来编译 main.c 看看,如下:

Qt使用FFmpeg的动态库_FFmpeg_14

同时要修改一下 DLL_IMPORT_TYPE 变量,设置为 msvc,这样链接的时候就会使用 lib 后缀的导入库,因为我 pro 文件里面用了这个 DLL_IMPORT_TYPE 变量来执行不同的分支代码。

Qt使用FFmpeg的动态库_FFmpeg_15


前面 引入的 都是 msys2 + mingw 编译出来 FFmpeg 动态库。

qt creator 如何 引入 msys2 + msvc 编译出来 FFmpeg 动态库 原理也是类似的,这里就不讲解了。