use std::num::NonZeroUsize;
use anyhow::Result;
use crate::{
analysis::MVAnalysisData,
fake::{block_data::FakeBlockData, plane_of_blocks::FakePlaneOfBlocks},
params::Subpel,
};
use semisafe::slice::get as semisafe_get;
use semisafe::slice::get_mut as semisafe_get_mut;
pub struct FakeGroupOfPlanes {
level_count: usize,
validity: bool,
planes: Vec<FakePlaneOfBlocks>,
}
impl FakeGroupOfPlanes {
#[must_use]
#[inline]
pub fn new(analysis_data: &MVAnalysisData) -> Self {
let blk_x1 = analysis_data.blk_x;
let blk_y1 = analysis_data.blk_y;
let width_b = unsafe {
NonZeroUsize::new_unchecked(analysis_data.blk_size_x.get() - analysis_data.overlap_x)
.saturating_mul(blk_x1)
.saturating_add(analysis_data.overlap_x)
};
let height_b = unsafe {
NonZeroUsize::new_unchecked(analysis_data.blk_size_y.get() - analysis_data.overlap_y)
.saturating_mul(blk_y1)
.saturating_add(analysis_data.overlap_y)
};
let mut planes = Vec::with_capacity(analysis_data.level_count);
planes.push(FakePlaneOfBlocks::new(
analysis_data.blk_size_x,
analysis_data.blk_size_y,
analysis_data.pel,
analysis_data.overlap_x,
analysis_data.overlap_y,
blk_x1,
blk_y1,
));
for i in 1..analysis_data.level_count {
let blk_x1 = unsafe {
NonZeroUsize::new_unchecked(
((width_b.get() >> i) - analysis_data.overlap_x)
/ (analysis_data.blk_size_x.get() - analysis_data.overlap_x),
)
};
let blk_y1 = unsafe {
NonZeroUsize::new_unchecked(
((height_b.get() >> i) - analysis_data.overlap_y)
/ (analysis_data.blk_size_y.get() - analysis_data.overlap_y),
)
};
planes.push(FakePlaneOfBlocks::new(
analysis_data.blk_size_x,
analysis_data.blk_size_y,
Subpel::Full,
analysis_data.overlap_x,
analysis_data.overlap_y,
blk_x1,
blk_y1,
));
}
Self {
level_count: analysis_data.level_count,
validity: false,
planes,
}
}
#[inline]
pub fn update(&mut self, vectors_data: &[u8]) -> Result<()> {
self.validity = Self::get_validity(vectors_data)?;
let mut offset = 2 * size_of::<i32>();
for i in (0..self.level_count).rev() {
semisafe_get_mut(&mut self.planes, i)
.update(semisafe_get(vectors_data, (offset + size_of::<i32>())..));
let size = i32::from_le_bytes(
semisafe_get(semisafe_get(vectors_data, offset..), ..size_of::<i32>())
.try_into()?,
);
offset += size as usize;
}
Ok(())
}
#[must_use]
#[inline]
pub fn get_block(&self, level: usize, blk: usize) -> &FakeBlockData {
semisafe_get(&self.planes, level).get_block(blk)
}
pub(crate) fn plane(&self, level: usize) -> &FakePlaneOfBlocks {
semisafe_get(&self.planes, level)
}
#[cfg(test)]
pub(crate) fn plane_mut(&mut self, level: usize) -> &mut FakePlaneOfBlocks {
semisafe_get_mut(&mut self.planes, level)
}
#[cfg(test)]
pub(crate) const fn set_validity(&mut self, validity: bool) {
self.validity = validity;
}
fn get_validity(vectors_data: &[u8]) -> Result<bool> {
let validity = i32::from_le_bytes(
semisafe_get(
semisafe_get(vectors_data, size_of::<i32>()..),
..size_of::<i32>(),
)
.try_into()?,
);
Ok(validity > 0)
}
#[must_use]
#[inline]
pub fn is_usable(&self, thscd1: u64, thscd2: u64) -> bool {
!self.is_scenechange(thscd1, thscd2) && self.is_valid()
}
fn is_scenechange(&self, thscd1: u64, thscd2: u64) -> bool {
semisafe_get(&self.planes, 0).is_scenechange(thscd1, thscd2)
}
pub(crate) const fn is_valid(&self) -> bool {
self.validity
}
}