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