在第一篇文章《在 Rust 中使用 FFmpeg (1):环境搭建》中我们通过 ffmpeg::decoder::find_by_name
(对应 FFmpeg 的 avcodec_find_decoder_by_name
)这样一个最简单的 API 调用验证了在 Rust 中使用 FFmpeg 的可行性。代码已经放到 GitHub 可以在这里找到,程序已改名为 hello
并作为整个测试工程的一个 package,运行方式要稍微改一下,如下:
cargo run --bin=hello
这个命令运行的很好,但是在 Windows 系统下如果我们直接双击运行编译出来的 hello.exe 的话,大概率会弹出如下的报错:
只能说理论是理论工程是工程,理论上看起来简单的东西在工程实践上可能有一系列的坑等着你踩,本章要探讨的链接库问题就是工程中最常见也必须首先解决的一个坑。
动态链接库
Windows 下有个 Dependency Walker 工具可以用来查看应用程序的 DLL 依赖关系,不过该工具在 Win10 下运行极其卡顿,这里推荐使用其开源替代品 Dependencies,直接下载编译好的 release 版本即可。
运行 DependenciesGUI 打开 hello.exe:
可以看到 hello.exe 依赖的 av 开头的几个 dll 找不到,这几个都是 FFmpeg 的动态库。crate ffmpeg-next
通过 vcpkg 使用 FFmpeg,而 vcpkg 默认安装的是动态库版本。
我们可以到 vcpkg 的目录找到这几个 dll 手工拷贝到 hello.exe 所在目录,依赖问题解决后就可以直接运行程序了。
实际上 ffmpeg-sys-next
(ffmpeg-next
依赖的底层 crate)已经帮我们做了一部分工作,将这些 dll 拷贝到了 target/build/debug
目录下一个名为 ffmpeg-sys-next-xxxxxxxx 的文件夹下的名为 out 的子文件夹。暂时还没找到优雅的方法获得这个路径,否则就可以在 build.rs
中实现自动拷贝了。如果哪位大佬清楚还请指教。
静态链接库
Windows 下可以实现静态链接 FFmpeg 库,其他平台暂时还未研究。
首先,使用 vcpkg 安装 FFmpeg 的静态库版本:
vcpkg install ffmpeg --triplet=x64-windows-static-md
然后添加系统环境变量CARGO_FEATURE_STATIC
,值设为 1:
记得重启终端和 IDE 令环境变量生效。
删除 target 目录重新编译项目,报错信息如下:
这是个好消息,说明已经在尝试链接静态库了。找不到的符号都是 Windows 系统 API,分别添加对应的链接命令即可解决。
以下面这一条报错信息为例:
avdevice.lib(dshow.o) : error LNK2019: 无法解析的外部符号 __imp_OleCreatePropertyFrame,函数 dshow_cycle_pins 中引用了该符号␍
符号 __imp_OleCreatePropertyFrame
对应的系统 API 是 OleCreatePropertyFrame
,在 MSDN(现在改叫 Microsoft Learn 了) 中查找对应的说明文档,直接拉到最下面的 Requirements 表格,可以看到这个 API 是 OleAut32.dll 提供的,对应的 lib 库是 OleAut32.lib:
在 hello
这个 package 的根目录下新建 build.rs
, 然后在 main 函数中添加如下代码指示 rust 编译器链接 OleAut32.lib:
println!("cargo:rustc-link-lib=OleAut32");
对其他链接错误如法炮制,稍加整理后,最终的 build.rs
内容如下:
#[cfg(windows)]
fn link_system_libs() {
println!("cargo:rustc-link-lib=Gdi32");
println!("cargo:rustc-link-lib=OleAut32");
println!("cargo:rustc-link-lib=Shlwapi");
println!("cargo:rustc-link-lib=Mfuuid");
println!("cargo:rustc-link-lib=Strmiids");
println!("cargo:rustc-link-lib=Vfw32");
}
#[cfg(not(windows))]
fn link_system_libs() {}
fn main() {
link_system_libs();
}
不出意外的话这次可以成功编译运行了,用 Dependencies 查看 hello.exe 的依赖关系:
果然,依赖的只有系统 dll,FFmpeg 库已经是静态链接了。
在 Rust 中使用 FFmpeg 系列文章
《在 Rust 中使用 FFmpeg (1):环境搭建》
《在 Rust 中使用 FFmpeg (2):视频解码测试》
《在 Rust 中使用 FFmpeg (3):动态链接和静态链接》