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    #[must_use]
74    pub fn from_raw(ptr: *mut c_void) -> Option<Self> {
75        if ptr.is_null() {
76            None
77        } else {
78            Some(Self(ptr))
79        }
80    }
81
82    /// Retain a borrowed Core Video buffer.
83    ///
84    /// # Safety
85    ///
86    /// `ptr` must be NULL or a valid `CVBufferRef`.
87    #[must_use]
88    pub unsafe fn from_raw_retained(ptr: *mut c_void) -> Option<Self> {
89        if ptr.is_null() {
90            None
91        } else {
92            let retained = unsafe { CVBufferRetain(ptr) };
93            Self::from_raw(retained)
94        }
95    }
96
97    /// Wrap a pixel buffer as a generic `CVBuffer`.
98    #[must_use]
99    pub fn from_pixel_buffer(pixel_buffer: &CVPixelBuffer) -> Option<Self> {
100        unsafe { Self::from_raw_retained(pixel_buffer.as_ptr()) }
101    }
102
103    /// Borrow the raw `CVBufferRef`.
104    #[must_use]
105    pub const fn as_ptr(&self) -> *mut c_void {
106        self.0
107    }
108
109    /// Attach a Core Foundation value to the buffer.
110    pub fn set_attachment(&self, key: &CFString, value: &dyn AsCFType, mode: CVAttachmentMode) {
111        unsafe { CVBufferSetAttachment(self.0, key.as_ptr(), value.as_ptr(), mode as u32) };
112    }
113
114    /// Copy an attachment value for `key`.
115    #[must_use]
116    pub fn attachment(&self, key: &CFString) -> Option<CFType> {
117        let mut attachment_mode = 0_u32;
118        let ptr = unsafe { CVBufferCopyAttachment(self.0, key.as_ptr(), &mut attachment_mode) };
119        CFType::from_raw(ptr)
120    }
121
122    /// Copy all attachments for the requested propagation mode.
123    #[must_use]
124    pub fn attachments(&self, mode: CVAttachmentMode) -> Option<CFDictionary> {
125        let ptr = unsafe { CVBufferCopyAttachments(self.0, mode as u32) };
126        CFDictionary::from_raw(ptr)
127    }
128
129    /// Remove all attachments.
130    pub fn remove_all_attachments(&self) {
131        unsafe { CVBufferRemoveAllAttachments(self.0) };
132    }
133}
134
135impl Clone for CVBuffer {
136    fn clone(&self) -> Self {
137        let retained = unsafe { CVBufferRetain(self.0) };
138        Self(retained)
139    }
140}
141
142impl Drop for CVBuffer {
143    fn drop(&mut self) {
144        unsafe { CVBufferRelease(self.0) };
145    }
146}
147
148impl PartialEq for CVBuffer {
149    fn eq(&self, other: &Self) -> bool {
150        self.0 == other.0
151    }
152}
153
154impl Eq for CVBuffer {}
155
156impl std::hash::Hash for CVBuffer {
157    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
158        self.0.hash(state);
159    }
160}
161
162impl fmt::Debug for CVBuffer {
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        f.debug_struct("CVBuffer").field("ptr", &self.0).finish()
165    }
166}
167
168/// Generic `CVImageBufferRef` wrapper.
169pub struct CVImageBuffer(*mut c_void);
170
171impl CVImageBuffer {
172    #[must_use]
173    pub fn from_raw(ptr: *mut c_void) -> Option<Self> {
174        if ptr.is_null() {
175            None
176        } else {
177            Some(Self(ptr))
178        }
179    }
180
181    /// Wrap a pixel buffer as a generic image buffer.
182    #[must_use]
183    pub fn from_pixel_buffer(pixel_buffer: &CVPixelBuffer) -> Option<Self> {
184        let retained = unsafe { CVBufferRetain(pixel_buffer.as_ptr()) };
185        Self::from_raw(retained)
186    }
187
188    /// Borrow the raw `CVImageBufferRef`.
189    #[must_use]
190    pub const fn as_ptr(&self) -> *mut c_void {
191        self.0
192    }
193
194    /// Encoded image size.
195    #[must_use]
196    pub fn encoded_size(&self) -> CVImageSize {
197        unsafe { CVImageBufferGetEncodedSize(self.0) }
198    }
199
200    /// Display size.
201    #[must_use]
202    pub fn display_size(&self) -> CVImageSize {
203        unsafe { CVImageBufferGetDisplaySize(self.0) }
204    }
205
206    /// Clean aperture rectangle.
207    #[must_use]
208    pub fn clean_rect(&self) -> CVImageRect {
209        unsafe { CVImageBufferGetCleanRect(self.0) }
210    }
211}
212
213impl Clone for CVImageBuffer {
214    fn clone(&self) -> Self {
215        let retained = unsafe { CVBufferRetain(self.0) };
216        Self(retained)
217    }
218}
219
220impl Drop for CVImageBuffer {
221    fn drop(&mut self) {
222        unsafe { CVBufferRelease(self.0) };
223    }
224}
225
226impl PartialEq for CVImageBuffer {
227    fn eq(&self, other: &Self) -> bool {
228        self.0 == other.0
229    }
230}
231
232impl Eq for CVImageBuffer {}
233
234impl std::hash::Hash for CVImageBuffer {
235    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
236        self.0.hash(state);
237    }
238}
239
240impl fmt::Debug for CVImageBuffer {
241    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242        f.debug_struct("CVImageBuffer")
243            .field("ptr", &self.0)
244            .field("encoded_size", &self.encoded_size())
245            .finish()
246    }
247}