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 压缩
每月269次下载
用于 2 crates
2.5MB
7K SLoC
dsi-bitstream
支持多种即时编码的压缩位流的Rust实现。
此库模仿了DSI Utilities中类似类的行为,但旨在更加灵活和(希望)高效。
两个主要特质是BitRead
和BitWrite
,它们分别关联两个主要实现BufBitReader
和BufBitWriter
。其他特质使读取和写入即时编码成为可能,例如在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
模块的文档以获取更多详细信息。
选项
有一些选项可以修改位读/写特质的行怍
- 可以使用
BE
或LE
类型作为第一个参数来选择端序。通常,本地端序是最好的选择,尽管有时一些底层指令(第一个位设置、最后一个位等)的缺乏可能会使非本地端序更有效。 - 数据逐字从后端读取或写入,字的大小可以通过第二个参数选择,但它必须与后端的字大小匹配,因此通常可以推断。目前,我们建议使用
usize
进行写入,以及是usize
一半的类型进行读取。
通过修改瞬时代码参数的默认值,可以获得更深入(以及更复杂)的调整。读取或写入瞬时代码的方法在支持特性中定义,通常具有const类型参数,特别是是否使用解码表(例如,GammaReadParam::read_gamma_param
)。这些特性为BitRead
/BitWrite
实现。唯一的例外是单值代码,它由BitRead::read_unary
和BitWrite::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