pub struct BoolEncoder {
low: u32,
range: u32,
count: i32,
out: Vec<u8>,
}
impl BoolEncoder {
pub fn new() -> BoolEncoder {
let mut e = BoolEncoder {
low: 0,
range: 255,
count: -24,
out: Vec::new(),
};
e.write_bool(0, 128);
e
}
pub fn write_bool(&mut self, bit: u32, prob: u8) {
let range0 = self.range;
let split = 1 + (((range0 - 1) * prob as u32) >> 8);
let mut low = self.low;
let mut range = if bit != 0 {
low = low.wrapping_add(split);
range0 - split
} else {
split
};
let mut shift = (range as u8).leading_zeros() as i32;
range <<= shift;
let mut count = self.count + shift;
if count >= 0 {
let offset = shift - count; if offset >= 1 && (low << ((offset - 1) as u32)) & 0x8000_0000 != 0 {
let mut x = self.out.len() as isize - 1;
while x >= 0 && self.out[x as usize] == 0xff {
self.out[x as usize] = 0;
x -= 1;
}
debug_assert!(x >= 0, "vp9 bool encoder: carry underflow");
if x >= 0 {
self.out[x as usize] += 1;
}
}
self.out
.push(((low >> ((24 - offset) as u32)) & 0xff) as u8);
low <<= offset as u32;
shift = count;
low &= 0x00ff_ffff;
count -= 8;
}
low <<= shift as u32;
self.count = count;
self.low = low;
self.range = range;
}
pub fn write_literal(&mut self, v: u32, n: u32) {
for i in (0..n).rev() {
self.write_bool((v >> i) & 1, 128);
}
}
pub fn write_tree(&mut self, tree: &[i8], probs: &[u8], symbol: i32) {
let mut path: Vec<(usize, u32)> = Vec::new();
let found = find_tree_path(tree, 0, symbol, &mut path);
debug_assert!(found, "vp9 write_tree: symbol {symbol} not in tree");
for (node, bit) in path {
self.write_bool(bit, probs[node >> 1]);
}
}
pub fn finish(mut self) -> Vec<u8> {
for _ in 0..32 {
self.write_bool(0, 128);
}
self.out
}
}
impl Default for BoolEncoder {
fn default() -> BoolEncoder {
BoolEncoder::new()
}
}
pub(crate) fn find_tree_path(
tree: &[i8],
node: usize,
symbol: i32,
path: &mut Vec<(usize, u32)>,
) -> bool {
for bit in 0..2u32 {
let next = tree[node + bit as usize];
path.push((node, bit));
if next <= 0 {
if -(next as i32) == symbol {
return true;
}
} else if find_tree_path(tree, next as usize, symbol, path) {
return true;
}
path.pop();
}
false
}
#[derive(Default)]
pub struct BitWriter {
out: Vec<u8>,
nbits: usize,
}
impl BitWriter {
pub fn new() -> BitWriter {
BitWriter::default()
}
pub fn bit_len(&self) -> usize {
self.nbits
}
pub fn put_bit(&mut self, bit: u32) {
if self.nbits % 8 == 0 {
self.out.push(0);
}
if bit & 1 != 0 {
let byte = self.nbits / 8;
self.out[byte] |= 1 << (7 - (self.nbits % 8));
}
self.nbits += 1;
}
pub fn put(&mut self, v: u32, n: u32) {
for i in (0..n).rev() {
self.put_bit((v >> i) & 1);
}
}
pub fn put_signed(&mut self, v: i32, n: u32) {
self.put(v.unsigned_abs(), n);
self.put_bit((v < 0) as u32);
}
pub fn into_bytes(self) -> Vec<u8> {
self.out
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bits::{BitReader, BoolDecoder};
fn xs(s: &mut u64) -> u64 {
*s ^= *s << 13;
*s ^= *s >> 7;
*s ^= *s << 17;
*s
}
#[test]
fn bool_roundtrip_random_streams() {
let mut s = 0x1234_5678_9abc_def0u64;
for _ in 0..300 {
let n = 50 + (xs(&mut s) % 500) as usize;
let pairs: Vec<(u32, u8)> = (0..n)
.map(|_| ((xs(&mut s) & 1) as u32, (1 + xs(&mut s) % 255) as u8))
.collect();
let mut enc = BoolEncoder::new();
for &(b, p) in &pairs {
enc.write_bool(b, p);
}
let bytes = enc.finish();
let mut dec = BoolDecoder::new(&bytes).unwrap();
for (i, &(b, p)) in pairs.iter().enumerate() {
assert_eq!(dec.read_bool(p), b, "mismatch at bool {i}");
}
}
}
#[test]
fn bool_roundtrip_every_prob() {
for prob in 1u8..=255 {
let bits: Vec<u32> = (0..96).map(|i| (i & 1) as u32).collect();
let mut enc = BoolEncoder::new();
for &b in &bits {
enc.write_bool(b, prob);
}
let bytes = enc.finish();
let mut dec = BoolDecoder::new(&bytes).unwrap();
for &b in &bits {
assert_eq!(dec.read_bool(prob), b, "prob {prob}");
}
}
}
#[test]
fn write_literal_roundtrips() {
let mut s = 0xdead_beef_0bad_f00du64;
let mut enc = BoolEncoder::new();
let mut vals = Vec::new();
for _ in 0..1000 {
let n = 1 + (xs(&mut s) % 16) as u32;
let v = (xs(&mut s) as u32) & ((1u32 << n) - 1);
enc.write_literal(v, n);
vals.push((v, n));
}
let bytes = enc.finish();
let mut dec = BoolDecoder::new(&bytes).unwrap();
for (v, n) in vals {
assert_eq!(dec.literal(n), v);
}
}
#[test]
fn write_tree_roundtrips_partition_shape() {
const PARTITION_TREE: [i8; 6] = [0, 2, -1, 4, -2, -3];
let probs = [100u8, 60, 200];
let mut s = 0x99_44_22_11u64;
let mut enc = BoolEncoder::new();
let mut syms = Vec::new();
for _ in 0..2000 {
let sym = (xs(&mut s) % 4) as i32;
enc.write_tree(&PARTITION_TREE, &probs, sym);
syms.push(sym);
}
let bytes = enc.finish();
let mut dec = BoolDecoder::new(&bytes).unwrap();
for sym in syms {
assert_eq!(
crate::token::read_tree(&mut dec, &PARTITION_TREE, &probs),
sym
);
}
}
#[test]
fn bitwriter_roundtrips_through_bitreader() {
let mut s = 0x5a5a_a5a5u64;
let mut w = BitWriter::new();
let mut fields: Vec<(u32, u32)> = Vec::new();
for _ in 0..500 {
let n = 1 + (xs(&mut s) % 24) as u32;
let v = (xs(&mut s) as u32) & ((1u64 << n) - 1) as u32;
w.put(v, n);
fields.push((v, n));
}
let bytes = w.into_bytes();
let mut r = BitReader::new(&bytes);
for (v, n) in fields {
assert_eq!(r.f(n).unwrap(), v);
}
}
#[test]
fn bitwriter_signed_roundtrips() {
let mut w = BitWriter::new();
let cases = [0i32, 1, -1, 7, -7, 31, -31, 100, -100];
for &v in &cases {
w.put_signed(v, 8);
}
let bytes = w.into_bytes();
let mut r = BitReader::new(&bytes);
for &v in &cases {
assert_eq!(r.s(8).unwrap(), v);
}
}
}