mirror of
https://github.com/storytold/effectcraft.git
synced 2026-10-27 11:37:02 -06:00
88 lines
2.0 KiB
Rust
88 lines
2.0 KiB
Rust
//! MSB-first bit writer for the OBU headers (spec 4.10 `f(n)` descriptors) and `leb128()`.
|
|
|
|
#[derive(Default)]
|
|
pub(crate) struct BitWriter {
|
|
pub buf: Vec<u8>,
|
|
nbits: usize,
|
|
}
|
|
|
|
impl BitWriter {
|
|
pub fn new() -> Self {
|
|
BitWriter::default()
|
|
}
|
|
|
|
/// `f(n)`: writes the low `n` bits of `v`, most significant first.
|
|
pub fn f(&mut self, n: u32, v: u32) {
|
|
for i in (0..n).rev() {
|
|
self.bit((v >> i) & 1 != 0);
|
|
}
|
|
}
|
|
|
|
pub fn bit(&mut self, b: bool) {
|
|
if self.nbits.is_multiple_of(8) {
|
|
self.buf.push(0);
|
|
}
|
|
if b {
|
|
let last = self.buf.len() - 1;
|
|
self.buf[last] |= 0x80 >> (self.nbits % 8);
|
|
}
|
|
self.nbits += 1;
|
|
}
|
|
|
|
/// `byte_alignment()`: zero bits up to the next byte boundary.
|
|
pub fn byte_align(&mut self) {
|
|
while !self.nbits.is_multiple_of(8) {
|
|
self.bit(false);
|
|
}
|
|
}
|
|
|
|
/// `trailing_bits()`: a one bit followed by zero bits up to the byte boundary.
|
|
pub fn trailing_bits(&mut self) {
|
|
self.bit(true);
|
|
self.byte_align();
|
|
}
|
|
|
|
pub fn into_bytes(self) -> Vec<u8> {
|
|
self.buf
|
|
}
|
|
}
|
|
|
|
/// `leb128()` encoding of an OBU size.
|
|
pub(crate) fn leb128(mut v: usize, out: &mut Vec<u8>) {
|
|
loop {
|
|
let mut b = (v & 0x7f) as u8;
|
|
v >>= 7;
|
|
if v != 0 {
|
|
b |= 0x80;
|
|
}
|
|
out.push(b);
|
|
if v == 0 {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An OBU with `obu_has_size_field` = 1 and no extension header.
|
|
pub(crate) fn obu(obu_type: u8, payload: &[u8], out: &mut Vec<u8>) {
|
|
out.push((obu_type << 3) | 0x02);
|
|
leb128(payload.len(), out);
|
|
out.extend_from_slice(payload);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn bits_and_leb128() {
|
|
let mut w = BitWriter::new();
|
|
w.f(3, 0b101);
|
|
w.f(6, 0b110011);
|
|
w.trailing_bits();
|
|
assert_eq!(w.into_bytes(), vec![0b1011_1001, 0b1100_0000]);
|
|
let mut v = Vec::new();
|
|
leb128(300, &mut v);
|
|
assert_eq!(v, vec![0xAC, 0x02]);
|
|
}
|
|
}
|