如何生成ffmpeg.dll
  1bTlX33AWdQ4 2023年11月13日 19 0

在前文《​​FFmpeg的API库介绍​​​》里面知道,FFmpeg 一共提供了 8 个 dll 库给外部使用,但是有时候为了软件的安装目录的文件更加简洁一点,会把这 8 个 dll 动态库全部合并进去一个 ​​ffmpeg.dll​​ 里面,挺多软件都这样做的,例如:Typora,draw.io,百度翻译,等等。

如何生成ffmpeg.dll_动态库


下面就来介绍如何生成 ​​ffmpeg.dll​​,在阅读本文之前,推荐阅读《编译链接基础知识》一章的以下文章。

1,《​​MSVC编译多个C程序文件​​》

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

我个人不太喜欢只写 步骤型 的文章,例如教你改 ​​makefile​​ 的哪个位置,添加哪些代码,就能生成 ​​ffmpeg.dll​​,这种步骤型的知识只能治标,不能治本。

我喜欢写的是 dll 动态库的生成过程,调了那些命令,命令的选项参数是什么的。我喜欢写的是,我是怎么学会这个技能的,这样可以举一反三,掌握了这些知识,即使后面遇到其他的 C/C++ 项目,也能轻松解决。

回顾《编译链接基础知识》一章的知识,动态库也是由多个 ​​.obj​​ 文件 生成的,如下:

link.exe /DLL /DEBUG /EXPORT:sun_rotate /EXPORT:moon_rotate /EXPORT:earth_rotate /OUT:star.dll earth.obj moon.obj sun.obj

上面的 ​​/EXPORT​​ 选项是导出 ​​.obj​​ 文件里面的哪些函数给外部使用,在 MSVC 环境上,是需要使用 ​​/EXPORT​​ 选项或者 def 文件来导出函数给外部使用的。Linux 的 gcc 环境,好像不需要这样做,好像默认是暴露 ​​.o​​ 文件里面的全部函数,可能 ​​gcc​​ 也可以设置只导出一部分,这个我不太清楚,后面补充。

提示:在 msys2 命令行下,虽然用的是 msvc 编译器,但是生成的目标文件的后缀是 ​​.o​​ ,而不是 ​​.obj​​,但是他们的内容格式是一样的。链接器不是以后缀名判断格式的。msys2 只是为了通用,所以把 ​​.obj​​ 后缀换成了 ​​.o​​ 后缀。


既然 dll 是通过 ​​.o​​ 文件生成的,我们只需要找到 FFmpeg 的 ​​makefile​​ 是在哪里生成 dll 的,然后照葫芦画瓢操作一下就可以了。

在《​​makefile逻辑分析​​》里知道,生成 8 个动态库的 ​​makefile​​ 代码在 ​​library.mak​​ 里面,如下:

如何生成ffmpeg.dll_动态库_02

这条命令很多变量,会不太容易看懂,大家可以使用 ​​make -n > test.txt​​ 命令,把 makefile 真正执行的命令转存到 ​​test.txt​​ 里面,就能看到最终是哪条命令生成 dll 动态库的了,如下:

提示:如果之前已经生成了动态库,需要先 make clean 删除掉,要不 ​​make -n​​ 没有内容输出的。

如何生成ffmpeg.dll_后缀_03

上图中的 两行命令,实际上就对应 ​​library.mak​​ 里面的两行代码,如下:

$(SLIB_CREATE_DEF_CMD)
$$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS)
$(SLIB_EXTRA_CMD)

​$(SLIB_CREATE_DEF_CMD)​​ 这句代码是执行 ​​./compat/windows/makedef​​ ,​​makedef​​ 是一个 shell 脚本,这个脚本是生成 ​​.def​​ 文件的,例如 ​​avdevice-58.def​​,​​avdevice-58.def​​ 是控制 ​​dll​​ 里面的哪些函数暴露给外部使用的。

​$$(LD)​​ 这句代码就是生成 ​​dll​​ 的代码,​​./compat/windows/mslink​​ 也是一个 shell 脚本,它最终调用的就是 ​​link.exe​​,​​mslink​​ 脚本会优选使用跟 ​​cl.exe​​ 同目录下的 ​​link.exe​​,这样是为了防止用错了了 ​​mingw​​ 的 ​​link.exe​​。

上图中可以看到,​​avdevice-58.def​​ 会传递给 ​​link.exe​​ 链接器

​$(SLIB_EXTRA_CMD)​​ 这行代码在 windows 环境下是 空,所以什么都没做。


从上图的命令可以看到,为了生成 ​​avcodec-58.dll​​,传递了很多的 ​​.o​​ 文件给 ​​link.exe​​。因此只要我们把 8 个 dll 需要的 ​​.o​​ 文件找出来,然后全部都传递给 ​​link.exe​​ 就能 生成一个 ​​ffmpeg.dll​​ 了,这样就把 8 个 动态库合并成一个了。

