use crate::ps::{Sps, TileLayout};
pub const PRED_NONE: u8 = 0;
pub const PRED_INTRA: u8 = 1;
pub const PRED_INTER: u8 = 2;
pub const PRED_SKIP: u8 = 3;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct SaoParams {
pub type_idx: u8,
pub aux: u8,
pub offset: [i16; 4],
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Motion {
pub mv: [[i16; 2]; 2],
pub ref_idx: [i8; 2],
pub pred_flags: u8,
pub ref_poc: [i32; 2],
pub ref_lt: u8,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct CtbFilterParams {
pub deblock_disabled: bool,
pub beta_offset_div2: i8,
pub tc_offset_div2: i8,
pub lf_across_slices: bool,
pub cb_qp_offset: i8,
pub cr_qp_offset: i8,
pub sao_luma: bool,
pub sao_chroma: bool,
}
pub struct PicState {
pub width: usize,
pub height: usize,
pub w4: usize,
pub h4: usize,
pub log2_ctb: usize,
pub ctb_w: usize,
pub ctb_h: usize,
pub zs: std::sync::Arc<[u32]>,
pub slice_addr: Vec<i32>,
pub ctb_slice: Vec<u16>,
pub tile_id: std::sync::Arc<[u32]>,
pub pred_mode: Vec<u8>,
pub intra_mode: Vec<u8>,
pub qp_y: Vec<i8>,
pub ct_depth: Vec<u8>,
pub edges: Vec<u8>,
pub nz: Vec<u8>,
pub filter_bypass: Vec<u8>,
pub motion: Vec<Motion>,
pub sao: Vec<[SaoParams; 3]>,
pub ctb_filter: Vec<CtbFilterParams>,
}
#[derive(Clone, Copy)]
pub struct AvailAt {
zs: u32,
slice: i32,
tile: u32,
}
pub struct SeqTables {
pub zs: std::sync::Arc<[u32]>,
pub tile_id: std::sync::Arc<[u32]>,
key: (usize, usize, usize, usize, Vec<u32>, Vec<u32>),
}
impl SeqTables {
pub fn build(sps: &Sps, tiles: &TileLayout) -> SeqTables {
let w4 = (sps.width as usize).div_ceil(4);
let h4 = (sps.height as usize).div_ceil(4);
let log2_ctb = sps.log2_ctb_size as usize;
let ctb_w = sps.pic_width_in_ctbs as usize;
let ctb_h = sps.pic_height_in_ctbs as usize;
let nctb = ctb_w * ctb_h;
let mut zs = vec![0u32; w4 * h4];
let shift = log2_ctb - 2;
for y in 0..h4 {
for x in 0..w4 {
let ctb_rs = ctb_w * (y >> shift) + (x >> shift);
let mut v = tiles.rs_to_ts[ctb_rs] << (shift * 2);
for i in 0..shift {
let m = 1usize << i;
if m & x != 0 {
v += (m * m) as u32;
}
if m & y != 0 {
v += (2 * m * m) as u32;
}
}
zs[y * w4 + x] = v;
}
}
let mut tile_id = vec![0u32; nctb];
for (rs, t) in tile_id.iter_mut().enumerate() {
*t = tiles.tile_id[tiles.rs_to_ts[rs] as usize];
}
SeqTables {
zs: zs.into(),
tile_id: tile_id.into(),
key: (w4, h4, log2_ctb, ctb_w, tiles.rs_to_ts.clone(), tiles.tile_id.clone()),
}
}
pub fn matches(&self, sps: &Sps, tiles: &TileLayout) -> bool {
self.key.0 == (sps.width as usize).div_ceil(4)
&& self.key.1 == (sps.height as usize).div_ceil(4)
&& self.key.2 == sps.log2_ctb_size as usize
&& self.key.3 == sps.pic_width_in_ctbs as usize
&& self.key.4 == tiles.rs_to_ts
&& self.key.5 == tiles.tile_id
}
}
impl PicState {
pub fn new(sps: &Sps, tiles: &TileLayout) -> Self {
Self::with_tables(sps, &SeqTables::build(sps, tiles))
}
pub fn with_tables(sps: &Sps, t: &SeqTables) -> Self {
let width = sps.width as usize;
let height = sps.height as usize;
let w4 = width.div_ceil(4);
let h4 = height.div_ceil(4);
let log2_ctb = sps.log2_ctb_size as usize;
let ctb_w = sps.pic_width_in_ctbs as usize;
let ctb_h = sps.pic_height_in_ctbs as usize;
let n4 = w4 * h4;
let nctb = ctb_w * ctb_h;
let (zs, tile_id) = (std::sync::Arc::clone(&t.zs), std::sync::Arc::clone(&t.tile_id));
PicState {
width,
height,
w4,
h4,
log2_ctb,
ctb_w,
ctb_h,
zs,
slice_addr: vec![-1; nctb],
ctb_slice: vec![0; nctb],
tile_id,
pred_mode: vec![PRED_NONE; n4],
intra_mode: vec![1; n4],
qp_y: vec![0; n4],
ct_depth: vec![0; n4],
edges: vec![0; n4],
nz: vec![0; n4],
filter_bypass: vec![0; n4],
motion: vec![Motion::default(); n4],
sao: vec![[SaoParams::default(); 3]; nctb],
ctb_filter: vec![CtbFilterParams::default(); nctb],
}
}
#[inline]
pub fn idx4(&self, x: usize, y: usize) -> usize {
(y >> 2) * self.w4 + (x >> 2)
}
#[inline]
pub fn ctb_of(&self, x: usize, y: usize) -> usize {
(y >> self.log2_ctb) * self.ctb_w + (x >> self.log2_ctb)
}
#[inline]
pub fn avail_at(&self, xc: i32, yc: i32) -> AvailAt {
let (xc, yc) = (xc as usize, yc as usize);
let cc = self.ctb_of(xc, yc);
AvailAt {
zs: self.zs[self.idx4(xc, yc)],
slice: self.slice_addr[cc],
tile: self.tile_id[cc],
}
}
#[inline]
pub fn avail_n_idx(&self, a: &AvailAt, xn: i32, yn: i32) -> Option<usize> {
if xn < 0 || yn < 0 || xn >= self.width as i32 || yn >= self.height as i32 {
return None;
}
let i = self.idx4(xn as usize, yn as usize);
if self.zs[i] > a.zs {
return None;
}
let cn = self.ctb_of(xn as usize, yn as usize);
if self.slice_addr[cn] < 0 || self.slice_addr[cn] != a.slice || self.tile_id[cn] != a.tile {
return None;
}
if self.pred_mode[i] == PRED_NONE {
return None;
}
Some(i)
}
#[inline]
pub fn avail_n(&self, a: &AvailAt, xn: i32, yn: i32) -> bool {
if xn < 0 || yn < 0 || xn >= self.width as i32 || yn >= self.height as i32 {
return false;
}
let i = self.idx4(xn as usize, yn as usize);
if self.zs[i] > a.zs {
return false;
}
let cn = self.ctb_of(xn as usize, yn as usize);
if self.slice_addr[cn] < 0 || self.slice_addr[cn] != a.slice || self.tile_id[cn] != a.tile {
return false;
}
self.pred_mode[i] != PRED_NONE
}
#[inline]
pub fn available(&self, xc: i32, yc: i32, xn: i32, yn: i32) -> bool {
self.avail_n(&self.avail_at(xc, yc), xn, yn)
}
pub fn fill4<T: Copy>(map: &mut [T], w4: usize, x: usize, y: usize, w: usize, h: usize, v: T) {
let x0 = x >> 2;
let y0 = y >> 2;
let x1 = (x + w).div_ceil(4);
let y1 = (y + h).div_ceil(4);
for yy in y0..y1 {
let r = yy * w4;
map[r + x0..r + x1].fill(v);
}
}
}