use objc2_core_video::{
CVPixelBuffer, CVPixelBufferGetBaseAddress, CVPixelBufferGetBaseAddressOfPlane,
CVPixelBufferGetBytesPerRow, CVPixelBufferGetBytesPerRowOfPlane, CVPixelBufferGetHeight,
CVPixelBufferGetHeightOfPlane, CVPixelBufferGetPixelFormatType, CVPixelBufferGetPlaneCount,
CVPixelBufferGetWidth,
};
use crate::frame::{Frame, Plane, Timestamp};
use crate::platform::macos::device::fourcc_to_pixel_format;
use crate::types::{PixelFormat, Size};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct MacosTimestamp {
pub value: i64,
pub timescale: i32,
pub flags: u32,
pub epoch: i64,
}
impl Timestamp for MacosTimestamp {
fn as_secs_f64(&self) -> f64 {
if self.timescale > 0 {
self.value as f64 / self.timescale as f64
} else {
0.0
}
}
}
pub struct MacosFrame<'a> {
pixel_buffer: &'a CVPixelBuffer,
planes: Vec<Plane<'a>>,
pixel_format: PixelFormat,
size: Size,
timestamp: MacosTimestamp,
}
impl<'a> MacosFrame<'a> {
pub(crate) unsafe fn from_locked_pixel_buffer(
pixel_buffer: &'a CVPixelBuffer,
timestamp: MacosTimestamp,
) -> Self {
let width = CVPixelBufferGetWidth(pixel_buffer);
let height = CVPixelBufferGetHeight(pixel_buffer);
let fourcc = CVPixelBufferGetPixelFormatType(pixel_buffer);
let pixel_format = fourcc_to_pixel_format(fourcc).unwrap_or(PixelFormat::Nv12);
let size = Size {
width: width as u32,
height: height as u32,
};
let plane_count = CVPixelBufferGetPlaneCount(pixel_buffer);
let planes = if plane_count == 0 {
let base = CVPixelBufferGetBaseAddress(pixel_buffer);
let bytes_per_row = CVPixelBufferGetBytesPerRow(pixel_buffer);
if base.is_null() {
vec![]
} else {
let len = bytes_per_row * height;
let data = unsafe { core::slice::from_raw_parts(base as *const u8, len) };
vec![Plane {
data,
bytes_per_row,
}]
}
} else {
(0..plane_count)
.filter_map(|i| {
let base = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer, i);
if base.is_null() {
return None;
}
let bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer, i);
let h = CVPixelBufferGetHeightOfPlane(pixel_buffer, i);
let len = bytes_per_row * h;
let data = unsafe { core::slice::from_raw_parts(base as *const u8, len) };
Some(Plane {
data,
bytes_per_row,
})
})
.collect()
};
MacosFrame {
pixel_buffer,
planes,
pixel_format,
size,
timestamp,
}
}
pub fn pixel_buffer_ref(&self) -> &CVPixelBuffer {
self.pixel_buffer
}
}
impl<'a> Frame for MacosFrame<'a> {
type Timestamp = MacosTimestamp;
fn pixel_format(&self) -> PixelFormat {
self.pixel_format
}
fn size(&self) -> Size {
self.size
}
fn planes(&self) -> &[Plane<'_>] {
&self.planes
}
fn timestamp(&self) -> MacosTimestamp {
self.timestamp
}
}