1、前言

  其实网上到处都能找到相关文章,之所以写这篇文章是因为我在移植过程中遇到过各种各样的坑,然后网上找解决方案解决方案还不一样,最终终于找到了适合自己的一套方案,先记录下来。总结一下其实在QT上移植一个FFmpeg 的库非常简单,很多时候是被误导了,又是windows又是linux,又是32位的QT或者64位QT,或者32位系统64位系统等等乱七八糟的。

  我是个记性极差的人,我记不住太多东西也不想去记,写这篇文章的目的就是为了记录我找到了一种可行的办法。

2、库文件下载

  下载地址:https://ffmpeg.org/download.html

  

  在弹出的界面中,鼠标下滑,找到release builds,然后找到previous release,这几个都是可以用的,essentials表示的是必要的,顾名思义这是个阉割版,full则是完全版,不带shared的只有可执行文件,如果只想学习FFmpeg的命令行下这个就行了,然后把里面的exe文件路径添加到环境变量里就可以直接用,如果要编程去调里面的函数,就要下带shared的版本。

  

   文件解压后bin、include、lib这几个文件夹里的东西是要移植到QT里的,具体怎么移在后面说。

  

  bin文件夹里面有3个exe文件,和一些dll文件,如下图:

  

  这几个exe文件是可以用命令行运行的,可以先测一下下下来的这个东西能不能在自己电脑上运行,操作方法为:

  按住shift键后在空白处右键->在此处打开powershell窗口,然后输入./ffmpeg -version,正常来说会打印出一些版本信息,如下图:

  

  如果没有,则说明下下来的这个库文件不能在你电脑上运行,这个时候想一下是不是下错了。

   include文件夹里面还有8个文件夹,这些文件夹里面才是一个个的头文件。

  

3、创建QT工程

  选择编译器要选MSVC的64位的这个

  

   然后main.cpp里面先随便写个hello world:

 1 #include "mainwindow.h"
 2 #include <QApplication>
 3 #include <iostream>
 4 
 5 using namespace std;
 6 
 7 int main(int argc, char *argv[])
 8 {
 9     QApplication a(argc, argv);
10     MainWindow w;
11     w.show();
12 
13     cout << "hello" << endl;
14 
15     return a.exec();
16 }

  运行一下,能正常输出,证明目前这个工程是没问题的:

 4、移植文件

  FFmpeg属于三方库,一般会在工程中创建一个thridpart文件夹专门用来存放三方库,然后在thirdpart里面新建一个ffmpeg文件夹,再把下载下来的ffmpeg库里的include和lib两个文件夹全部拷贝到ffmpeg文件夹下,如下图:

  

  现在东西已经放到工程目录了,但是还得告诉QT要把这些东西真正的放到工程里去。注意

  注意后面的步骤对新手来说很容易出幺蛾子。

  先说错误做法,在工程中右键->添加现有文件,然后把include目录下的子目录下的所有头文件添加进去,或者直接打开.pro文件,找到HEADERS,把需要添加的头文件全部加在后面,这两种做法本质上是一样的,目的是为了让编译器能找到对应的头文件,虽然这样编译器能找到对应的头文件,但是这样做是错的。为什么呢,我们随便打开里面的一个头文件,比如include\libavcodec\avcodec.h,它前面有一段包含别的头文件的代码,如下:

#include "libavutil/samplefmt.h"
#include "libavutil/attributes.h"
#include "libavutil/avutil.h"
#include "libavutil/buffer.h"
#include "libavutil/channel_layout.h"
#include "libavutil/dict.h"
#include "libavutil/frame.h"
#include "libavutil/log.h"
#include "libavutil/pixfmt.h"
#include "libavutil/rational.h"

  这里面去包含一个头文件的方式是把头文件所在路径包含进去了,也就是说我们不需要去指定具体应该包含哪个头文件,只需要告诉编译器去“include”这个目录下去找就行了(当然我们使用的时候也要这么用)。具体方法是在.prj文件里面加一个INCLUDEPATH,如下:

  

  接下来要把lib文件夹里的库添加进去,这里网上能找到不同的说法,比如加不加-L,加不加小写的l,加不加.lib等,可能不同的版本是会不一样,但是有个最简单的办法是直接在工程上右键->添加库,如下:

  

 

 

   点击完成之后,在.pro文件会增加几行,重点就是看加的那几行的格式,比如:

   这个时候我们就知道添加库的写法是这么写的,于是刚刚新增的这么多行都可以删了,按照他自己添加的方法这样写就行了。修改后如下:

LIBS += \
    -L$$PWD/thirdpart/ffmpeg/lib/ -lavcodec \
    -lavdevice \
    -lavfilter \
    -lavformat \
    -lavutil \
    -lpostproc \
    -lswresample \
    -lswscale

  这个时候就可以改下main函数,测试一下移植成功了没,改过的main函数如下:

 1 #include "mainwindow.h"
 2 #include <QApplication>
 3 #include <iostream>
 4 
 5 extern "C" {
 6 #include "libavcodec/avcodec.h"
 7 }
 8 
 9 using namespace std;
10 
11 int main(int argc, char *argv[])
12 {
13     QApplication a(argc, argv);
14     MainWindow w;
15     w.show();
16 
17     cout << "version is " << endl;
18     cout << avcodec_version() << endl;
19 
20     return a.exec();
21 }

  注意包含的ffmpeg的头文件要加exttern “C”,否则编译会报如下错误:

  main.obj:-1: error: LNK2019: 无法解析的外部符号 "unsigned int __cdecl avcodec_version(void)" (?avcodec_version@@YAIXZ),该符号在函数 main 中被引用

   编译过去之后可以试着运行一下,但是肯定会报错“程序异常结束”,这是因为缺少程序运行时需要的库,这时找到运行的exe文件所在的目录,把ffmpeg里面的bin文件夹里的所有dll文件拷贝到和自己生成的exe文件相同的目录下,再运行就可以了:

  运行结果如下: