3个不稳定版本

0.2.0 2024年6月23日
0.1.2 2024年6月23日
0.1.1 2023年2月25日
0.1.0 2023年2月13日

#109 in 音频

BSD-3-Clause

1.5MB
47K SLoC

unsafe-libopus

这个库是将libopus 1.3.1从C语言翻译为不安全Rust语言,并使用c2rust辅助完成的。

因为它与C代码的结构几乎相同,并且充满了“不安全”的元素,所以被称为“不安全”的libopus。

这种转换仍然允许你在纯Rust环境中使用库,无需链接器技巧和动态链接问题,从而摆脱C编译器工具链。

这也许可以是libopus的更符合Rust风格的实现的开端,尽管我不确定这是否值得付出努力。

使用方法

您可以通过使用来自此PRopus crate的分支来利用此库

[dependencies]
opus = { git = "https://github.com/DCNick3/opus-rs.git", branch = "unsafe-libopus", default-features = false, features = ["unsafe-libopus-backend"] }

也许,这个库将来会有安全的API,但现在,它主要是audiopus_sys crate的替代品。

转换技术

首先,使用以下命令编译了libopus 1.3.1

CC=clang ./configure --disable-shared --disable-stack-protector --enable-extra-programs --disable-doc --disable-asm --disable-rtcd --disable-intrinsics --disable-dependency-tracking--disable-maintainer-mode --enable-hardening
CC=clang compiledb make -j

然后,使用生成的compile_commands.json文件,使用以下命令将C代码转换为Rust:

c2rust transpile compile_commands.json -o . --overwrite-existing --reorganize-definitions --emit-modules --translate-const-macros --emit-build-files

然后,手动重新组织生成的代码,以删除所有结构体的重复,并消除对#[no_mangle] extern "C"函数的使用:它们现在都链接到Rust,无需导出。

其他重构包括

  • 将测试二进制文件从库中分离出来作为“示例”
  • 通过在库中定义它们的变体来删除对libc函数的依赖(灵感来自unsafe-libyaml
  • 通过将libc类型替换为具体的Rust类型来删除对libc crate的依赖(例如libc::c_int -> i32等)
  • 通过将 C 的变长参数替换为自定义的 VarArgs 结构体来移除 C 的变长参数,因为 Rust 中的 C 变长参数还不稳定。这使得 opus_*_ctl 函数族变为宏。

性能

该库的翻译未使用内联汇编、处理器 intrinsic 和运行时 CPU 检测,因此目前不如原始代码快。具有这些功能的 C 版本在我的机器上比 Rust 版本快约 20%。

正确性

该库使用 C 代码库中的(大部分)原始测试进行测试。它们以 Rust 集成测试的形式存在于 tests 目录中。C 代码库中的许多单元测试尚未翻译。

测试的核心在于 unsafe-libopus-tools/src/bin/run_vectors2.rs。它使用 IETF 发布的测试向量对解码器和编码器进行测试,并将结果与位于 upstream-libopus 的 opus 1.3.1 的 C 实现进行比较。它对结果进行了一些小的修改,以提高可移植性。

解码器通过解码测试向量和将结果与多个输出采样率下的 C 实现进行比较来测试。它们被检查以完全匹配。

对编码器执行同样的操作,在多个不同的比特率下运行,并将编码结果与 C 实现进行比较。除了比特率外,没有更改其他参数,这目前是测试的一个弱点。

严格来说,对于这是一个有效实现,不需要相同的编码结果:编码器可以自由做出很多选择,从而产生不同的质量结果。然而,制作一个比原始 opus 更好的编解码器不是目标。因此,通过要求完全相同的结果,我们防止了编码器行为的任何偏差。

安全性

目前,大多数代码都是不安全的,因为它是 C 代码的直接翻译。

我正在逐步重构代码,以确保其某些部分的安全性。以前保持有效性是一个挑战,但现在有了针对 C 代码实现进行测试的测试,这应该会更容易。

许可证

与原始 libopus 一样,unsafe-libopus 在 BSD 3 条款许可证下授权。

依赖关系