但是这些 ​​.o​​ 文件非常多的,我们并不需要一个一个找出来。有个快捷技巧,那就是直接把 静态库 拿来用,​​libavcodec.a​​ 这些静态库就是 ​​.o​​ 文件的集合,静态库的原理就是把多个 ​​.o​​ 文件打包在一起,所以我们可以直接使用静态库来生成动态库

不过由于后面需要用到一些 def 文件,而 def 文件是随着 DLL 动态库一起生成的,我们需要先参考《​​用msys2与msvc编译FFmpeg​​》编译出动态库,编译完成之后,就可以在 ​​build64\ffmepg-4.4-msvc\lib​​ 目录看到 ​​avcodec-58.def​​ 等文件,如下:

如何生成ffmpeg.dll_动态库_04

提醒:我们不需要 bin 目录下的 ​​avcodec-58.dll​​ 等 dll 文件,只是要用一下这些 def 文件。


然后再执行一下 make clean,把生成的文件删掉,再执行以下命令生成 静态库,如下:

./configure \
--prefix=/home/loken/ffmpeg/build64/ffmepg-4.4-msvc-static \
--enable-gpl \
--enable-nonfree \
--disable-sdl2 \
--disable-optimizations \
--disable-asm \
--disable-stripping \
--extra-cflags="-MDd" \
--toolchain=msvc

上面的命令把 ​​--enable-shared​​ 删除,所以会生成静态库,然后再执行下面的命令。

make -j12
make install

运行完毕之后,就可以在 ​​ffmepg-4.4-msvc-static/lib​​ 目录看到静态库,如下:

如何生成ffmpeg.dll_后缀_05

然后,我们把 之前编译动态库的时候生成的 ​​avcodec-58.def​​ 等 复制到跟 静态库同级的目录,如下:

如何生成ffmpeg.dll_后缀_06

由于 ​​link.exe​​ 链接器 ​​-def​​ 选项好像不能支持多个 ​​def​​ 文件输入,所以我把 这 8 个 def 文件的内容全部复制到 ​​ffmpeg.def​​ 里面了,如下:

如何生成ffmpeg.dll_后缀_07

注意:def 文件只能有一个 ​​EXPORTS​​ ,不要把 ​​EXPORTS​​ 也复制 8 个进去,这里提供一个 ​​ffmpeg.def​​ 文件下载,供读者参考。


然后就可以执行下面的命令把这 8 个静态库合成一个 ffmpeg.dll 了,如下:

cd /home/loken/ffmpeg/build64/ffmepg-4.4-msvc-static/lib
../../../FFmpeg-n4.4.1/compat/windows/mslink -dll -def:ffmpeg.def -implib:ffmpeg.lib -nologo -debug -out:ffmpeg.dll secur32.lib Ws2_32.lib mfplat.lib mfuuid.lib ole32.lib strmiids.lib ole32.lib user32.lib bcrypt.lib oleaut32.lib ole32.lib shlwapi.lib gdi32.lib vfw32.lib libavcodec.a libavdevice.a libavfilter.a libavformat.a libavutil.a libpostproc.a libswresample.a libswscale.a

上面的命令,有一些 lib 导入库是 Windows 系统的库,例如 gdi 库,我是怎么知道需要这些库的呢?是通过之前的 ​​make -n​​ 生成的 ​​test.txt​​ 里面的选项 参数的。

编译完成之后,就可以看到 ​​ffmpeg.dll​​ 了,如下:

如何生成ffmpeg.dll_后缀_08

如何生成ffmpeg.dll_静态库_09


下面我们就用一个示例 ​​input_2​​ 测试一下 这个 ​​ffmpeg.dll​​ 好不好用,编译环境是 Qt 5.15.2 跟 MSVC2019_64bit 。运行效果如下:

如何生成ffmpeg.dll_后缀_10

提示:这个 input_2 项目不知道为什么 mp4 文件 copy 不过去,所以需要手动复制到调试目录,还有 ffmpeg.dll 也 copy 失败了,要手动拷贝到 exe 统计目录,这是个 bug,我后面解决。

​ffmpeg.dll​​ 是可以正常使用的,再通过以下命令查看一下 ​​input_2.exe​​ 的 DLL 依赖,如下:

dumpbin.exe /DEPENDENTS input_2.exe

如何生成ffmpeg.dll_静态库_11

可以看到, ​​input_2.exe​​ 确实只依赖 ​​ffmpeg.dll​


其实把 8 个 动态库合并成一个 ffmpeg.dll 还有一个好处,可以节省一些空间,如下:

如何生成ffmpeg.dll_后缀_12

如何生成ffmpeg.dll_静态库_13

原来 8 个库是 25.3M,合并成一个 ​​ffmpeg.dll​​ 之后,变成了 19.1M 了。

不过这个可能是因为我编译动态库的时候,有些选项没设置。一般情况合并成一个 dll ,空间会有所减少,不过可能不会少 6 M 这么多。

虽然本文讲解的是在 windows 下生成 ​​ffmpeg.dll​​,但是在 Linux 下合成 ​​ffmpeg.so​​ 也是类似的原理。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
1bTlX33AWdQ4