use std::{
iter::FusedIterator,
marker::PhantomData,
ops::{Index, IndexMut},
slice,
};
use v_frame::{
pixel::Pixel,
plane::{Plane, PlaneConfig, PlaneOffset},
};
use super::block::{BLOCK_TO_PLANE_SHIFT, BlockOffset};
#[derive(Debug)]
pub struct PlaneRegion<'a, T: Pixel> {
data: *const T, pub plane_cfg: &'a PlaneConfig,
rect: Rect,
phantom: PhantomData<&'a T>,
}
#[derive(Debug)]
pub struct PlaneRegionMut<'a, T: Pixel> {
data: *mut T, pub plane_cfg: &'a PlaneConfig,
rect: Rect,
phantom: PhantomData<&'a mut T>,
}
macro_rules! plane_region_common {
($name:ident, $as_ptr:ident $(,$opt_mut:tt)?) => {
impl<'a, T: Pixel> $name<'a, T> {
#[cold]
pub fn empty(plane_cfg : &'a PlaneConfig) -> Self {
return Self {
data: std::ptr::null_mut::<T>(),
plane_cfg,
rect: Rect::default(),
phantom: PhantomData,
}
}
pub fn from_slice(data: &'a $($opt_mut)? [T], cfg: &'a PlaneConfig, rect: Rect) -> Self {
if cfg.width == 0 || cfg.height == 0 {
return Self::empty(&cfg);
}
assert!(rect.x >= -(cfg.xorigin as isize));
assert!(rect.y >= -(cfg.yorigin as isize));
assert!(cfg.xorigin as isize + rect.x + rect.width as isize <= cfg.stride as isize);
assert!(cfg.yorigin as isize + rect.y + rect.height as isize <= cfg.alloc_height as isize);
unsafe { Self::from_slice_unsafe(data, cfg, rect)}
}
unsafe fn from_slice_unsafe(data: &'a $($opt_mut)? [T], cfg: &'a PlaneConfig, rect: Rect) -> Self {
let origin = (cfg.yorigin as isize + rect.y) * cfg.stride as isize + cfg.xorigin as isize + rect.x;
Self {
data: data.$as_ptr().offset(origin),
plane_cfg: cfg,
rect,
phantom: PhantomData,
}
}
pub fn new(plane: &'a $($opt_mut)? Plane<T>, rect: Rect) -> Self {
Self::from_slice(& $($opt_mut)? plane.data, &plane.cfg, rect)
}
#[allow(dead_code)]
pub fn new_from_plane(plane: &'a $($opt_mut)? Plane<T>) -> Self {
let rect = Rect {
x: 0,
y: 0,
width: plane.cfg.stride - plane.cfg.xorigin,
height: plane.cfg.alloc_height - plane.cfg.yorigin,
};
unsafe { Self::from_slice_unsafe(& $($opt_mut)? plane.data, &plane.cfg, rect) }
}
#[allow(dead_code)]
pub fn data_ptr(&self) -> *const T {
self.data
}
pub fn rect(&self) -> &Rect {
&self.rect
}
#[allow(dead_code)]
pub fn rows_iter(&self) -> PlaneRegionRowsIter<'_, T> {
PlaneRegionRowsIter {
data: self.data,
stride: self.plane_cfg.stride,
width: self.rect.width,
remaining: self.rect.height,
phantom: PhantomData,
}
}
#[allow(dead_code)]
pub fn vert_windows(&self, h: usize) -> VertWindows<'_, T> {
VertWindows {
data: self.data,
plane_cfg: self.plane_cfg,
remaining: (self.rect.height as isize - h as isize + 1).max(0) as usize,
output_rect: Rect {
x: self.rect.x,
y: self.rect.y,
width: self.rect.width,
height: h
}
}
}
#[allow(dead_code)]
pub fn horz_windows(&self, w: usize) -> HorzWindows<'_, T> {
HorzWindows {
data: self.data,
plane_cfg: self.plane_cfg,
remaining: (self.rect.width as isize - w as isize + 1).max(0) as usize,
output_rect: Rect {
x: self.rect.x,
y: self.rect.y,
width: w,
height: self.rect.height
}
}
}
#[allow(dead_code)]
pub fn subregion(&self, area: Area) -> PlaneRegion<'_, T> {
if self.data.is_null() {
return PlaneRegion::empty(&self.plane_cfg);
}
let rect = area.to_rect(
self.plane_cfg.xdec,
self.plane_cfg.ydec,
self.rect.width,
self.rect.height,
);
assert!(rect.x >= 0 && rect.x as usize <= self.rect.width);
assert!(rect.y >= 0 && rect.y as usize <= self.rect.height);
let data = unsafe {
self.data.add(rect.y as usize * self.plane_cfg.stride + rect.x as usize)
};
let absolute_rect = Rect {
x: self.rect.x + rect.x,
y: self.rect.y + rect.y,
width: rect.width,
height: rect.height,
};
PlaneRegion {
data,
plane_cfg: &self.plane_cfg,
rect: absolute_rect,
phantom: PhantomData,
}
}
}
unsafe impl<T: Pixel> Send for $name<'_, T> {}
unsafe impl<T: Pixel> Sync for $name<'_, T> {}
impl<T: Pixel> Index<usize> for $name<'_, T> {
type Output = [T];
fn index(&self, index: usize) -> &Self::Output {
assert!(index < self.rect.height);
unsafe {
let ptr = self.data.add(index * self.plane_cfg.stride);
slice::from_raw_parts(ptr, self.rect.width)
}
}
}
}
}
plane_region_common!(PlaneRegion, as_ptr);
plane_region_common!(PlaneRegionMut, as_mut_ptr, mut);
impl<T: Pixel> PlaneRegionMut<'_, T> {
pub fn data_ptr_mut(&mut self) -> *mut T {
self.data
}
pub fn rows_iter_mut(&mut self) -> PlaneRegionRowsIterMut<'_, T> {
PlaneRegionRowsIterMut {
data: self.data,
stride: self.plane_cfg.stride,
width: self.rect.width,
remaining: self.rect.height,
phantom: PhantomData,
}
}
pub fn as_const(&self) -> PlaneRegion<'_, T> {
PlaneRegion {
data: self.data,
plane_cfg: self.plane_cfg,
rect: self.rect,
phantom: PhantomData,
}
}
}
impl<T: Pixel> IndexMut<usize> for PlaneRegionMut<'_, T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
assert!(index < self.rect.height);
unsafe {
let ptr = self.data.add(index * self.plane_cfg.stride);
slice::from_raw_parts_mut(ptr, self.rect.width)
}
}
}
pub struct PlaneRegionRowsIter<'a, T: Pixel> {
data: *const T,
stride: usize,
width: usize,
remaining: usize,
phantom: PhantomData<&'a T>,
}
impl<'a, T: Pixel> Iterator for PlaneRegionRowsIter<'a, T> {
type Item = &'a [T];
fn next(&mut self) -> Option<Self::Item> {
if self.remaining > 0 {
let row = unsafe {
let ptr = self.data;
self.data = self.data.add(self.stride);
slice::from_raw_parts(ptr, self.width)
};
self.remaining -= 1;
Some(row)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
pub struct PlaneRegionRowsIterMut<'a, T: Pixel> {
data: *mut T,
stride: usize,
width: usize,
remaining: usize,
phantom: PhantomData<&'a mut T>,
}
impl<'a, T: Pixel> Iterator for PlaneRegionRowsIterMut<'a, T> {
type Item = &'a mut [T];
fn next(&mut self) -> Option<Self::Item> {
if self.remaining > 0 {
let row = unsafe {
let ptr = self.data;
self.data = self.data.add(self.stride);
slice::from_raw_parts_mut(ptr, self.width)
};
self.remaining -= 1;
Some(row)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
}
impl<T: Pixel> ExactSizeIterator for PlaneRegionRowsIter<'_, T> {
}
impl<T: Pixel> FusedIterator for PlaneRegionRowsIter<'_, T> {
}
impl<T: Pixel> ExactSizeIterator for PlaneRegionRowsIterMut<'_, T> {
}
impl<T: Pixel> FusedIterator for PlaneRegionRowsIterMut<'_, T> {
}
pub struct VertWindows<'a, T: Pixel> {
data: *const T,
plane_cfg: &'a PlaneConfig,
remaining: usize,
output_rect: Rect,
}
pub struct HorzWindows<'a, T: Pixel> {
data: *const T,
plane_cfg: &'a PlaneConfig,
remaining: usize,
output_rect: Rect,
}
impl<'a, T: Pixel> Iterator for VertWindows<'a, T> {
type Item = PlaneRegion<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
self.nth(0)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if self.remaining > n {
self.data = unsafe { self.data.add(self.plane_cfg.stride * n) };
self.output_rect.y += n as isize;
let output = PlaneRegion {
data: self.data,
plane_cfg: self.plane_cfg,
rect: self.output_rect,
phantom: PhantomData,
};
self.data = unsafe { self.data.add(self.plane_cfg.stride) };
self.output_rect.y += 1;
self.remaining -= n + 1;
Some(output)
} else {
None
}
}
}
impl<'a, T: Pixel> Iterator for HorzWindows<'a, T> {
type Item = PlaneRegion<'a, T>;
fn next(&mut self) -> Option<Self::Item> {
self.nth(0)
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, Some(self.remaining))
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
if self.remaining > n {
self.data = unsafe { self.data.add(n) };
self.output_rect.x += n as isize;
let output = PlaneRegion {
data: self.data,
plane_cfg: self.plane_cfg,
rect: self.output_rect,
phantom: PhantomData,
};
self.data = unsafe { self.data.add(1) };
self.output_rect.x += 1;
self.remaining -= n + 1;
Some(output)
} else {
None
}
}
}
impl<T: Pixel> ExactSizeIterator for VertWindows<'_, T> {
}
impl<T: Pixel> FusedIterator for VertWindows<'_, T> {
}
impl<T: Pixel> ExactSizeIterator for HorzWindows<'_, T> {
}
impl<T: Pixel> FusedIterator for HorzWindows<'_, T> {
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Rect {
pub x: isize,
pub y: isize,
pub width: usize,
pub height: usize,
}
#[derive(Debug, Clone, Copy)]
pub enum Area {
Rect(Rect),
StartingAt { x: isize, y: isize },
BlockStartingAt { bo: BlockOffset },
}
impl Area {
pub const fn to_rect(
self,
xdec: usize,
ydec: usize,
parent_width: usize,
parent_height: usize,
) -> Rect {
match self {
Area::Rect(rect) => rect,
Area::StartingAt { x, y } => Rect {
x,
y,
width: (parent_width as isize - x) as usize,
height: (parent_height as isize - y) as usize,
},
Area::BlockStartingAt { bo } => {
let x = (bo.x >> xdec << BLOCK_TO_PLANE_SHIFT) as isize;
let y = (bo.y >> ydec << BLOCK_TO_PLANE_SHIFT) as isize;
Rect {
x,
y,
width: (parent_width as isize - x) as usize,
height: (parent_height as isize - y) as usize,
}
}
}
}
}
pub trait AsRegion<T: Pixel> {
fn as_region(&self) -> PlaneRegion<'_, T>;
fn region(&self, area: Area) -> PlaneRegion<'_, T>;
fn region_mut(&mut self, area: Area) -> PlaneRegionMut<'_, T>;
}
impl<T: Pixel> AsRegion<T> for Plane<T> {
fn as_region(&self) -> PlaneRegion<'_, T> {
PlaneRegion::new_from_plane(self)
}
fn region(&self, area: Area) -> PlaneRegion<'_, T> {
let rect = area.to_rect(
self.cfg.xdec,
self.cfg.ydec,
self.cfg.stride - self.cfg.xorigin,
self.cfg.alloc_height - self.cfg.yorigin,
);
PlaneRegion::new(self, rect)
}
fn region_mut(&mut self, area: Area) -> PlaneRegionMut<'_, T> {
let rect = area.to_rect(
self.cfg.xdec,
self.cfg.ydec,
self.cfg.stride - self.cfg.xorigin,
self.cfg.alloc_height - self.cfg.yorigin,
);
PlaneRegionMut::new(self, rect)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PlaneBlockOffset(pub BlockOffset);
impl PlaneBlockOffset {
pub const fn to_luma_plane_offset(self) -> PlaneOffset {
self.0.to_luma_plane_offset()
}
}