#![deny(clippy::indexing_slicing)]
use crate::msac::{
rav1d_msac_decode_bool_bypass, rav1d_msac_decode_bools, rav1d_msac_decode_symbol_adapt4,
rav1d_msac_decode_symbol_adapt8, MsacContext,
};
pub const PALETTE_MAX_SIZE: usize = 8;
#[derive(Clone, Default)]
pub struct PaletteBlock {
pub n: usize,
pub colors: [u16; PALETTE_MAX_SIZE],
pub map: Vec<u8>,
pub w: usize,
pub h: usize,
}
thread_local! {
static PAL_ABOVE: std::cell::RefCell<Vec<(u8, [u16; PALETTE_MAX_SIZE])>> =
const { std::cell::RefCell::new(Vec::new()) };
static PAL_LEFT: std::cell::RefCell<Vec<(u8, [u16; PALETTE_MAX_SIZE])>> =
const { std::cell::RefCell::new(Vec::new()) };
}
pub fn pal_reset(iw4: usize, ih4: usize) {
PAL_ABOVE.with(|c| *c.borrow_mut() = vec![(0u8, [0u16; PALETTE_MAX_SIZE]); iw4 + 32]);
PAL_LEFT.with(|c| *c.borrow_mut() = vec![(0u8, [0u16; PALETTE_MAX_SIZE]); ih4 + 32]);
}
pub fn pal_splat(bx4: usize, by4: usize, bw4: usize, bh4: usize, n: usize, colors: &[u16; PALETTE_MAX_SIZE]) {
PAL_ABOVE.with(|c| {
let mut v = c.borrow_mut();
for x in bx4..(bx4 + bw4).min(v.len()) {
if let Some(c) = v.get_mut(x) { *c = (n as u8, *colors); }
}
});
PAL_LEFT.with(|c| {
let mut v = c.borrow_mut();
for y in by4..(by4 + bh4).min(v.len()) {
if let Some(c) = v.get_mut(y) { *c = (n as u8, *colors); }
}
});
}
pub fn palette_cache(bx4: usize, by4: usize, have_left: bool, have_top: bool) -> ([u16; 2 * PALETTE_MAX_SIZE], usize) {
let mut cache = [0u16; 2 * PALETTE_MAX_SIZE];
let above = if have_top && (by4 & 15) != 0 {
PAL_ABOVE.with(|c| c.borrow().get(bx4).copied().unwrap_or((0, [0; 8])))
} else {
(0, [0; 8])
};
let left = if have_left {
PAL_LEFT.with(|c| c.borrow().get(by4).copied().unwrap_or((0, [0; 8])))
} else {
(0, [0; 8])
};
let (mut an, acol) = (above.0 as usize, above.1);
let (mut ln, lcol) = (left.0 as usize, left.1);
let mut n = 0usize;
let (mut ai, mut li) = (0usize, 0usize);
while an > 0 && ln > 0 {
if let (Some(d), Some(&v)) = (cache.get_mut(n), acol.get(ai)) { *d = v; }
n += 1; ai += 1; an -= 1;
if let (Some(d), Some(&v)) = (cache.get_mut(n), lcol.get(li)) { *d = v; }
n += 1; li += 1; ln -= 1;
}
while an > 0 {
if let (Some(d), Some(&v)) = (cache.get_mut(n), acol.get(ai)) { *d = v; }
n += 1; ai += 1; an -= 1;
}
while ln > 0 {
if let (Some(d), Some(&v)) = (cache.get_mut(n), lcol.get(li)) { *d = v; }
n += 1; li += 1; ln -= 1;
}
(cache, n)
}
pub fn read_uniform(msac: &mut MsacContext, n: usize) -> usize {
let l = (usize::BITS - n.leading_zeros()) as u8; let m = (1usize << l) - n;
let v = rav1d_msac_decode_bools(msac, l - 1) as usize;
if v < m {
v
} else {
(v << 1) - m + rav1d_msac_decode_bool_bypass(msac) as usize
}
}
fn ceil_log2(x: i32) -> u8 {
if x < 2 {
0
} else {
(32 - (x - 1).leading_zeros()) as u8
}
}
pub fn read_palette_colors_y(
msac: &mut MsacContext,
bd_bits: u8,
n: usize,
bx4: usize,
by4: usize,
have_left: bool,
have_top: bool,
) -> [u16; PALETTE_MAX_SIZE] {
let (cache, n_cache) = palette_cache(bx4, by4, have_left, have_top);
let mut colors = [0u16; PALETTE_MAX_SIZE];
let mut idx = 0usize;
let mut i = 0usize;
while i < n_cache && idx < n {
if rav1d_msac_decode_bool_bypass(msac) {
if let (Some(d), Some(&v)) = (colors.get_mut(idx), cache.get(i)) { *d = v; }
idx += 1;
}
i += 1;
}
if idx < n {
if let Some(d) = colors.get_mut(idx) { *d = rav1d_msac_decode_bools(msac, bd_bits) as u16; }
idx += 1;
if idx < n {
let min_bits = bd_bits - 3;
let mut bits = min_bits + rav1d_msac_decode_bools(msac, 2) as u8;
let mut range = (1i32 << bd_bits) - colors.get(idx - 1).copied().unwrap_or(0) as i32 - 1;
while idx < n {
let delta = rav1d_msac_decode_bools(msac, bits) as i32 + 1;
let prev = colors.get(idx - 1).copied().unwrap_or(0) as i32;
let c = (prev + delta).clamp(0, (1 << bd_bits) - 1);
range -= c - prev;
if let Some(d) = colors.get_mut(idx) { *d = c as u16; }
bits = bits.min(ceil_log2(range));
idx += 1;
}
}
}
if let Some(sl) = colors.get_mut(..n) { sl.sort_unstable(); }
colors
}
pub fn color_index_ctx(map: &[u8], stride: usize, r: usize, c: usize) -> (usize, [u8; PALETTE_MAX_SIZE]) {
let mut order: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
let mut status = [false; PALETTE_MAX_SIZE];
let mut cnt = 0usize;
let mut swap = |order: &mut [u8; 8], status: &mut [bool; 8], cnt: &mut usize, switch_idx: usize, max_idx: u8| {
if let Some(d) = order.get_mut(switch_idx) { *d = max_idx; }
if let Some(d) = status.get_mut(max_idx as usize) { *d = true; }
*cnt += 1;
};
let ctx;
if r > 0 && c > 0 {
let g = |i: usize| map.get(i).copied().unwrap_or(0);
let n0 = g(r * stride + c - 1); let n1 = g((r - 1) * stride + c - 1); let n2 = g((r - 1) * stride + c); if n0 == n1 && n0 == n2 {
ctx = 4;
swap(&mut order, &mut status, &mut cnt, 0, n0);
} else if n0 == n2 {
ctx = 3;
swap(&mut order, &mut status, &mut cnt, 0, n0);
swap(&mut order, &mut status, &mut cnt, 1, n1);
} else if n0 == n1 {
ctx = 2;
swap(&mut order, &mut status, &mut cnt, 0, n0);
swap(&mut order, &mut status, &mut cnt, 1, n2);
} else if n1 == n2 {
ctx = 2;
swap(&mut order, &mut status, &mut cnt, 0, n2);
swap(&mut order, &mut status, &mut cnt, 1, n0);
} else {
ctx = 1;
swap(&mut order, &mut status, &mut cnt, 0, n0);
swap(&mut order, &mut status, &mut cnt, 1, n2);
swap(&mut order, &mut status, &mut cnt, 2, n1);
}
} else if c == 0 && r > 0 {
ctx = 0;
swap(&mut order, &mut status, &mut cnt, 0, map.get((r - 1) * stride + c).copied().unwrap_or(0));
} else {
ctx = 0;
swap(&mut order, &mut status, &mut cnt, 0, map.get(r * stride + c - 1).copied().unwrap_or(0));
}
let mut write_idx = cnt;
for read_idx in 0..PALETTE_MAX_SIZE {
if !status.get(read_idx).copied().unwrap_or(true) {
if let Some(d) = order.get_mut(write_idx) { *d = read_idx as u8; }
write_idx += 1;
}
}
(ctx, order)
}
#[allow(clippy::too_many_arguments)]
pub fn decode_color_map(
msac: &mut MsacContext,
cdf_identity: &mut [[u16; 4]; 4],
cdf_map: &mut [[[u16; 8]; 5]; 7],
n_colors: usize,
pw: usize,
ph: usize,
rows: usize,
cols: usize,
) -> Option<Vec<u8>> {
let mut map = vec![0u8; pw * ph];
let transverse_allowed = pw < 64 && ph < 64;
let direction = if transverse_allowed { rav1d_msac_decode_bool_bypass(msac) as usize } else { 0 };
let axis1_limit = if direction != 0 { rows } else { cols };
let axis2_limit = if direction != 0 { cols } else { rows };
let mut prev_identity = 0usize;
for ax2 in 0..axis2_limit {
let ctx = if ax2 == 0 { 3 } else { prev_identity };
let ctx = ctx.min(cdf_identity.len() - 1);
let flag = match cdf_identity.get_mut(ctx) {
Some(c) => rav1d_msac_decode_symbol_adapt4(msac, c, 2) as usize,
None => return None,
};
if flag == 2 && ax2 == 0 {
return None; }
for ax1 in 0..axis1_limit {
let (y, x) = if direction != 0 { (ax1, ax2) } else { (ax2, ax1) };
let dst = y * pw + x;
let g = |m: &Vec<u8>, i: usize| m.get(i).copied().unwrap_or(0);
let v = if flag == 2 {
if direction != 0 { g(&map, y * pw + x.wrapping_sub(1)) } else { g(&map, (y.wrapping_sub(1)) * pw + x) }
} else if flag == 1 && ax1 > 0 {
if direction != 0 { g(&map, (y.wrapping_sub(1)) * pw + x) } else { g(&map, y * pw + x.wrapping_sub(1)) }
} else if ax2 == 0 && ax1 == 0 {
read_uniform(msac, n_colors) as u8
} else {
let (cctx, order) = color_index_ctx(&map, pw, y, x);
let row = match cdf_map.get_mut(n_colors.wrapping_sub(2)).and_then(|r| r.get_mut(cctx)) {
Some(r) => r,
None => return None,
};
let idx = rav1d_msac_decode_symbol_adapt8(msac, row, (n_colors - 1) as u8) as usize;
order.get(idx).copied().unwrap_or(0)
};
if let Some(d) = map.get_mut(dst) { *d = v; }
}
prev_identity = flag;
}
if cols < pw {
for r in 0..rows {
let v = map.get(r * pw + cols - 1).copied().unwrap_or(0);
for c in cols..pw {
if let Some(d) = map.get_mut(r * pw + c) { *d = v; }
}
}
}
for r in rows..ph {
let (a, b) = map.split_at_mut(r * pw);
b[..pw].copy_from_slice(&a[(rows - 1) * pw..(rows - 1) * pw + pw]);
}
Some(map)
}