#[cfg(feature = "nostd")]
use alloc::{sync::Arc, vec, vec::Vec};
#[cfg(not(feature = "nostd"))]
use std::{sync::Arc, vec::Vec};
#[derive(Clone)]
pub struct Frame {
buffer: Arc<Vec<u8>>,
width: u32,
height: u32,
timestamp: u32,
format: PixelFormat,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PixelFormat {
Rgba8,
Bgra8,
Rgb8,
}
impl Frame {
pub fn new(buffer: Vec<u8>, width: u32, height: u32, timestamp: u32) -> Self {
Self {
buffer: Arc::new(buffer),
width,
height,
timestamp,
format: PixelFormat::Rgba8,
}
}
pub fn from_rgba(buffer: Vec<u8>, width: u32, height: u32) -> Self {
Self::new(buffer, width, height, 0)
}
pub fn with_format(
buffer: Vec<u8>,
width: u32,
height: u32,
timestamp: u32,
format: PixelFormat,
) -> Self {
Self {
buffer: Arc::new(buffer),
width,
height,
timestamp,
format,
}
}
pub fn empty(width: u32, height: u32, timestamp: u32) -> Self {
let size = (width * height * 4) as usize;
Self::new(vec![0; size], width, height, timestamp)
}
pub fn with_timestamp(&self, timestamp: u32) -> Self {
Self {
buffer: Arc::clone(&self.buffer),
timestamp,
..*self
}
}
pub fn data(&self) -> &[u8] {
self.buffer.as_slice()
}
pub fn pixels(&self) -> &[u8] {
self.buffer.as_slice()
}
pub fn data_mut(&mut self) -> &mut [u8] {
Arc::make_mut(&mut self.buffer).as_mut_slice()
}
pub fn into_buffer(self) -> Vec<u8> {
Arc::try_unwrap(self.buffer).unwrap_or_else(|arc| (*arc).clone())
}
pub fn width(&self) -> u32 {
self.width
}
pub fn height(&self) -> u32 {
self.height
}
pub fn timestamp(&self) -> u32 {
self.timestamp
}
pub fn format(&self) -> PixelFormat {
self.format
}
pub fn bytes_per_pixel(&self) -> usize {
match self.format {
PixelFormat::Rgba8 | PixelFormat::Bgra8 => 4,
PixelFormat::Rgb8 => 3,
}
}
pub fn stride(&self) -> usize {
self.width as usize * self.bytes_per_pixel()
}
pub fn to_rgba(mut self) -> Self {
match self.format {
PixelFormat::Rgba8 => self,
PixelFormat::Bgra8 => {
for chunk in Arc::make_mut(&mut self.buffer).chunks_exact_mut(4) {
chunk.swap(0, 2);
}
self.format = PixelFormat::Rgba8;
self
}
PixelFormat::Rgb8 => {
let mut rgba = Vec::with_capacity((self.width * self.height * 4) as usize);
for chunk in self.buffer.chunks_exact(3) {
rgba.extend_from_slice(&[chunk[0], chunk[1], chunk[2], 255]);
}
self.buffer = Arc::new(rgba);
self.format = PixelFormat::Rgba8;
self
}
}
}
pub fn is_empty(&self) -> bool {
match self.format {
PixelFormat::Rgba8 | PixelFormat::Bgra8 => {
self.buffer.chunks_exact(4).all(|pixel| pixel[3] == 0)
}
PixelFormat::Rgb8 => false,
}
}
}