#codes #bitstream #data-stream

no-std dsi-bitstream

支持多种即时编码的读写位流的Rust实现

18个不稳定版本 (3个破坏性版本)

0.4.2 2024年4月7日
0.4.0 2024年3月18日
0.3.1 2024年2月27日
0.2.3 2024年2月3日
0.1.9 2024年1月27日

#152 in 压缩

Download history 88/week @ 2024-04-19 99/week @ 2024-04-26 141/week @ 2024-05-03 57/week @ 2024-05-10 91/week @ 2024-05-17 164/week @ 2024-05-24 101/week @ 2024-05-31 49/week @ 2024-06-07 36/week @ 2024-06-14 33/week @ 2024-06-21 38/week @ 2024-06-28 32/week @ 2024-07-05 32/week @ 2024-07-12 54/week @ 2024-07-19 119/week @ 2024-07-26 58/week @ 2024-08-02

每月269次下载
用于 2 crates

Apache-2.0 OR LGPL-2.1-or-later

2.5MB
7K SLoC

Rust 5.5K SLoC // 0.1% comments Python 1K SLoC // 0.2% comments Shell 10 SLoC // 0.4% comments

dsi-bitstream

downloads dependents GitHub CI license Latest version Documentation

支持多种即时编码的压缩位流的Rust实现。

此库模仿了DSI Utilities中类似类的行为,但旨在更加灵活和(希望)高效。

两个主要特质是BitReadBitWrite,它们分别关联两个主要实现BufBitReaderBufBitWriter。其他特质使读取和写入即时编码成为可能,例如在H.264 (MPEG-4)H.265中使用的指数Golomb码

# fn main() -> Result<(), Box<dyn std::error::Error>> {
use dsi_bitstream::prelude::*;
// To write a bit stream, we need first a WordWrite around an output backend
// (in this case, a vector), which is word-based for efficiency.
// It could be a file, etc. 
let mut word_write = MemWordWriterVec::new(Vec::<u64>::new());
// Let us create a little-endian bit writer. The write word size will be inferred.
let mut writer = BufBitWriter::<LE, _>::new(word_write);
// Write 0 using 10 bits
writer.write_bits(0, 10)?;
// Write 1 in unary code
writer.write_unary(0)?;
// Write 2 in γ code
writer.write_gamma(1)?;
// Write 3 in δ code
writer.write_delta(2)?;
writer.flush();

// Let's recover the data
let data = writer.into_inner()?.into_inner();

// Reading back the data is similar, but since a reader has a bit buffer
// twice as large as the read word size, it is more efficient to use a 
// u32 as read word, so we need to transmute the data.
let data = unsafe { std::mem::transmute::<_, Vec<u32>>(data) };
let mut reader = BufBitReader::<LE, _>::new(MemWordReader::new(data));
assert_eq!(reader.read_bits(10)?, 0);
assert_eq!(reader.read_unary()?, 0);
assert_eq!(reader.read_gamma()?, 1);
assert_eq!(reader.read_delta()?, 2);

# Ok(())
# }

在这种情况下,后端已经基于字,但如果你有基于字的后端,如文件,可以使用WordAdapter将其适配到基于字的后端。

您也可以使用后端的引用而不是拥有值,但这种方法效率较低

# fn main() -> Result<(), Box<dyn std::error::Error>> {
use dsi_bitstream::prelude::*;
let mut data = Vec::<u64>::new();
let mut word_write = MemWordWriterVec::new(&mut data);
let mut writer = BufBitWriter::<LE, _>::new(word_write);
writer.write_bits(0, 10)?;
writer.write_unary(0)?;
writer.write_gamma(1)?;
writer.write_delta(2)?;
writer.flush();
drop(writer); // We must drop the writer release the borrow on data

let data = unsafe { std::mem::transmute::<_, Vec<u32>>(data) };
let mut reader = BufBitReader::<LE, _>::new(MemWordReader::new(&data));
assert_eq!(reader.read_bits(10)?, 0);
assert_eq!(reader.read_unary()?, 0);
assert_eq!(reader.read_gamma()?, 1);
assert_eq!(reader.read_delta()?, 2);
# Ok(())
# }

请参阅traits模块和impls模块的文档以获取更多详细信息。

选项

有一些选项可以修改位读/写特质的行怍

  • 可以使用BELE类型作为第一个参数来选择端序。通常,本地端序是最好的选择,尽管有时一些底层指令(第一个位设置、最后一个位等)的缺乏可能会使非本地端序更有效。
  • 数据逐字从后端读取或写入,字的大小可以通过第二个参数选择,但它必须与后端的字大小匹配,因此通常可以推断。目前,我们建议使用usize进行写入,以及是usize一半的类型进行读取。

通过修改瞬时代码参数的默认值,可以获得更深入(以及更复杂)的调整。读取或写入瞬时代码的方法在支持特性中定义,通常具有const类型参数,特别是是否使用解码表(例如,GammaReadParam::read_gamma_param)。这些特性为BitRead/BitWrite实现。唯一的例外是单值代码,它由BitRead::read_unaryBitWrite::write_unary实现。

然而,还有一些具有非参数方法(例如,GammaRead::read_gamma)的特性,它们是用户的标准入口点。这些特性根据实现ReadParams/WriteParams的选择器类型分别实现为BufBitReader/BufBitWriter。参数的默认值是DefaultReadParams/DefaultWriteParams,它使用我们在几个平台上测试过的选项,并认为它们是良好的默认值,但通过传递ReadParams/WriteParams的不同实现,可以更改默认行为。有关更多详细信息,请参阅params

最后,如果您选择使用表,则表的大小已硬编码在源代码中(特别是,在codes源目录中的*_tables.rs文件中)并且只能通过在python目录中运行脚本gen_code_tables.py来更改,该脚本会根据脚本末尾硬编码的值重新生成表。

基准测试

要评估您的硬件上的性能,您可以在benchmarks目录中运行基准测试,该目录测试了在多个参数组合下读取/写入操作的速度。请参阅其中的 crate 文档。在svg目录中包含了一些架构的这些基准测试的参考结果。

测试

除了单元测试外,我们还提供由模糊测试生成的压缩预计算语料库。您可以通过启用 fuzz 功能来在这些压缩预计算语料库上运行测试。

cargo test --features fuzz

启用该功能后,如果存在,测试还会在顶级 fuzz 目录中找到的本地语料库上运行。

致谢

本软件部分由欧盟-NGEU 资助的 NRRP MUR 计划下的 SERICS 项目(PE00000014)和法国国家研究署的 ANR COREGRAPHIE 项目(ANR-20-CE23-0002)资助。

依赖关系

~4–30MB
~450K SLoC