camera_stream/platform/macos/
frame.rs1use core::ffi::c_void;
2
3use objc2_core_video::{
4 CVPixelBuffer, CVPixelBufferGetBaseAddress, CVPixelBufferGetBaseAddressOfPlane,
5 CVPixelBufferGetBytesPerRow, CVPixelBufferGetBytesPerRowOfPlane, CVPixelBufferGetHeight,
6 CVPixelBufferGetHeightOfPlane, CVPixelBufferGetPixelFormatType, CVPixelBufferGetPlaneCount,
7 CVPixelBufferGetWidth,
8};
9
10use crate::frame::{Frame, Plane, Timestamp};
11use crate::platform::macos::device::fourcc_to_pixel_format;
12use crate::types::{PixelFormat, Size};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub struct MacosTimestamp {
21 pub value: i64,
23 pub timescale: i32,
25 pub flags: u32,
27 pub epoch: i64,
29}
30
31impl Timestamp for MacosTimestamp {
32 fn as_secs_f64(&self) -> f64 {
33 if self.timescale > 0 {
34 self.value as f64 / self.timescale as f64
35 } else {
36 0.0
37 }
38 }
39}
40
41pub struct MacosFrame<'a> {
44 pixel_buffer: &'a CVPixelBuffer,
45 planes: Vec<Plane<'a>>,
46 pixel_format: PixelFormat,
47 size: Size,
48 timestamp: MacosTimestamp,
49}
50
51impl<'a> MacosFrame<'a> {
52 pub(crate) unsafe fn from_locked_pixel_buffer(
55 pixel_buffer: &'a CVPixelBuffer,
56 timestamp: MacosTimestamp,
57 ) -> Self {
58 let width = CVPixelBufferGetWidth(pixel_buffer);
59 let height = CVPixelBufferGetHeight(pixel_buffer);
60 let fourcc = CVPixelBufferGetPixelFormatType(pixel_buffer);
61 let pixel_format = fourcc_to_pixel_format(fourcc).unwrap_or(PixelFormat::Nv12);
62 let size = Size {
63 width: width as u32,
64 height: height as u32,
65 };
66
67 let plane_count = CVPixelBufferGetPlaneCount(pixel_buffer);
68 let planes = if plane_count == 0 {
69 let base = CVPixelBufferGetBaseAddress(pixel_buffer);
71 let bytes_per_row = CVPixelBufferGetBytesPerRow(pixel_buffer);
72 if base.is_null() {
73 vec![]
74 } else {
75 let len = bytes_per_row * height;
76 let data = unsafe { core::slice::from_raw_parts(base as *const u8, len) };
77 vec![Plane {
78 data,
79 bytes_per_row,
80 }]
81 }
82 } else {
83 (0..plane_count)
84 .filter_map(|i| {
85 let base = CVPixelBufferGetBaseAddressOfPlane(pixel_buffer, i);
86 if base.is_null() {
87 return None;
88 }
89 let bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixel_buffer, i);
90 let h = CVPixelBufferGetHeightOfPlane(pixel_buffer, i);
91 let len = bytes_per_row * h;
92 let data = unsafe { core::slice::from_raw_parts(base as *const u8, len) };
93 Some(Plane {
94 data,
95 bytes_per_row,
96 })
97 })
98 .collect()
99 };
100
101 MacosFrame {
102 pixel_buffer,
103 planes,
104 pixel_format,
105 size,
106 timestamp,
107 }
108 }
109
110 pub fn pixel_buffer_ptr(&self) -> *const c_void {
112 self.pixel_buffer as *const CVPixelBuffer as *const c_void
113 }
114}
115
116impl<'a> Frame for MacosFrame<'a> {
117 type Timestamp = MacosTimestamp;
118
119 fn pixel_format(&self) -> PixelFormat {
120 self.pixel_format
121 }
122
123 fn size(&self) -> Size {
124 self.size
125 }
126
127 fn planes(&self) -> &[Plane<'_>] {
128 &self.planes
129 }
130
131 fn timestamp(&self) -> MacosTimestamp {
132 self.timestamp
133 }
134}