在我的FFmpeg课程中,我总是推荐大家使用 Linux(Ubuntu)系统 或 Mac系统 来学习FFmpeg。其原因,是在Windows下编译FFmpeg太麻烦了,这大大增加了我们学习FFmpeg的成本。
不光如此,在Windows下编译FFmpeg所需要的依赖库也很麻烦,比如我们经常使用的fdk-aac、x264等在Windows下都要单独编译才可以使用。
不过,总还是有一些同学需要在Windows下使用FFmpeg,而FFmpeg官网上介绍的Windows下编译FFmpeg的文章实在是太老了,基本不可用。为了解决这部分同学的难题,这里我总结了一份Windows下编译和使用FFmpeg的方法,希望能帮助到大家!
准备编译环境
首先,我们要准备好编译环境,一台装有Windows10系统的电脑是必须的(没有比这再正确的废话了:))。
同时,要将Visual Studio安装好,比如 VS2019 社区版或 VS2022社区版(VS2019可以到这里下载,VS2022可以到这里下载)。这两个版本你用哪个都行,根据自己的需要选择吧。如果不是工作中必须要使用VS2019,那我建议你使用最新版的VS2022。
除了需要安装VS之外,还要安装MSYS2,这是一款Windows下模拟Linux的软件。FFmpeg的编译就是在该软件中进行的,而编译时使用的编译器(cl.exe)和链接器(link.exe)则是由Visual Studio提供的。MSYS2可以到这里下载
需要注意的是,在下载MSYS2时可能需要有网络代理才行。考虑到有些同学没有网络代理软件,我将MSYS2的一个备份放到了百度盘上,你也可以到这里下载。不过当你去百度盘下载这个软件时,它的版本可能已经比较老了,建议有条件的同学还是到官网上下载。
顺便说一下,对于刚学习Linux的同学来说,在Windows上装MSYS2学习Linux是个不错的选择,它比PowerShell要好用得多
下载源码
编译环境准备好之后,接下来我们需要下载一份最新的FFmpeg源码,你可以从这里下载,也可以使用Git下载。Git下载的方法如下:
- 先将Git命令安装好
- 然后执行下面的命令此时,代码就被下载到
1
2cd /d
git clone https://git.ffmpeg.org/ffmpeg.git ffmpegD:
盘的ffmpeg目录下了
Windows下编译FFmpeg的方法
当 FFmpeg 源码准备就绪后,我们就可以编译FFmpeg了。
首先,进入MSYS2的安装目录,比如我这里将MSYS2安装到了D:\MSYS64
目录下。在该目录下打开 msys2_shell.cmd 文件,将该文件第 17 行代码的注释打开,即去掉 rem 关键字,如下所示:
1 | @echo off |
之所以要打开该注释,是为了让MSYS2可以继承Windows控制台的环境变量。
之后,通过面的方法找到x64 Native Tools Command Prompt for VS 2019
命令窗口:
1 | Windows开始菜单 -> Visual Studio 2022 -> x64 Native Tools Command Prompt for VS 2019 |
在该命令窗口中输入下面的命令启动 MSYS2 软件
1 | # 进入到MSYS2 目录下 |
此时,会弹出MSYS2的命令窗口。接下来,在该窗口中输入下面命令,安装必要的编译工具:
1 | pacman -S diffutils make pkg-config yasm |
其中 pacman 是MSYS2的 包安装工具;而 diffutils、make……都是编译FFmpeg时需要用的 编译工具。
当编译工具安装好后,曳光弹在MSYS2命令窗中执行下面命令,进入到FFmpeg源码目录下:
1 | cd /d/ffmpeg |
紧接着,运行 FFmpeg 源码目录中的 configure
脚本生成 Makefile 文件,命令如下:
1 | ./configure --prefix=/usr/local/ffmpeg--enable-gpl --enable-nonfree --enable-shared --disable-ffprobe --toolchain=msvc |
上述命令的含义是使用mscv作为FFmpeg的编译工具链;编译出的FFmpeg库被放到/usr/local/ffmpeg
目录下;编译的库是动态库,在Windows下就是 DLL 库;编译时不生成 ffprobe 程序。
上述脚本执行完成后,你可以在 FFmpeg 源码目录下发现多了一个 Makefile 文件。有了这个文件我们就可以编译FFmpeg了,编译命令如下:
1 | make -j 4 && make install |
当执行完这条命令后,在 /usr/local/ffmpeg/bin
目录下就可以找到编译好的FFmpeg库和FFmpeg命令了。
需要注意的是,編译时有你有可能会遇到到如下错误:
1 | ...... error C2065: “slib”: 未声明的标识符 |
该问题是因为在Windows下无法识别 CC_IDENT 导致的,只需将包括 CC_IDENT关键字的那行代码注释掉即可。
在Windows上找到编译好的FFmpeg库
上面我将编译好的FFmpeg库安装到了/usr/local/ffmpeg
目录下,但在Windows下如何找到这个目录呢?
其实非常简单,你只需确定好MSYS2的根目录是哪儿就可以找到编译好的FFmpeg库了。以我的环境为例,我将MSYS2安装到了D:\MSYS64
这个目录下,那么D:\MSYS64
这个目录就是MSYS2的根目录。
因此,我编译好的FFmpeg库就存放在D:\MSYS64\usr\local\ffmpeg
目录下。
VS项目中引用FFmpeg库
编译好FFmpeg库后,下面我们就可以在VS中引用它了。
首先你要创建一个新的VS项目,具体方法如下:
1 | 打开VS -> 创建新项目 -> 创建控制台项目 -> 填写项目名 |
项目创建好后你会发现它里边只有一个testffmpeg.cpp
文件,该文件特别简单,只有一个main(...)
函数和一条cout << ...
语句。现在我们就可以在这个main(...)
函数中调用FFmpeg API 了。
但在开始编码之前,我们需要将用到的FFmpeg库和头文件引入到VS工程中,这样后面VS才能正确的将程序编译出来。下面咱们来看看该如何在VS中引入FFmpeg库头文件、库文件:
引入FFmpeg头文件
在
1
项目右键 -> 属性 -> C/C++ -> 常规 -> 附加包含目录
中添加FFmpeg头文件所在路径。
指定库文件位置
在
1
项目右键 -> 属性 -> 链接器 -> 常规 -> 附加库目录
中添加FFmpeg库所在路径。
指定使用哪个库
在1
项目右键 -> 属性 -> 链接器 -> 输入 -> 附加依赖项
中指定你所用到的FFmpeg库,如avutil.lib
当上面这此工作完成后,我们就可以在main(...)
函数中调用FFmpeg API了,如调用FFmpeg库中的日志函数:
1 | ... |
上述代码中,调用了FFmpeg中的两个API,分别是 av_log_set_level(...)
以及av_log(...)
,这两个函数都是FFmpeg avutil库中的API。所以在使用这两个API之前,我们要在main.c中需要通过#include
关键字将 libavtuil/log.h 这个头文件引入进来。
此外,由于FFmpeg是C语言库,而我们用VS创建的是C++工程,所以在引入头文件时需要加上extern "C"
关键字,否则的话VS无法将其成功编译。
运行编译好的程序
上面当我们运行编译好的程序时你会发现,它弹出了报错窗口,显示 “无法找到xxx.dll库” 的出错信息,其原因是在运行时无法找到需要的动态库。
解决办法很简单,只需将我们之前编译好的FFmpeg库,即提示的无法找到的.dll
库,拷贝到执行程序的同一目录下,这样执行程序就可以找到该库并正确执行了。
编译FFmpeg依赖库
很多时候我们在编译FFmpeg库时还要增加一些其它库,如SDL、x264等,如何能将这些库添加到FFmpeg中呢?
要想将这些库编译到FFmpeg中,首先我们要编译出Windows下可用的对应库,下面咱们就来看一下如何在Windows系统下将它们编译出来。
编译SDL
首先从github上获取SDL源码,命令如下:
1 | git clone https://github.com/libsdl-org/SDL.git |
需要注意的是,SDL现在已经发布了3.0版本,而ffmpeg目前只能用SDL2版本,所以在拉取代码后,需要切换到2.26这个版本
下载好 SDL2 源码后,我们需要使用 CMake 为其生成VS工程,所以我们首先到这里下载CMake,并将其安装到Windows系统上。
之后打开 CMake-GUI,在 CMake-GUI 中指定SDL2源码所在路径以及编译后的输出路径,随后执行
1 | Configure -> Generate |
生成VS工程。有了VS工程,我们就可以通过VS2019或VS2022来编译SDL了。
需要指出的是,编译好的SDL会保存到指定输出目录的 Release 或 Debug 目录下(例如指定的输出目录为/usr/local/sdl2
,则输出路径为/usr/local/sdl2/Release
),而我们希望输出的路径则是/usr/local/sdl2/lib
。
为了满足要求,我们需要在指定输出目录下创建 lib 目录,并将SDL2.lib 和 SDL2.dll文件拷贝到 lib 目录下。同时在 lib 目录下创建 pkgconfig 目录,将sdl2.pc 文件拷贝到该目录中。
此外,我们还要修改 sdl2.pc 中的内容,将其中的库路径修改为指定的输出路径,最终完整的目录结构如下所示:
1 | /usr/local/sdl2 |
编译x264
x264库的编译还是比较简单的,与SDL一样我们也要先获取其源码,可以通过下面的命令获取x264源码:
1 | git clone https://code.videolan.org/videolan/x264.git |
源码获取到后,可以直接在MSYS2环境下编译出Windows下可用的动态库,具体步骤如下:
1 | # 通过VS X64 Native... 窗口打开MSYS2 |
通过上面的命令就可以将x264编译出来了。x264编译好后,其输出的目录结构与SDL2是一样的,在/usr/local/x264
中包括了include
、lib
、bin
等目录。
要特别强调的一点是,我们需要将lib
目录下的libx264.dll.lib
文件名修改为libx264.lib
,否则ffmpeg编译时会报 “无法找到该库” 的错误。
编译fdk-aac
fdk-aac的编译与SDL类似,它同样要使用CMake生成VS工程文件,之后再通过VS编译该库。
首先,通下面的的命令获取fdk-aac源码:
1 | git clone https://github.com/mstorsjo/fdk-aac.git |
之后,通过CMake生成VS工程文件,具体执行步骤请参考 SDL 生成 VS 工程的步骤,这里就不再重复了。
接下来,使用VS2019或VS2022编译fdk-aac,编译好的库同要会被放到Release或Debug目录下,因此我们必须像处理SDL库一样,需要手工组织fdk-aac的输出目录树。
至此fdk-aac就算编译好了。
在编译fdk-aac时有个特殊情况,就是使用CMake的方式无法产生include头文件(这也有可能是我哪块执行的不对)。为了解决这个问题,我又用 MSYS2+mingw 的方式重新编译了一遍fdk-aac,这种方式是可以生成 include 头文件的,然后将生成的头文件手动拷贝到了/usr/local/fdk-aac目录下即可。
FFmpeg如何使用上述编译好的库呢?
首先,我们要设置环境变量PKG_CONFIG_PATH
,通过它告诉FFmpeg上述几个库从哪儿可以找到,具体的设置方法如下:
- 在MSYS2窗口中打开
.bashrc
1
2pacman -S vim
vim ~/.bashrc - 在
~/.bashrc
中设置环境变量1
2
3export PKG_CONFIG_PATH=/usr/local/sdl2/lib/pkgconfig:/usr/local/x264/lib/pkgconfig:/usr/local/fdk-aac/lib/pkgconfig:$PKG_CONFIG_PATH
:wq #保存并退出vim - 让环境变是生效
1
source ~/.bashrc
接下来,重新生成FFmpeg的Makefile文件,并重新编译,命令如下:
1 | ./configure --prefix=/usr/local/ffmpeg --arch=x86_64 --enable-shared --disable-ffprobe --disable-doc --enable-libx264 --enable-gpl --enable-fdk-aac --enable-nonfree --toolchain=msvc |
最后,将sdl2的dll、x264的dll以及fdk-aac的dll拷贝到ffmpeg的bin目录下,这样就可以正确的执行 ffmpeg.exe 或 ffplay.exe 命令了。
小结
上面就是在Windows下编译和使用FFmpeg的方法。如果你在Linux或Mac下可以熟练的编译FFmpeg,你会发现,在Window下编译FFmpeg的步骤与在Linux和Mac下编译的步骤是一样的,关键点是在Windows下该如何搭建好编译环境。
此外需要强调的是,在Windows下编译FFmpeg时,由于它不能识别 CC_IDENT 关键字,所以编译时会报错,我们只需将使用该关键字的语句注释掉即可解决该问题。
另外,在程序中通过#include
引用FFmpeg头文件时,一定要记得加 extern "C"
关键字,告诉C++编译器,这个头文件是一个C类型的头文件,这样它才能正确编译。
附录
- ShiftMediaProject,有同学给我推荐了这个项目,我简单了解了一下,这个项目真不错,可以直接使用VS对FFmpeg进行调试,有兴趣的同学可以偿试一下。