如何生成ffmpeg.dll—FFmpeg魔改教程

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

1-1


下面就来介绍如何生成 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 里面,如下:

1-2

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

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

1-3

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

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

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

$$(LD) 这句代码就是生成 dll 的代码,./compat/windows/mslink 也是一个 shell 脚本,它最终调用的就是 link.exemslink 脚本会优选使用跟 cl.exe 同目录下的 link.exe,这样是为了防止用错了了 mingwlink.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 等文件,如下:

1-3-2

提醒:我们不需要 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 目录看到静态库,如下:

1-4

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

1-5

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

1-6

注意: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 了,如下:

1-7

1-8


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

1-9

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

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

dumpbin.exe /DEPENDENTS input_2.exe

2-0

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


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

2-1

2-2

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

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

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

版权所属 xianwanzhiyin.net 罗上文 2023 all right reserved,powered by Gitbook该文件修订时间: 2023-05-17 11:39:55

results matching ""

    No results matching ""