use super::bitreader::{BitReader, BitReaderError};
#[derive(Debug, thiserror::Error, PartialEq, Eq)]
pub enum EntropyError {
#[error("entropy decode: out of input")]
OutOfInput,
#[error("entropy decode: malformed codeword (unary prefix too long)")]
MalformedCodeword,
}
impl From<BitReaderError> for EntropyError {
fn from(_e: BitReaderError) -> Self {
Self::OutOfInput
}
}
pub fn decode_unsigned_codeword(reader: &mut BitReader<'_>, k: u32) -> Result<u32, EntropyError> {
let quotient = reader.count_leading_ones()?;
if quotient > 31 {
return Err(EntropyError::MalformedCodeword);
}
let remainder = if k > 0 { reader.read_bits(k)? } else { 0 };
Ok((quotient << k) | remainder)
}
pub fn decode_signed_codeword(reader: &mut BitReader<'_>, k: u32) -> Result<i32, EntropyError> {
let magnitude = decode_unsigned_codeword(reader, k)?;
if magnitude == 0 {
return Ok(0);
}
let sign = reader.read_bit()?;
let signed = if sign == 1 {
-(magnitude as i32)
} else {
magnitude as i32
};
Ok(signed)
}
#[must_use]
pub fn next_k_dc(prev_magnitude: u32) -> u32 {
const TABLE: [u8; 28] = [
0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
];
u32::from(TABLE[(prev_magnitude as usize).min(TABLE.len() - 1)])
}
#[must_use]
pub fn next_k_ac_level(prev_magnitude: u32) -> u32 {
const TABLE: [u8; 16] = [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7];
u32::from(TABLE[(prev_magnitude as usize).min(TABLE.len() - 1)])
}
#[must_use]
pub fn next_k_ac_run(prev_run: u32) -> u32 {
const TABLE: [u8; 16] = [0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7];
u32::from(TABLE[(prev_run as usize).min(TABLE.len() - 1)])
}
pub fn decode_block(
reader: &mut BitReader<'_>,
previous_dc: i32,
) -> Result<([i32; 64], i32), EntropyError> {
let mut coeffs = [0i32; 64];
let dc_delta = decode_signed_codeword(reader, next_k_dc(previous_dc.unsigned_abs()))?;
let dc = previous_dc.wrapping_add(dc_delta);
coeffs[0] = dc;
let mut k_run = 3u32;
let mut k_level = 1u32;
let mut pos = 1usize;
while pos < 64 {
let run = decode_unsigned_codeword(reader, k_run)?;
pos += run as usize;
if pos >= 64 {
break;
}
let level_mag = decode_unsigned_codeword(reader, k_level)? + 1;
let sign = reader.read_bit()?;
let level = if sign == 1 {
-(level_mag as i32)
} else {
level_mag as i32
};
coeffs[pos] = level;
k_run = next_k_ac_run(run);
k_level = next_k_ac_level(level_mag);
pos += 1;
}
Ok((coeffs, dc))
}
#[cfg(test)]
mod tests {
use super::*;
fn encode_codeword(q: u32, k: u32, r: u32) -> Vec<u8> {
let mut bits: Vec<u8> = Vec::new();
for _ in 0..q {
bits.push(1);
}
bits.push(0); for i in (0..k).rev() {
bits.push(((r >> i) & 1) as u8);
}
while bits.len() % 8 != 0 {
bits.push(0);
}
bits.chunks(8)
.map(|c| c.iter().fold(0u8, |acc, &b| (acc << 1) | b))
.collect()
}
#[test]
fn decode_unsigned_k_zero_is_pure_unary() {
let buf = encode_codeword(3, 0, 0);
let mut r = BitReader::new(&buf);
assert_eq!(decode_unsigned_codeword(&mut r, 0).unwrap(), 3);
}
#[test]
fn decode_unsigned_k_two_value_5() {
let buf = encode_codeword(1, 2, 1);
let mut r = BitReader::new(&buf);
assert_eq!(decode_unsigned_codeword(&mut r, 2).unwrap(), 5);
}
#[test]
fn decode_unsigned_k_three_value_zero() {
let buf = encode_codeword(0, 3, 0);
let mut r = BitReader::new(&buf);
assert_eq!(decode_unsigned_codeword(&mut r, 3).unwrap(), 0);
}
#[test]
fn decode_signed_zero_emits_no_sign_bit() {
let buf = encode_codeword(0, 2, 0); let mut r = BitReader::new(&buf);
assert_eq!(decode_signed_codeword(&mut r, 2).unwrap(), 0);
assert_eq!(r.bits_remaining(), 5);
}
#[test]
fn decode_signed_positive_then_sign_bit_zero() {
let mut bits = vec![1u8, 1, 1, 0, 0];
while bits.len() % 8 != 0 {
bits.push(0);
}
let byte: u8 = bits[0..8].iter().fold(0, |acc, &b| (acc << 1) | b);
let buf = vec![byte];
let mut r = BitReader::new(&buf);
assert_eq!(decode_signed_codeword(&mut r, 0).unwrap(), 3);
}
#[test]
fn decode_signed_negative() {
let bits = [1u8, 1, 1, 0, 1, 0, 0, 0];
let byte: u8 = bits.iter().fold(0, |acc, &b| (acc << 1) | b);
let buf = vec![byte];
let mut r = BitReader::new(&buf);
assert_eq!(decode_signed_codeword(&mut r, 0).unwrap(), -3);
}
#[test]
fn dc_k_adaptation_widens_for_big_magnitudes() {
assert_eq!(next_k_dc(0), 0);
assert_eq!(next_k_dc(1), 0);
assert_eq!(next_k_dc(2), 1);
assert_eq!(next_k_dc(10), 5);
assert_eq!(next_k_dc(1000), 7); }
#[test]
fn ac_level_k_adaptation_clamps() {
assert_eq!(next_k_ac_level(0), 0);
assert_eq!(next_k_ac_level(100), 7);
}
#[test]
fn ac_run_k_adaptation_clamps() {
assert_eq!(next_k_ac_run(0), 0);
assert_eq!(next_k_ac_run(100), 7);
}
#[test]
fn malformed_codeword_errors() {
let buf = [0xFFu8; 8];
let mut r = BitReader::new(&buf);
assert!(matches!(
decode_unsigned_codeword(&mut r, 0),
Err(EntropyError::MalformedCodeword) | Err(EntropyError::OutOfInput)
));
}
#[test]
fn out_of_input_propagates() {
let buf = [];
let mut r = BitReader::new(&buf);
assert_eq!(
decode_unsigned_codeword(&mut r, 0).unwrap_err(),
EntropyError::OutOfInput
);
}
}