在 Rust 中使用 FFmpeg (3):动态链接和静态链接

在第一篇文章《在 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:
MSDN文档示例
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 的依赖关系:
Dependencies 查看依赖
果然,依赖的只有系统 dll,FFmpeg 库已经是静态链接了。

在 Rust 中使用 FFmpeg 系列文章

《在 Rust 中使用 FFmpeg (1):环境搭建》
《在 Rust 中使用 FFmpeg (2):视频解码测试》
《在 Rust 中使用 FFmpeg (3):动态链接和静态链接》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值