每个主流平台基本都有自己的音视频开发库(API),用以处理音视频数据,比如:
为了让所有平台的开发者都能够学习到音视频开发的通用技术,本教程主要讲解跨平台的音视频开发库FFmpeg。其实只要你掌握了FFmpeg,也可以很快上手其他音视频开发库,因为底层原理都是一样的,你最终操作的都是一样的数据,比如MP3、MP4文件。
FFmpeg的名字由FF和mpeg组成。
有很多知名项目都采用了FFmpeg,比如:
FFmpeg 是一个开源项目,源码也是开放出来的。所以一般有两种下载方式:
第一种:源码下载,直接去官网下载即可,下列是文件列表(我们不做分析)
第二种:已经编译好的下载,以下是各个文件。
略过:
可以参考文章:https://www.cnblogs.com/mjios/p/14465178.html#toc_title_5
在Windows中,我们最终是通过调用FFmpeg动态库(dll)中的函数来操作音视频数据,使用dll的其中一种方式是需要用到 3种文件:
第一种:头文件(
xxx.h
文件)
- 包含了函数的声明
- 通过#include去导入相应的头文件
第二种:(动态链接库的)导入库(Import Library)文件。
不同编译器,使用的文件格式不同:
.lib
:用于MSVC编译器中.dll.a
:用于MinGW编译器中但是作用是相同的:
- 包含了dll中函数的入口,用于辅助找到,并调用dll中的函数。
- 最终需要链接到Windows程序中(比如合并到exe文件中)
第三种:动态链接库(Dynamic Link Library)(
.dll
)
- 包含了函数的具体实现代码
- Windows程序会在运行过程中,动态调用dll中的函数
值得一提的是,在Windows中,静态链接库(Static Link Library)的扩展名也是.lib、.dll.a。静态链接库和导入库的区别是:
Pro 文件是对编译器进行配置,指导编译器去哪里寻找动态库、哪里寻找头文件 等等。
INCLUDEPATH +=
:增加头文件的搜索路径。
LIBS +=
:指定链接库
注意:
FFMPEG_HOME
,指定 ffmpeg 的根目录。-L
:设置导入库的目录,以便编译器能够找到导入库-l
:link 设置需要链接的导入库名称# 库文件的根目录
win32{
FFMPEG_HOME = D:/openlib/ffmpeg-4.4.1-full_build-shared
}
macx{
FFMPEG_HOME = ..
}
# 设置头文件的目录,以便编译器能够找到头文件
INCLUDEPATH += $${FFMPEG_HOME}/include
# 设置导入库的目录和需要链接的导入库
LIBS += -L $${FFMPEG_HOME}/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample
实际的动态库文件如下图所示,但是在 pro 文件当中链接的时候需要注意名称。
(前面加 -l
代表 -link,拓展名 .lib
去掉)
编写代码测试:
#include "mainwindow.h"
#include
#include
// FFmpeg是C语言库
// 有了extern "C",才能在C++中导入C语言函数
extern "C" {
#include
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
qDebug()<< av_version_info();
w.show();
return a.exec();
}
运行结果:
4.4.1-full_build-www.gyan.dev
如果不能运行:
1、先测试一下 Qt 能不能搜索到对应的头文件,在 #include
的时候,IDE 会提示路径。
2、多半是 pro 文件对 变量的解引用问题,$${FFMPEG_HOME}
,可以先取消变量,直接将路径贴过去看看能不能使用。
现在的程序在 Qt 里面编译的时候可以运行,但是双击生成的 .exe
文件却不能运行。
原因:系统找不到 qt、ffmpeg 的动态库。
解决办法:
1、找到这些动态库的位置
2、解决系统无法定位的问题
使用 everything 搜索对应库的名称,虽然有很多的动态库文件,但是我们应该使用 Qt 的IDE当中自带的。
exe在寻找dll文件时,大概按照以下优先级顺序去查找(这里只列出了大概的搜索路径,并没有写全):
(1).exe
所在的目录
(2)Windows 的 System目录
C:/Windows/System
C:/Windows/System32
(3)Windows目录:C:/Windows
(4)环境变量Path中的路径
我个人一般使用第四种方法,将动态库的路径配置到环境变量当中。
第1种方式需要在每一个Qt程序中都拷贝一份FFmpeg的dll文件,第2~4种方式可以让多个Qt程序共用同一份FFmpeg的dll文件。
(1)ffplay 是基于FFmpeg、SDL两个库实现的。通过编程的方式播放音视频,也是需要用到这2个库。FFmpeg大家都已经清楚了,比较陌生的是SDL。
(2)SDL(Simple DirectMedia Layer),是一个跨平台的C语言多媒体开发库。
(3)SDL官网下载地址:https://www.libsdl.org/download-2.0.php
(4)解压后的目录结构如下图所示,跟FFmpeg的目录结构类似,因此就不再赘述每个文件夹的作用。
# 库文件的根目录
win32{
FFMPEG_HOME = D:/openlib/ffmpeg-4.4.1-full_build-shared
SDL_HOME = D:/openlib/SDL2-2.0.22/x86_64-w64-mingw32
}
macx{
FFMPEG_HOME = ..
}
# 设置头文件的目录,以便编译器能够找到头文件
INCLUDEPATH += $${FFMPEG_HOME}/include
INCLUDEPATH += $${SDL_HOME}/include
# 设置导入库的目录和需要链接的导入库
LIBS += -L $${FFMPEG_HOME}/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample
LIBS += -L $${SDL_HOME}/lib \
-lSDL2
原因:LIBS 链接的时候:-L
后面不能有空格。
修改:
LIBS += -L$${FFMPEG_HOME}/lib \
-lavcodec \
-lavdevice \
-lavfilter \
-lavformat \
-lavutil \
-lpostproc \
-lswscale \
-lswresample
LIBS += -L$${SDL_HOME}/lib \
-lSDL2
#include "SDL2/SDL.h"
修改:
extern "C"{
#include "SDL2/SDL.h"
#undef main
}