use std::ops::{Deref, DerefMut};
use arrayvec::ArrayVec;
use crate::{PixelFormat, PlaneDims, MAX_PLANES};
pub trait Frame {
fn format(&self) -> PixelFormat;
fn pixel_dimensions(&self) -> (usize, usize);
fn planes(&self) -> ArrayVec<FramePlaneRef, MAX_PLANES>;
}
pub trait FrameMut: Frame {
fn planes_mut(&mut self) -> ArrayVec<FramePlaneMut, MAX_PLANES>;
}
pub struct FramePlaneRef<'a> {
data: &'a [u8],
stride: usize,
}
impl<'p> FramePlaneRef<'p> {
#[inline]
pub fn new(data: &'p mut [u8], stride: usize) -> Self {
Self { data, stride }
}
#[inline]
pub fn stride(&self) -> usize {
self.stride
}
#[inline]
pub fn as_slice(&self) -> &'p [u8] {
self.data
}
}
impl Deref for FramePlaneRef<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.data
}
}
impl PartialEq for FramePlaneRef<'_> {
fn eq(&self, other: &Self) -> bool {
self.stride == other.stride && self.data == other.data
}
}
impl Eq for FramePlaneRef<'_> {}
pub struct FramePlaneMut<'a> {
data: &'a mut [u8],
stride: usize,
}
impl<'a> FramePlaneMut<'a> {
#[inline]
pub fn new(data: &'a mut [u8], stride: usize) -> Self {
Self { data, stride }
}
#[inline]
pub fn stride(&self) -> usize {
self.stride
}
#[inline]
pub fn into_slice(self) -> &'a mut [u8] {
self.data
}
}
impl Deref for FramePlaneMut<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.data
}
}
impl DerefMut for FramePlaneMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data
}
}
impl PartialEq for FramePlaneMut<'_> {
fn eq(&self, other: &Self) -> bool {
self.stride == other.stride && self.data == other.data
}
}
impl Eq for FramePlaneMut<'_> {}
#[derive(Clone)]
pub struct ConsecutiveFrame<S> {
format: PixelFormat,
width: usize,
height: usize,
dims: [PlaneDims; MAX_PLANES],
storage: S,
}
impl<S> ConsecutiveFrame<S> {
fn total_size(&self) -> usize {
let mut total_size = 0usize;
for dims in self.dims.iter() {
total_size = total_size
.checked_add(dims.stride * dims.rows)
.expect("total frame size should not overflow");
}
total_size
}
}
impl ConsecutiveFrame<()> {
pub fn new(format: PixelFormat, width: usize, height: usize) -> Self {
let mut dims = [PlaneDims::default(); MAX_PLANES];
for (dim, min) in dims.iter_mut().zip(format.min_plane_dims(width, height)) {
*dim = min;
}
ConsecutiveFrame {
format,
width,
height,
dims,
storage: (),
}
}
pub fn with_padding(mut self, padding: usize) -> Self {
let padding_mask = padding
.checked_next_power_of_two()
.expect("padding should not overflow")
- 1;
for dims in self.dims.iter_mut() {
dims.stride = dims
.stride
.checked_add(padding_mask)
.expect("plane stride with padding should not overflow")
& !padding_mask;
}
self
}
pub fn new_vec(self) -> ConsecutiveFrame<Vec<u8>> {
ConsecutiveFrame {
format: self.format,
width: self.width,
height: self.height,
dims: self.dims,
storage: vec![0; self.total_size()],
}
}
pub fn with_storage<S: Deref<Target = [u8]>>(self, storage: S) -> ConsecutiveFrame<S> {
assert!(
storage.len() >= self.total_size(),
"storage={} < total_size={}",
storage.len(),
self.total_size()
);
ConsecutiveFrame {
format: self.format,
width: self.width,
height: self.height,
dims: self.dims,
storage,
}
}
}
impl<S> ConsecutiveFrame<S> {
pub fn inner(&self) -> &S {
&self.storage
}
pub fn inner_mut(&mut self) -> &mut S {
&mut self.storage
}
pub fn into_inner(self) -> S {
self.storage
}
}
impl<S: Deref<Target = [u8]>> Frame for ConsecutiveFrame<S> {
#[inline]
fn format(&self) -> PixelFormat {
self.format
}
#[inline]
fn pixel_dimensions(&self) -> (usize, usize) {
(self.width, self.height)
}
fn planes(&self) -> ArrayVec<FramePlaneRef, MAX_PLANES> {
let mut storage = self.storage.deref();
let mut planes = ArrayVec::new();
for dims in self.dims.iter().take(self.format.num_planes()) {
let (data, rest) = storage.split_at(dims.stride * dims.rows);
storage = rest;
planes.push(FramePlaneRef {
data,
stride: dims.stride,
});
}
planes
}
}
impl<S: DerefMut<Target = [u8]>> FrameMut for ConsecutiveFrame<S> {
fn planes_mut(&mut self) -> ArrayVec<FramePlaneMut, MAX_PLANES> {
let mut storage = self.storage.deref_mut();
let mut planes = ArrayVec::new();
for dims in self.dims.iter().take(self.format.num_planes()) {
let (data, rest) = storage.split_at_mut(dims.stride * dims.rows);
storage = rest;
planes.push(FramePlaneMut {
data,
stride: dims.stride,
});
}
planes
}
}