use crate::error::{MjpegError as Error, Result};
#[derive(Clone, Copy, Debug)]
pub struct QeEntry {
pub qe: u16,
pub nlps: u8,
pub nmps: u8,
pub switch: u8,
}
const fn e(qe: u16, nlps: u8, nmps: u8, switch: u8) -> QeEntry {
QeEntry {
qe,
nlps,
nmps,
switch,
}
}
pub const QE_TABLE: [QeEntry; 113] = [
e(0x5A1D, 1, 1, 1), e(0x2586, 14, 2, 0), e(0x1114, 16, 3, 0), e(0x080B, 18, 4, 0), e(0x03D8, 20, 5, 0), e(0x01DA, 23, 6, 0), e(0x00E5, 25, 7, 0), e(0x006F, 28, 8, 0), e(0x0036, 30, 9, 0), e(0x001A, 33, 10, 0), e(0x000D, 35, 11, 0), e(0x0006, 9, 12, 0), e(0x0003, 10, 13, 0), e(0x0001, 12, 13, 0), e(0x5A7F, 15, 15, 1), e(0x3F25, 36, 16, 0), e(0x2CF2, 38, 17, 0), e(0x207C, 39, 18, 0), e(0x17B9, 40, 19, 0), e(0x1182, 42, 20, 0), e(0x0CEF, 43, 21, 0), e(0x09A1, 45, 22, 0), e(0x072F, 46, 23, 0), e(0x055C, 48, 24, 0), e(0x0406, 49, 25, 0), e(0x0303, 51, 26, 0), e(0x0240, 52, 27, 0), e(0x01B1, 54, 28, 0), e(0x0144, 56, 29, 0), e(0x00F5, 57, 30, 0), e(0x00B7, 59, 31, 0), e(0x008A, 60, 32, 0), e(0x0068, 62, 33, 0), e(0x004E, 63, 34, 0), e(0x003B, 32, 35, 0), e(0x002C, 33, 9, 0), e(0x5AE1, 37, 37, 1), e(0x484C, 64, 38, 0), e(0x3A0D, 65, 39, 0), e(0x2EF1, 67, 40, 0), e(0x261F, 68, 41, 0), e(0x1F33, 69, 42, 0), e(0x19A8, 70, 43, 0), e(0x1518, 72, 44, 0), e(0x1177, 73, 45, 0), e(0x0E74, 74, 46, 0), e(0x0BFB, 75, 47, 0), e(0x09F8, 77, 48, 0), e(0x0861, 78, 49, 0), e(0x0706, 79, 50, 0), e(0x05CD, 48, 51, 0), e(0x04DE, 50, 52, 0), e(0x040F, 50, 53, 0), e(0x0363, 51, 54, 0), e(0x02D4, 52, 55, 0), e(0x025C, 53, 56, 0), e(0x01F8, 54, 57, 0), e(0x01A4, 55, 58, 0), e(0x0160, 56, 59, 0), e(0x0125, 57, 60, 0), e(0x00F6, 58, 61, 0), e(0x00CB, 59, 62, 0), e(0x00AB, 61, 63, 0), e(0x008F, 61, 32, 0), e(0x5B12, 65, 65, 1), e(0x4D04, 80, 66, 0), e(0x412C, 81, 67, 0), e(0x37D8, 82, 68, 0), e(0x2FE8, 83, 69, 0), e(0x293C, 84, 70, 0), e(0x2379, 86, 71, 0), e(0x1EDF, 87, 72, 0), e(0x1AA9, 87, 73, 0), e(0x174E, 72, 74, 0), e(0x1424, 72, 75, 0), e(0x119C, 74, 76, 0), e(0x0F6B, 74, 77, 0), e(0x0D51, 75, 78, 0), e(0x0BB6, 77, 79, 0), e(0x0A40, 77, 48, 0), e(0x5832, 80, 81, 1), e(0x4D1C, 88, 82, 0), e(0x438E, 89, 83, 0), e(0x3BDD, 90, 84, 0), e(0x34EE, 91, 85, 0), e(0x2EAE, 92, 86, 0), e(0x299A, 93, 87, 0), e(0x2516, 86, 71, 0), e(0x5570, 88, 89, 1), e(0x4CA9, 95, 90, 0), e(0x44D9, 96, 91, 0), e(0x3E22, 97, 92, 0), e(0x3824, 99, 93, 0), e(0x32B4, 99, 94, 0), e(0x2E17, 93, 86, 0), e(0x56A8, 95, 96, 1), e(0x4F46, 101, 97, 0), e(0x47E5, 102, 98, 0), e(0x41CF, 103, 99, 0), e(0x3C3D, 104, 100, 0), e(0x375E, 99, 93, 0), e(0x5231, 105, 102, 0), e(0x4C0F, 106, 103, 0), e(0x4639, 107, 104, 0), e(0x415E, 103, 99, 0), e(0x5627, 105, 106, 1), e(0x50E7, 108, 107, 0), e(0x4B85, 109, 103, 0), e(0x5597, 110, 109, 0), e(0x504F, 111, 107, 0), e(0x5A10, 110, 111, 1), e(0x5522, 112, 109, 0), e(0x59EB, 112, 111, 1), ];
#[derive(Clone, Copy, Debug, Default)]
pub struct Context {
pub idx: u8,
pub mps: u8,
}
pub struct ByteSource<'a> {
buf: &'a [u8],
pos: usize,
pub seen_marker: Option<u8>,
}
impl<'a> ByteSource<'a> {
pub fn new(buf: &'a [u8]) -> Self {
Self {
buf,
pos: 0,
seen_marker: None,
}
}
pub fn next_byte(&mut self) -> u8 {
if self.seen_marker.is_some() {
return 0;
}
if self.pos >= self.buf.len() {
self.seen_marker = Some(0);
return 0;
}
let b = self.buf[self.pos];
self.pos += 1;
if b == 0xFF {
while self.pos < self.buf.len() && self.buf[self.pos] == 0xFF {
self.pos += 1;
}
if self.pos >= self.buf.len() {
self.seen_marker = Some(0);
return 0;
}
let nxt = self.buf[self.pos];
self.pos += 1;
if nxt == 0x00 {
return 0xFF;
}
self.seen_marker = Some(nxt);
return 0;
}
b
}
}
pub struct ArithDecoder<'a> {
pub src: ByteSource<'a>,
pub a: u32,
pub c: u32,
pub ct: i32,
}
impl<'a> ArithDecoder<'a> {
pub fn new(scan: &'a [u8]) -> Self {
let mut s = ByteSource::new(scan);
let b0 = s.next_byte() as u32;
let b1 = s.next_byte() as u32;
let c = (b0 << 24) | (b1 << 16);
Self {
src: s,
a: 0,
c,
ct: 0,
}
}
pub fn restart(&mut self) {
let b0 = self.src.next_byte() as u32;
let b1 = self.src.next_byte() as u32;
self.c = (b0 << 24) | (b1 << 16);
self.a = 0;
self.ct = 0;
}
pub fn reset_with_source(&mut self, scan: &'a [u8]) {
self.src = ByteSource::new(scan);
let b0 = self.src.next_byte() as u32;
let b1 = self.src.next_byte() as u32;
self.c = (b0 << 24) | (b1 << 16);
self.a = 0;
self.ct = 0;
}
fn renorm_d(&mut self) {
loop {
if self.ct == 0 {
let b = self.src.next_byte() as u32;
self.c = self.c.wrapping_add(b << 8);
self.ct = 8;
}
self.a = (self.a << 1) & 0xFFFF;
self.c <<= 1;
self.ct -= 1;
if self.a >= 0x8000 {
break;
}
}
}
pub fn decode(&mut self, ctx: &mut Context) -> u8 {
let entry = QE_TABLE[ctx.idx as usize];
let qe = entry.qe as u32;
self.a = self.a.wrapping_sub(qe) & 0xFFFF;
let cx = (self.c >> 16) & 0xFFFF;
if cx < self.a {
if self.a < 0x8000 {
let d = self.cond_mps_exchange(ctx);
self.renorm_d();
d
} else {
ctx.mps
}
} else {
let d = self.cond_lps_exchange(ctx);
self.renorm_d();
d
}
}
fn cond_lps_exchange(&mut self, ctx: &mut Context) -> u8 {
let entry = QE_TABLE[ctx.idx as usize];
let qe = entry.qe as u32;
let cx = (self.c >> 16) & 0xFFFF;
let new_cx = cx.wrapping_sub(self.a) & 0xFFFF;
self.c = (self.c & 0xFFFF) | (new_cx << 16);
let was_a = self.a;
self.a = qe;
let d;
if was_a < qe {
d = ctx.mps;
ctx.idx = entry.nmps;
} else {
d = 1 - ctx.mps;
if entry.switch == 1 {
ctx.mps ^= 1;
}
ctx.idx = entry.nlps;
}
d
}
fn cond_mps_exchange(&mut self, ctx: &mut Context) -> u8 {
let entry = QE_TABLE[ctx.idx as usize];
let qe = entry.qe as u32;
let d;
if self.a < qe {
d = 1 - ctx.mps;
if entry.switch == 1 {
ctx.mps ^= 1;
}
ctx.idx = entry.nlps;
} else {
d = ctx.mps;
ctx.idx = entry.nmps;
}
d
}
pub fn marker(&self) -> Option<u8> {
self.src.seen_marker
}
}
pub struct ArithEncoder {
out: Vec<u8>,
a: u32,
c: u32,
ct: i32,
st: u32,
}
impl ArithEncoder {
pub fn new() -> Self {
Self {
out: Vec::new(),
a: 0x10000,
c: 0,
ct: 11,
st: 0,
}
}
pub fn code_bit(&mut self, ctx: &mut Context, d: u8) {
let entry = QE_TABLE[ctx.idx as usize];
let qe = entry.qe as u32;
if d == ctx.mps {
self.a -= qe;
if self.a < 0x8000 {
if self.a < qe {
self.c += self.a;
self.a = qe;
}
ctx.idx = entry.nmps;
self.renorm_e();
}
} else {
self.a -= qe;
if self.a >= qe {
self.c += self.a;
self.a = qe;
}
if entry.switch == 1 {
ctx.mps ^= 1;
}
ctx.idx = entry.nlps;
self.renorm_e();
}
}
fn renorm_e(&mut self) {
loop {
self.a <<= 1;
self.c <<= 1;
self.ct -= 1;
if self.ct == 0 {
self.byte_out();
self.ct = 8;
}
if self.a >= 0x8000 {
break;
}
}
}
fn byte_out(&mut self) {
let t = self.c >> 19;
if t > 0xFF {
if let Some(last) = self.out.last_mut() {
*last = last.wrapping_add(1);
if *last == 0xFF {
self.out.push(0);
}
}
for _ in 0..self.st {
self.out.push(0);
}
self.st = 0;
self.out.push((t & 0xFF) as u8);
} else if t == 0xFF {
self.st += 1;
} else {
for _ in 0..self.st {
self.out.push(0xFF);
self.out.push(0);
}
self.st = 0;
self.out.push(t as u8);
}
self.c &= 0x7FFFF;
}
pub fn finish(mut self) -> Vec<u8> {
let mut t = self.c.wrapping_add(self.a - 1) & 0xFFFF_0000;
if t < self.c {
t += 0x8000;
}
self.c = t;
self.c <<= self.ct as u32;
self.byte_out();
self.c <<= 8;
self.byte_out();
for _ in 0..self.st {
self.out.push(0xFF);
self.out.push(0);
}
self.st = 0;
while self.out.last() == Some(&0) {
self.out.pop();
}
if self.out.last() == Some(&0xFF) {
self.out.push(0);
}
self.out
}
}
impl Default for ArithEncoder {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct DcStats {
pub bins: [Context; 49],
pub l: u8,
pub u: u8,
pub prev_diff: i32,
pub pred: i32,
}
impl DcStats {
pub fn new() -> Self {
Self {
bins: [Context::default(); 49],
l: 0,
u: 1,
prev_diff: 0,
pred: 0,
}
}
pub fn reset(&mut self) {
for b in self.bins.iter_mut() {
*b = Context::default();
}
self.prev_diff = 0;
self.pred = 0;
}
pub fn restart_reset(&mut self) {
for b in self.bins.iter_mut() {
*b = Context::default();
}
self.prev_diff = 0;
self.pred = 0;
}
pub fn dc_context(&self) -> usize {
let da = self.prev_diff;
let lower = if self.l == 0 {
0
} else {
1i32 << (self.l - 1) as i32
};
let upper = 1i32 << self.u as i32;
let abs = da.unsigned_abs() as i32;
if abs <= lower {
0
} else if abs <= upper {
if da > 0 {
4
} else {
8
}
} else if da > 0 {
12
} else {
16
}
}
}
impl Default for DcStats {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct AcStats {
pub bins: [Context; 245],
pub kx: u8,
}
impl AcStats {
pub fn new() -> Self {
Self {
bins: [Context::default(); 245],
kx: 5,
}
}
pub fn reset(&mut self) {
for b in self.bins.iter_mut() {
*b = Context::default();
}
}
pub fn restart_reset(&mut self) {
self.reset();
}
}
impl Default for AcStats {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct AcRefineStats {
pub bins: [Context; 189],
}
impl AcRefineStats {
pub fn new() -> Self {
Self {
bins: [Context::default(); 189],
}
}
pub fn reset(&mut self) {
for b in self.bins.iter_mut() {
*b = Context::default();
}
}
pub fn restart_reset(&mut self) {
self.reset();
}
}
impl Default for AcRefineStats {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub struct LosslessStats {
pub bins: [Context; 158],
pub l: u8,
pub u: u8,
}
impl LosslessStats {
pub fn new() -> Self {
Self {
bins: [Context::default(); 158],
l: 0,
u: 1,
}
}
pub fn reset(&mut self) {
for b in self.bins.iter_mut() {
*b = Context::default();
}
}
pub fn classify(&self, d: i32) -> usize {
let lower = if self.l == 0 {
0
} else {
1i32 << (self.l - 1) as i32
};
let upper = 1i32 << self.u as i32;
let abs = d.unsigned_abs() as i32;
if abs <= lower {
0
} else if abs <= upper {
if d > 0 {
1
} else {
2
}
} else if d > 0 {
3
} else {
4
}
}
fn s0(&self, da: i32, db: i32) -> usize {
20 * self.classify(da) + 4 * self.classify(db)
}
fn x1(&self, db: i32) -> usize {
if self.classify(db) <= 2 {
100
} else {
129
}
}
}
impl Default for LosslessStats {
fn default() -> Self {
Self::new()
}
}
pub fn decode_fixed_bit(d: &mut ArithDecoder<'_>) -> u8 {
let mut ctx = Context { idx: 0, mps: 0 };
d.decode(&mut ctx)
}
fn decode_magnitude(
d: &mut ArithDecoder<'_>,
bins: &mut [Context],
sx_first: usize,
x1_base: usize,
is_dc: bool,
ac_ctx_low: bool,
) -> Result<i32> {
let mut s = sx_first;
let mut m: i32 = 1;
let mut category: u32 = 0;
let d0 = d.decode(&mut bins[s]);
if d0 != 0 {
m = 2;
s = x1_base;
category = 1;
let d1 = d.decode(&mut bins[s]);
if d1 != 0 {
m = 4;
s = if is_dc {
x1_base + 1 } else if ac_ctx_low {
189
} else {
217
};
category = 2;
loop {
let dx = d.decode(&mut bins[s]);
if dx == 0 {
break;
}
m <<= 1;
s += 1;
category += 1;
if m == 0 || category > 15 {
return Err(Error::invalid("arith: magnitude category > 15"));
}
}
}
}
let mut sz: i32 = 0;
if category >= 2 {
let m_bin_base = s + 14;
let mut bit = m >> 1;
sz = bit;
bit >>= 1;
while bit != 0 {
let b = d.decode(&mut bins[m_bin_base]);
if b != 0 {
sz |= bit;
}
bit >>= 1;
}
} else if category == 1 {
sz = 1;
}
Ok(sz)
}
pub fn decode_dc_diff(d: &mut ArithDecoder<'_>, dc: &mut DcStats) -> Result<i32> {
let s0 = dc.dc_context();
let zero = d.decode(&mut dc.bins[s0]);
if zero == 0 {
dc.prev_diff = 0;
return Ok(0);
}
let sign = d.decode(&mut dc.bins[s0 + 1]);
let sx_first = if sign == 0 { s0 + 2 } else { s0 + 3 };
let mag = decode_magnitude(d, &mut dc.bins, sx_first, 20, true, false)?;
let v = mag + 1;
let signed = if sign != 0 { -v } else { v };
dc.prev_diff = signed;
Ok(signed)
}
pub fn decode_ac(
d: &mut ArithDecoder<'_>,
ac: &mut AcStats,
coefs: &mut [i32; 64],
ss: usize,
se: usize,
) -> Result<()> {
use crate::jpeg::zigzag::ZIGZAG;
let mut k = ss;
loop {
let se_bin = 3 * (k - 1);
let eob = d.decode(&mut ac.bins[se_bin]);
if eob != 0 {
return Ok(());
}
loop {
let s0 = 3 * (k - 1) + 1;
let zero = d.decode(&mut ac.bins[s0]);
if zero != 0 {
break;
}
k += 1;
if k > se {
return Err(Error::invalid("arith AC: run past Se"));
}
}
let sign = decode_fixed_bit(d);
let sx_first = 3 * (k - 1) + 2;
let ac_low = (k as u8) <= ac.kx;
let mag = decode_magnitude(d, &mut ac.bins, sx_first, sx_first, false, ac_low)?;
let v = mag + 1;
let signed = if sign != 0 { -v } else { v };
coefs[ZIGZAG[k]] = signed;
if k == se {
return Ok(());
}
k += 1;
}
}
pub fn decode_ac_refine(
d: &mut ArithDecoder<'_>,
st: &mut AcRefineStats,
coefs: &mut [i32; 64],
ss: usize,
se: usize,
al: u8,
) -> Result<()> {
use crate::jpeg::zigzag::ZIGZAG;
if ss == 0 || se > 63 || ss > se {
return Err(Error::invalid("arith AC refine: invalid band"));
}
let p1: i32 = 1 << al;
let mut eobx = ss;
for k in ss..=se {
if coefs[ZIGZAG[k]] != 0 {
eobx = k + 1;
}
}
let mut k = ss;
loop {
if k >= eobx {
let se_bin = 3 * (k - 1);
if d.decode(&mut st.bins[se_bin]) != 0 {
return Ok(());
}
}
loop {
let pos = ZIGZAG[k];
if coefs[pos] != 0 {
let t = d.decode(&mut st.bins[3 * (k - 1) + 2]);
if t != 0 {
if coefs[pos] >= 0 {
coefs[pos] += p1;
} else {
coefs[pos] -= p1;
}
}
break;
}
if d.decode(&mut st.bins[3 * (k - 1) + 1]) != 0 {
let sign = decode_fixed_bit(d);
coefs[pos] = if sign != 0 { -p1 } else { p1 };
break;
}
k += 1;
if k > se {
return Err(Error::invalid("arith AC refine: run past Se"));
}
}
if k == se {
return Ok(());
}
k += 1;
}
}
pub fn decode_lossless_diff(
d: &mut ArithDecoder<'_>,
st: &mut LosslessStats,
da: i32,
db: i32,
) -> Result<i32> {
let s0 = st.s0(da, db);
let zero = d.decode(&mut st.bins[s0]);
if zero == 0 {
return Ok(0);
}
let sign = d.decode(&mut st.bins[s0 + 1]);
let sx_first = s0 + 2 + sign as usize;
let x1 = st.x1(db);
let mag = decode_magnitude(d, &mut st.bins, sx_first, x1, true, false)?;
let v = mag + 1;
Ok(if sign != 0 { -v } else { v })
}
pub fn encode_lossless_diff(
e: &mut ArithEncoder,
st: &mut LosslessStats,
da: i32,
db: i32,
v: i32,
) -> Result<()> {
let s0 = st.s0(da, db);
if v == 0 {
e.code_bit(&mut st.bins[s0], 0);
return Ok(());
}
e.code_bit(&mut st.bins[s0], 1);
let sign = u8::from(v < 0);
e.code_bit(&mut st.bins[s0 + 1], sign);
let sx_first = s0 + 2 + sign as usize;
let sz = v.unsigned_abs() - 1;
if sz > 32767 {
return Err(Error::invalid("arith lossless: |diff| > 32768"));
}
let x1 = st.x1(db);
encode_magnitude(e, &mut st.bins, sx_first, x1, sz);
Ok(())
}
pub(crate) fn encode_magnitude(
e: &mut ArithEncoder,
bins: &mut [Context],
sx_first: usize,
x1: usize,
sz: u32,
) {
if sz == 0 {
e.code_bit(&mut bins[sx_first], 0);
return;
}
e.code_bit(&mut bins[sx_first], 1);
if sz < 2 {
e.code_bit(&mut bins[x1], 0);
return;
}
e.code_bit(&mut bins[x1], 1);
let mut m: u32 = 4;
let mut s = x1 + 1; while sz >= m {
e.code_bit(&mut bins[s], 1);
m <<= 1;
s += 1;
}
e.code_bit(&mut bins[s], 0);
let m_bin = s + 14;
let mut bit = m >> 2;
while bit != 0 {
e.code_bit(&mut bins[m_bin], u8::from(sz & bit != 0));
bit >>= 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
const K4_ENCODED: [u8; 32] = [
0x65, 0x5B, 0x51, 0x44, 0xF7, 0x96, 0x9D, 0x51, 0x78, 0x55, 0xBF, 0xFF, 0x00, 0xFC, 0x51,
0x84, 0xC7, 0xCE, 0xF9, 0x39, 0x00, 0x28, 0x7D, 0x46, 0x70, 0x8E, 0xCB, 0xC0, 0xF6, 0xFF,
0xD9, 0x00,
];
const K4_PLAINTEXT: [u8; 32] = [
0x00, 0x02, 0x00, 0x51, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x52, 0x87, 0x2A, 0xAA, 0xAA, 0xAA,
0xAA, 0x82, 0xC0, 0x20, 0x00, 0xFC, 0xD7, 0x9E, 0xF6, 0x74, 0xEA, 0xAB, 0xF7, 0x69, 0x7E,
0xE7, 0x4C,
];
#[test]
fn k4_arith_roundtrip_decode() {
let scan = &K4_ENCODED[..29];
let mut d = ArithDecoder::new(scan);
let mut ctx = Context::default();
let mut decoded = vec![0u8; 32];
for byte_i in 0..32 {
let mut byte = 0u8;
for _ in 0..8 {
let b = d.decode(&mut ctx);
byte = (byte << 1) | b;
}
decoded[byte_i] = byte;
}
assert_eq!(
decoded, K4_PLAINTEXT,
"K.4 arithmetic decode did not reproduce the source plaintext"
);
}
#[test]
fn qe_table_initial_state() {
assert_eq!(QE_TABLE[0].qe, 0x5A1D);
assert_eq!(QE_TABLE[0].nlps, 1);
assert_eq!(QE_TABLE[0].nmps, 1);
assert_eq!(QE_TABLE[0].switch, 1);
assert_eq!(QE_TABLE.len(), 113);
}
#[test]
fn k4_arith_roundtrip_encode() {
let mut e = ArithEncoder::new();
let mut ctx = Context::default();
for &byte in K4_PLAINTEXT.iter() {
for bit in (0..8).rev() {
e.code_bit(&mut ctx, (byte >> bit) & 1);
}
}
let out = e.finish();
assert_eq!(
out,
&K4_ENCODED[..29],
"K.4 arithmetic encode did not reproduce the spec's compressed sequence"
);
}
#[test]
fn arith_encode_decode_roundtrip_multi_context() {
let mut s = 0x1234_5678u32;
let mut next = move || {
s ^= s << 13;
s ^= s >> 17;
s ^= s << 5;
s
};
const N: usize = 4096;
const NCTX: usize = 7;
let mut bits = Vec::with_capacity(N);
let mut ctx_ids = Vec::with_capacity(N);
for _ in 0..N {
let r = next();
bits.push(u8::from((r & 0x7) == 0));
ctx_ids.push(((r >> 8) as usize) % NCTX);
}
let mut e = ArithEncoder::new();
let mut ectx = [Context::default(); NCTX];
for i in 0..N {
e.code_bit(&mut ectx[ctx_ids[i]], bits[i]);
}
let coded = e.finish();
let mut d = ArithDecoder::new(&coded);
let mut dctx = [Context::default(); NCTX];
for i in 0..N {
assert_eq!(
d.decode(&mut dctx[ctx_ids[i]]),
bits[i],
"decision {i} mismatched"
);
}
}
#[test]
fn lossless_diff_roundtrip() {
for (l, u) in [(0u8, 1u8), (2, 5), (0, 15)] {
let diffs: Vec<i32> = vec![
0, 1, -1, 2, -2, 3, 0, 0, 17, -300, 4095, -4096, 32767, -32768, 0, 5, 12345,
-12345, 1, 0, -1, 255, -256, 32767, -32768, 8, 0,
];
let mut est = LosslessStats::new();
est.l = l;
est.u = u;
let mut e = ArithEncoder::new();
let mut da = 0i32;
for (i, &v) in diffs.iter().enumerate() {
let db = if i >= 5 { diffs[i - 5] } else { 0 };
encode_lossless_diff(&mut e, &mut est, da, db, v).unwrap();
da = v;
}
let coded = e.finish();
let mut dst = LosslessStats::new();
dst.l = l;
dst.u = u;
let mut d = ArithDecoder::new(&coded);
let mut da = 0i32;
for (i, &v) in diffs.iter().enumerate() {
let db = if i >= 5 { diffs[i - 5] } else { 0 };
let got = decode_lossless_diff(&mut d, &mut dst, da, db).unwrap();
assert_eq!(got, v, "diff {i} mismatched at L={l} U={u}");
da = v;
}
}
}
#[test]
fn lossless_context_bases() {
let st = LosslessStats::new(); assert_eq!(st.classify(0), 0);
assert_eq!(st.classify(1), 1);
assert_eq!(st.classify(2), 1);
assert_eq!(st.classify(-1), 2);
assert_eq!(st.classify(-2), 2);
assert_eq!(st.classify(3), 3);
assert_eq!(st.classify(-3), 4);
assert_eq!(st.s0(0, 0), 0);
assert_eq!(st.s0(0, -100), 16);
assert_eq!(st.s0(-100, 0), 80);
assert_eq!(st.s0(-100, -100), 96);
assert_eq!(st.x1(2), 100);
assert_eq!(st.x1(-2), 100);
assert_eq!(st.x1(3), 129);
assert_eq!(st.x1(-3), 129);
let mut st = LosslessStats::new();
st.l = 3;
st.u = 5;
assert_eq!(st.classify(4), 0);
assert_eq!(st.classify(5), 1);
assert_eq!(st.classify(32), 1);
assert_eq!(st.classify(33), 3);
assert_eq!(st.classify(-33), 4);
}
#[test]
fn byte_source_unstuff() {
let buf = [0xFF, 0x00, 0x42, 0xFF, 0xD9];
let mut s = ByteSource::new(&buf);
assert_eq!(s.next_byte(), 0xFF);
assert_eq!(s.next_byte(), 0x42);
assert_eq!(s.next_byte(), 0); assert_eq!(s.seen_marker, Some(0xD9));
assert_eq!(s.next_byte(), 0); }
}