Skip to main content

apple_cf/cv/
buffer.rs

1//! Core Video buffer/image-buffer wrappers.
2//!
3#![allow(clippy::missing_errors_doc)]
4
5//! ```rust
6//! use apple_cf::cf::{CFString, CFType};
7//! use apple_cf::cv::{CVAttachmentMode, CVBuffer, CVImageBuffer, CVPixelBuffer};
8//!
9//! let pixel_buffer = CVPixelBuffer::create(8, 8, 0x4247_5241).expect("pixel buffer");
10//! let buffer = CVBuffer::from_pixel_buffer(&pixel_buffer).expect("buffer");
11//! let key = CFString::new("com.doomfish.apple-cf.example");
12//! let value = CFString::new("value");
13//! buffer.set_attachment(&key, &value, CVAttachmentMode::ShouldPropagate);
14//! assert!(buffer.attachment(&key).is_some());
15//!
16//! let image = CVImageBuffer::from_pixel_buffer(&pixel_buffer).expect("image buffer");
17//! assert_eq!(image.encoded_size().width, 8.0);
18//! ```
19
20use super::CVPixelBuffer;
21use crate::cf::{AsCFType, CFDictionary, CFString, CFType};
22use std::ffi::c_void;
23use std::fmt;
24
25#[link(name = "CoreVideo", kind = "framework")]
26extern "C" {
27    fn CVBufferRetain(buffer: *mut c_void) -> *mut c_void;
28    fn CVBufferRelease(buffer: *mut c_void);
29    fn CVBufferSetAttachment(buffer: *mut c_void, key: *mut c_void, value: *mut c_void, mode: u32);
30    fn CVBufferCopyAttachment(
31        buffer: *mut c_void,
32        key: *mut c_void,
33        attachment_mode: *mut u32,
34    ) -> *mut c_void;
35    fn CVBufferCopyAttachments(buffer: *mut c_void, attachment_mode: u32) -> *mut c_void;
36    fn CVBufferRemoveAllAttachments(buffer: *mut c_void);
37
38    fn CVImageBufferGetEncodedSize(image_buffer: *mut c_void) -> CVImageSize;
39    fn CVImageBufferGetDisplaySize(image_buffer: *mut c_void) -> CVImageSize;
40    fn CVImageBufferGetCleanRect(image_buffer: *mut c_void) -> CVImageRect;
41}
42
43/// Attachment propagation mode.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45#[repr(u32)]
46pub enum CVAttachmentMode {
47    ShouldNotPropagate = 0,
48    ShouldPropagate = 1,
49}
50
51/// Size returned by `CVImageBuffer` accessors.
52#[repr(C)]
53#[derive(Debug, Clone, Copy, PartialEq)]
54pub struct CVImageSize {
55    pub width: f64,
56    pub height: f64,
57}
58
59/// Rectangle returned by `CVImageBufferGetCleanRect`.
60#[repr(C)]
61#[derive(Debug, Clone, Copy, PartialEq)]
62pub struct CVImageRect {
63    pub x: f64,
64    pub y: f64,
65    pub width: f64,
66    pub height: f64,
67}
68
69/// Generic `CVBufferRef` wrapper.
70pub struct CVBuffer(*mut c_void);
71
72impl CVBuffer {
73    /// Wraps a +1 retained `CVBufferRef` and returns `None` for null.
74    #[must_use]
75    pub fn from_raw(ptr: *mut c_void) -> Option<Self> {
76        if ptr.is_null() {
77            None
78        } else {
79            Some(Self(ptr))
80        }
81    }
82
83    /// Retains a +0 borrowed `CVBufferRef` and wraps the resulting +1 reference.
84    ///
85    /// # Safety
86    ///
87    /// `ptr` must be NULL or a valid `CVBufferRef`.
88    #[must_use]
89    pub unsafe fn from_raw_retained(ptr: *mut c_void) -> Option<Self> {
90        if ptr.is_null() {
91            None
92        } else {
93            let retained = unsafe { CVBufferRetain(ptr) };
94            Self::from_raw(retained)
95        }
96    }
97
98    /// Wrap a pixel buffer as a generic `CVBuffer`.
99    #[must_use]
100    pub fn from_pixel_buffer(pixel_buffer: &CVPixelBuffer) -> Option<Self> {
101        unsafe { Self::from_raw_retained(pixel_buffer.as_ptr()) }
102    }
103
104    /// Borrow the raw `CVBufferRef`.
105    #[must_use]
106    pub const fn as_ptr(&self) -> *mut c_void {
107        self.0
108    }
109
110    /// Attach a Core Foundation value to the buffer.
111    pub fn set_attachment(&self, key: &CFString, value: &dyn AsCFType, mode: CVAttachmentMode) {
112        unsafe { CVBufferSetAttachment(self.0, key.as_ptr(), value.as_ptr(), mode as u32) };
113    }
114
115    /// Copy an attachment value for `key`.
116    #[must_use]
117    pub fn attachment(&self, key: &CFString) -> Option<CFType> {
118        let mut attachment_mode = 0_u32;
119        let ptr = unsafe { CVBufferCopyAttachment(self.0, key.as_ptr(), &mut attachment_mode) };
120        CFType::from_raw(ptr)
121    }
122
123    /// Copy all attachments for the requested propagation mode.
124    #[must_use]
125    pub fn attachments(&self, mode: CVAttachmentMode) -> Option<CFDictionary> {
126        let ptr = unsafe { CVBufferCopyAttachments(self.0, mode as u32) };
127        CFDictionary::from_raw(ptr)
128    }
129
130    /// Remove all attachments.
131    pub fn remove_all_attachments(&self) {
132        unsafe { CVBufferRemoveAllAttachments(self.0) };
133    }
134}
135
136impl Clone for CVBuffer {
137    fn clone(&self) -> Self {
138        let retained = unsafe { CVBufferRetain(self.0) };
139        Self(retained)
140    }
141}
142
143impl Drop for CVBuffer {
144    fn drop(&mut self) {
145        unsafe { CVBufferRelease(self.0) };
146    }
147}
148
149impl PartialEq for CVBuffer {
150    fn eq(&self, other: &Self) -> bool {
151        self.0 == other.0
152    }
153}
154
155impl Eq for CVBuffer {}
156
157impl std::hash::Hash for CVBuffer {
158    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
159        self.0.hash(state);
160    }
161}
162
163impl fmt::Debug for CVBuffer {
164    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165        f.debug_struct("CVBuffer").field("ptr", &self.0).finish()
166    }
167}
168
169/// Generic `CVImageBufferRef` wrapper.
170pub struct CVImageBuffer(*mut c_void);
171
172impl CVImageBuffer {
173    /// Wraps a +1 retained `CVImageBufferRef` and returns `None` for null.
174    #[must_use]
175    pub fn from_raw(ptr: *mut c_void) -> Option<Self> {
176        if ptr.is_null() {
177            None
178        } else {
179            Some(Self(ptr))
180        }
181    }
182
183    /// Wrap a pixel buffer as a generic image buffer.
184    #[must_use]
185    pub fn from_pixel_buffer(pixel_buffer: &CVPixelBuffer) -> Option<Self> {
186        let retained = unsafe { CVBufferRetain(pixel_buffer.as_ptr()) };
187        Self::from_raw(retained)
188    }
189
190    /// Borrow the raw `CVImageBufferRef`.
191    #[must_use]
192    pub const fn as_ptr(&self) -> *mut c_void {
193        self.0
194    }
195
196    /// Encoded image size.
197    #[must_use]
198    pub fn encoded_size(&self) -> CVImageSize {
199        unsafe { CVImageBufferGetEncodedSize(self.0) }
200    }
201
202    /// Display size.
203    #[must_use]
204    pub fn display_size(&self) -> CVImageSize {
205        unsafe { CVImageBufferGetDisplaySize(self.0) }
206    }
207
208    /// Clean aperture rectangle.
209    #[must_use]
210    pub fn clean_rect(&self) -> CVImageRect {
211        unsafe { CVImageBufferGetCleanRect(self.0) }
212    }
213}
214
215impl Clone for CVImageBuffer {
216    fn clone(&self) -> Self {
217        let retained = unsafe { CVBufferRetain(self.0) };
218        Self(retained)
219    }
220}
221
222impl Drop for CVImageBuffer {
223    fn drop(&mut self) {
224        unsafe { CVBufferRelease(self.0) };
225    }
226}
227
228impl PartialEq for CVImageBuffer {
229    fn eq(&self, other: &Self) -> bool {
230        self.0 == other.0
231    }
232}
233
234impl Eq for CVImageBuffer {}
235
236impl std::hash::Hash for CVImageBuffer {
237    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
238        self.0.hash(state);
239    }
240}
241
242impl fmt::Debug for CVImageBuffer {
243    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244        f.debug_struct("CVImageBuffer")
245            .field("ptr", &self.0)
246            .field("encoded_size", &self.encoded_size())
247            .finish()
248    }
249}