1use crate::cf::{AsCFType, CFDictionary, CFNumber, CFString};
4use crate::iosurface::IOSurface;
5use crate::{ffi, raw};
6use std::collections::HashMap;
7use std::fmt;
8use std::io::{self, Read, Seek, SeekFrom};
9use std::sync::Arc;
10
11#[repr(transparent)]
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
30pub struct CVPixelBufferLockFlags(u64);
31
32impl CVPixelBufferLockFlags {
33 pub const NONE: Self = Self(0);
35
36 pub const READ_ONLY: Self = Self(0x0000_0001);
39
40 #[must_use]
42 pub const fn from_bits(bits: u64) -> Self {
43 Self(bits)
44 }
45
46 #[must_use]
48 pub const fn bits(self) -> u64 {
49 self.0
50 }
51
52 #[must_use]
54 pub const fn is_read_only(self) -> bool {
55 (self.0 & Self::READ_ONLY.0) != 0
56 }
57
58 #[must_use]
60 pub const fn is_empty(self) -> bool {
61 self.0 == 0
62 }
63}
64
65impl From<CVPixelBufferLockFlags> for u64 {
66 fn from(flags: CVPixelBufferLockFlags) -> Self {
67 flags.0
68 }
69}
70
71#[derive(Debug)]
72pub struct CVPixelBuffer(*mut std::ffi::c_void);
74
75impl PartialEq for CVPixelBuffer {
76 fn eq(&self, other: &Self) -> bool {
77 self.0 == other.0
78 }
79}
80
81impl Eq for CVPixelBuffer {}
82
83impl std::hash::Hash for CVPixelBuffer {
84 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
85 unsafe {
86 let hash_value = ffi::cv_pixel_buffer_hash(self.0);
87 hash_value.hash(state);
88 }
89 }
90}
91
92impl CVPixelBuffer {
93 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
101 if ptr.is_null() {
102 None
103 } else {
104 Some(Self(ptr))
105 }
106 }
107
108 #[must_use]
115 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
116 if ptr.is_null() {
117 None
118 } else {
119 let retained = unsafe { ffi::cv_pixel_buffer_retain(ptr) };
120 unsafe { Self::from_raw(retained) }
121 }
122 }
123
124 pub const unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
130 Self(ptr)
131 }
132
133 #[must_use]
135 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
136 self.0
137 }
138
139 pub fn create(width: usize, height: usize, pixel_format: u32) -> Result<Self, i32> {
165 unsafe {
166 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
167 let status =
168 ffi::cv_pixel_buffer_create(width, height, pixel_format, &raw mut pixel_buffer_ptr);
169
170 if status == 0 && !pixel_buffer_ptr.is_null() {
171 Ok(Self(pixel_buffer_ptr))
172 } else {
173 Err(status)
174 }
175 }
176 }
177
178 pub unsafe fn create_with_bytes(
237 width: usize,
238 height: usize,
239 pixel_format: u32,
240 base_address: *mut std::ffi::c_void,
241 bytes_per_row: usize,
242 ) -> Result<Self, i32> {
243 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
244 let status = ffi::cv_pixel_buffer_create_with_bytes(
245 width,
246 height,
247 pixel_format,
248 base_address,
249 bytes_per_row,
250 &raw mut pixel_buffer_ptr,
251 );
252
253 if status == 0 && !pixel_buffer_ptr.is_null() {
254 Ok(Self(pixel_buffer_ptr))
255 } else {
256 Err(status)
257 }
258 }
259
260 pub fn fill_extended_pixels(&self) -> Result<(), i32> {
269 unsafe {
270 let status = ffi::cv_pixel_buffer_fill_extended_pixels(self.0);
271 if status == 0 {
272 Ok(())
273 } else {
274 Err(status)
275 }
276 }
277 }
278
279 pub unsafe fn create_with_planar_bytes(
292 width: usize,
293 height: usize,
294 pixel_format: u32,
295 plane_base_addresses: &[*mut std::ffi::c_void],
296 plane_widths: &[usize],
297 plane_heights: &[usize],
298 plane_bytes_per_row: &[usize],
299 ) -> Result<Self, i32> {
300 if plane_base_addresses.len() != plane_widths.len()
301 || plane_widths.len() != plane_heights.len()
302 || plane_heights.len() != plane_bytes_per_row.len()
303 {
304 return Err(-50); }
306
307 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
308 let status = ffi::cv_pixel_buffer_create_with_planar_bytes(
309 width,
310 height,
311 pixel_format,
312 plane_base_addresses.len(),
313 plane_base_addresses.as_ptr(),
314 plane_widths.as_ptr(),
315 plane_heights.as_ptr(),
316 plane_bytes_per_row.as_ptr(),
317 &raw mut pixel_buffer_ptr,
318 );
319
320 if status == 0 && !pixel_buffer_ptr.is_null() {
321 Ok(Self(pixel_buffer_ptr))
322 } else {
323 Err(status)
324 }
325 }
326
327 pub fn create_with_io_surface(surface: &IOSurface) -> Result<Self, i32> {
333 unsafe {
334 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
335 let status = ffi::cv_pixel_buffer_create_with_io_surface(
336 surface.as_ptr(),
337 &raw mut pixel_buffer_ptr,
338 );
339
340 if status == 0 && !pixel_buffer_ptr.is_null() {
341 Ok(Self(pixel_buffer_ptr))
342 } else {
343 Err(status)
344 }
345 }
346 }
347
348 #[must_use]
350 pub fn type_id() -> usize {
351 unsafe { ffi::cv_pixel_buffer_get_type_id() }
352 }
353
354 #[must_use]
356 pub fn data_size(&self) -> usize {
357 unsafe { ffi::cv_pixel_buffer_get_data_size(self.0) }
358 }
359
360 #[must_use]
362 pub fn is_planar(&self) -> bool {
363 unsafe { ffi::cv_pixel_buffer_is_planar(self.0) }
364 }
365
366 #[must_use]
368 pub fn plane_count(&self) -> usize {
369 unsafe { ffi::cv_pixel_buffer_get_plane_count(self.0) }
370 }
371
372 #[must_use]
374 pub fn width_of_plane(&self, plane_index: usize) -> usize {
375 unsafe { ffi::cv_pixel_buffer_get_width_of_plane(self.0, plane_index) }
376 }
377
378 #[must_use]
380 pub fn height_of_plane(&self, plane_index: usize) -> usize {
381 unsafe { ffi::cv_pixel_buffer_get_height_of_plane(self.0, plane_index) }
382 }
383
384 fn base_address_of_plane_raw(&self, plane_index: usize) -> Option<*mut u8> {
389 unsafe {
390 let ptr = ffi::cv_pixel_buffer_get_base_address_of_plane(self.0, plane_index);
391 if ptr.is_null() {
392 None
393 } else {
394 Some(ptr.cast::<u8>())
395 }
396 }
397 }
398
399 #[must_use]
401 pub fn bytes_per_row_of_plane(&self, plane_index: usize) -> usize {
402 unsafe { ffi::cv_pixel_buffer_get_bytes_per_row_of_plane(self.0, plane_index) }
403 }
404
405 #[must_use]
407 pub fn extended_pixels(&self) -> (usize, usize, usize, usize) {
408 unsafe {
409 let mut left: usize = 0;
410 let mut right: usize = 0;
411 let mut top: usize = 0;
412 let mut bottom: usize = 0;
413 ffi::cv_pixel_buffer_get_extended_pixels(
414 self.0,
415 &raw mut left,
416 &raw mut right,
417 &raw mut top,
418 &raw mut bottom,
419 );
420 (left, right, top, bottom)
421 }
422 }
423
424 #[must_use]
426 pub fn is_backed_by_io_surface(&self) -> bool {
427 self.io_surface().is_some()
428 }
429
430 #[must_use]
432 pub fn width(&self) -> usize {
433 unsafe { ffi::cv_pixel_buffer_get_width(self.0) }
434 }
435
436 #[must_use]
438 pub fn height(&self) -> usize {
439 unsafe { ffi::cv_pixel_buffer_get_height(self.0) }
440 }
441
442 #[must_use]
444 pub fn pixel_format(&self) -> u32 {
445 unsafe { ffi::cv_pixel_buffer_get_pixel_format_type(self.0) }
446 }
447
448 #[must_use]
450 pub fn bytes_per_row(&self) -> usize {
451 unsafe { ffi::cv_pixel_buffer_get_bytes_per_row(self.0) }
452 }
453
454 pub unsafe fn lock_raw(&self, flags: CVPixelBufferLockFlags) -> Result<(), i32> {
470 let result = unsafe { raw::CVPixelBufferLockBaseAddress(self.0.cast(), flags.bits()) };
471 if result == 0 {
472 Ok(())
473 } else {
474 Err(result)
475 }
476 }
477
478 pub unsafe fn unlock_raw(&self, flags: CVPixelBufferLockFlags) -> Result<(), i32> {
491 let result = unsafe { raw::CVPixelBufferUnlockBaseAddress(self.0.cast(), flags.bits()) };
492 if result == 0 {
493 Ok(())
494 } else {
495 Err(result)
496 }
497 }
498
499 fn base_address_raw(&self) -> Option<*mut u8> {
504 unsafe {
505 let ptr = ffi::cv_pixel_buffer_get_base_address(self.0);
506 if ptr.is_null() {
507 None
508 } else {
509 Some(ptr.cast::<u8>())
510 }
511 }
512 }
513
514 #[must_use]
516 pub fn io_surface(&self) -> Option<IOSurface> {
517 unsafe {
518 let ptr = ffi::cv_pixel_buffer_get_io_surface(self.0);
519 IOSurface::from_raw(ptr)
520 }
521 }
522
523 pub fn lock(&self, flags: CVPixelBufferLockFlags) -> Result<CVPixelBufferLockGuard<'_>, i32> {
548 unsafe { self.lock_raw(flags)? };
549 Ok(CVPixelBufferLockGuard {
550 buffer: self,
551 flags,
552 })
553 }
554
555 pub fn lock_read_only(&self) -> Result<CVPixelBufferLockGuard<'_>, i32> {
563 self.lock(CVPixelBufferLockFlags::READ_ONLY)
564 }
565
566 pub fn lock_read_write(&self) -> Result<CVPixelBufferLockGuard<'_>, i32> {
574 self.lock(CVPixelBufferLockFlags::NONE)
575 }
576}
577
578pub struct CVPixelBufferLockGuard<'a> {
580 buffer: &'a CVPixelBuffer,
581 flags: CVPixelBufferLockFlags,
582}
583
584impl CVPixelBufferLockGuard<'_> {
585 fn non_planar_data_len(&self) -> Option<usize> {
586 if self.buffer.is_planar() {
587 return None;
588 }
589 let len = self.height().checked_mul(self.bytes_per_row())?;
590 (len <= self.data_size() && isize::try_from(len).is_ok()).then_some(len)
591 }
592
593 #[must_use]
598 pub fn base_address(&self) -> *const u8 {
599 self.buffer
600 .base_address_raw()
601 .unwrap_or(std::ptr::null_mut())
602 .cast_const()
603 }
604
605 pub fn base_address_mut(&mut self) -> Option<*mut u8> {
611 if self.flags.is_read_only() {
612 None
613 } else {
614 self.buffer.base_address_raw()
615 }
616 }
617
618 pub fn base_address_of_plane(&self, plane_index: usize) -> Option<*const u8> {
628 self.buffer
629 .base_address_of_plane_raw(plane_index)
630 .map(<*mut u8>::cast_const)
631 }
632
633 pub fn base_address_of_plane_mut(&mut self, plane_index: usize) -> Option<*mut u8> {
638 if self.flags.is_read_only() {
639 return None;
640 }
641 self.buffer.base_address_of_plane_raw(plane_index)
642 }
643
644 #[must_use]
646 pub fn width(&self) -> usize {
647 self.buffer.width()
648 }
649
650 #[must_use]
652 pub fn height(&self) -> usize {
653 self.buffer.height()
654 }
655
656 #[must_use]
658 pub fn bytes_per_row(&self) -> usize {
659 self.buffer.bytes_per_row()
660 }
661
662 #[must_use]
666 pub fn data_size(&self) -> usize {
667 self.buffer.data_size()
668 }
669
670 #[must_use]
672 pub fn plane_count(&self) -> usize {
673 self.buffer.plane_count()
674 }
675
676 #[must_use]
678 pub fn width_of_plane(&self, plane_index: usize) -> usize {
679 self.buffer.width_of_plane(plane_index)
680 }
681
682 #[must_use]
684 pub fn height_of_plane(&self, plane_index: usize) -> usize {
685 self.buffer.height_of_plane(plane_index)
686 }
687
688 #[must_use]
690 pub fn bytes_per_row_of_plane(&self, plane_index: usize) -> usize {
691 self.buffer.bytes_per_row_of_plane(plane_index)
692 }
693
694 #[must_use]
706 pub unsafe fn as_slice(&self) -> Option<&[u8]> {
707 let ptr = self.base_address();
708 let len = self.non_planar_data_len()?;
709 if len == 0 {
710 return Some(&[]);
711 }
712 if ptr.is_null() {
713 return None;
714 }
715 Some(unsafe { std::slice::from_raw_parts(ptr, len) })
716 }
717
718 pub unsafe fn as_slice_mut(&mut self) -> Option<&mut [u8]> {
730 let len = self.non_planar_data_len()?;
731 if len == 0 {
732 return Some(&mut []);
733 }
734 let ptr = self.base_address_mut()?;
735 Some(unsafe { std::slice::from_raw_parts_mut(ptr, len) })
736 }
737
738 #[must_use]
750 pub unsafe fn plane_data(&self, plane_index: usize) -> Option<&[u8]> {
751 if !self.buffer.is_planar() || plane_index >= self.buffer.plane_count() {
752 return None;
753 }
754 let base = self.base_address_of_plane(plane_index)?;
755 let height = self.buffer.height_of_plane(plane_index);
756 let bytes_per_row = self.buffer.bytes_per_row_of_plane(plane_index);
757 let len = height.checked_mul(bytes_per_row)?;
758 if isize::try_from(len).is_err() {
759 return None;
760 }
761 Some(unsafe { std::slice::from_raw_parts(base, len) })
762 }
763
764 #[must_use]
773 pub unsafe fn plane_row(&self, plane_index: usize, row_index: usize) -> Option<&[u8]> {
774 if !self.buffer.is_planar() || plane_index >= self.buffer.plane_count() {
775 return None;
776 }
777 let height = self.buffer.height_of_plane(plane_index);
778 if row_index >= height {
779 return None;
780 }
781 let base = self.base_address_of_plane(plane_index)?;
782 let bytes_per_row = self.buffer.bytes_per_row_of_plane(plane_index);
783 let plane_len = height.checked_mul(bytes_per_row)?;
784 let offset = row_index.checked_mul(bytes_per_row)?;
785 let end = offset.checked_add(bytes_per_row)?;
786 if end > plane_len || isize::try_from(bytes_per_row).is_err() {
787 return None;
788 }
789 Some(unsafe { std::slice::from_raw_parts(base.add(offset), bytes_per_row) })
790 }
791
792 #[must_use]
801 pub unsafe fn row(&self, row_index: usize) -> Option<&[u8]> {
802 if row_index >= self.height() {
803 return None;
804 }
805 let len = self.non_planar_data_len()?;
806 let ptr = self.base_address();
807 if ptr.is_null() {
808 return None;
809 }
810 let bytes_per_row = self.bytes_per_row();
811 let offset = row_index.checked_mul(bytes_per_row)?;
812 let end = offset.checked_add(bytes_per_row)?;
813 if end > len || isize::try_from(bytes_per_row).is_err() {
814 return None;
815 }
816 Some(unsafe { std::slice::from_raw_parts(ptr.add(offset), bytes_per_row) })
817 }
818
819 #[must_use]
849 pub unsafe fn cursor(&self) -> Option<io::Cursor<&[u8]>> {
850 unsafe { self.as_slice() }.map(io::Cursor::new)
851 }
852
853 #[must_use]
855 pub fn as_ptr(&self) -> *const u8 {
856 self.base_address()
857 }
858
859 pub fn as_mut_ptr(&mut self) -> Option<*mut u8> {
863 self.base_address_mut()
864 }
865
866 #[must_use]
868 pub const fn is_read_only(&self) -> bool {
869 self.flags.is_read_only()
870 }
871
872 #[must_use]
874 pub const fn options(&self) -> CVPixelBufferLockFlags {
875 self.flags
876 }
877
878 #[must_use]
880 pub fn pixel_format(&self) -> u32 {
881 self.buffer.pixel_format()
882 }
883}
884
885impl Drop for CVPixelBufferLockGuard<'_> {
886 fn drop(&mut self) {
887 let _ = unsafe { self.buffer.unlock_raw(self.flags) };
888 }
889}
890
891impl std::fmt::Debug for CVPixelBufferLockGuard<'_> {
892 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
893 f.debug_struct("CVPixelBufferLockGuard")
894 .field("flags", &self.flags)
895 .field("buffer_size", &(self.buffer.width(), self.buffer.height()))
896 .finish()
897 }
898}
899
900crate::utils::retained::cf_retained!(
901 CVPixelBuffer,
902 retain = ffi::cv_pixel_buffer_retain,
903 release = ffi::cv_pixel_buffer_release,
904);
905
906unsafe impl Send for CVPixelBuffer {}
911unsafe impl Sync for CVPixelBuffer {}
912
913impl fmt::Display for CVPixelBuffer {
914 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
915 write!(
916 f,
917 "CVPixelBuffer({}x{}, format: 0x{:08X})",
918 self.width(),
919 self.height(),
920 self.pixel_format()
921 )
922 }
923}
924
925#[repr(transparent)]
927#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
928pub struct CVPixelBufferPoolFlushFlags(u64);
929
930impl CVPixelBufferPoolFlushFlags {
931 pub const NONE: Self = Self(0);
933
934 pub const EXCESS_BUFFERS: Self = Self(1);
936
937 #[must_use]
939 pub const fn from_bits(bits: u64) -> Self {
940 Self(bits)
941 }
942
943 #[must_use]
945 pub const fn bits(self) -> u64 {
946 self.0
947 }
948}
949
950impl std::ops::BitOr for CVPixelBufferPoolFlushFlags {
951 type Output = Self;
952
953 fn bitor(self, rhs: Self) -> Self::Output {
954 Self(self.0 | rhs.0)
955 }
956}
957
958impl std::ops::BitOrAssign for CVPixelBufferPoolFlushFlags {
959 fn bitor_assign(&mut self, rhs: Self) {
960 self.0 |= rhs.0;
961 }
962}
963
964impl From<CVPixelBufferPoolFlushFlags> for u64 {
965 fn from(flags: CVPixelBufferPoolFlushFlags) -> Self {
966 flags.bits()
967 }
968}
969
970const CV_RETURN_WOULD_EXCEED_ALLOCATION_THRESHOLD: i32 = -6689;
971const PARAM_ERR: i32 = -50;
972
973#[derive(Debug)]
974struct CVPixelBufferPoolPolicy {
975 max_buffers: Option<usize>,
976 allocation_attributes: Option<CFDictionary>,
977}
978
979#[allow(clippy::non_send_fields_in_send_ty)]
982unsafe impl Send for CVPixelBufferPoolPolicy {}
983unsafe impl Sync for CVPixelBufferPoolPolicy {}
984
985impl CVPixelBufferPoolPolicy {
986 const fn unlimited() -> Self {
987 Self {
988 max_buffers: None,
989 allocation_attributes: None,
990 }
991 }
992
993 fn new(max_buffers: usize) -> Result<Self, i32> {
994 if max_buffers == 0 {
995 return Ok(Self::unlimited());
996 }
997
998 let threshold = i64::try_from(max_buffers).map_err(|_| PARAM_ERR)?;
999 let key = retained_cf_string(
1000 unsafe { raw::kCVPixelBufferPoolAllocationThresholdKey },
1001 "kCVPixelBufferPoolAllocationThresholdKey",
1002 );
1003 let value = CFNumber::from_i64(threshold);
1004 let attributes = CFDictionary::from_pairs(&[(&key, &value)]);
1005
1006 Ok(Self {
1007 max_buffers: Some(max_buffers),
1008 allocation_attributes: Some(attributes),
1009 })
1010 }
1011
1012 const fn max_buffers(&self) -> usize {
1013 match self.max_buffers {
1014 Some(max_buffers) => max_buffers,
1015 None => 0,
1016 }
1017 }
1018}
1019
1020fn retained_cf_string(ptr: raw::CFStringRef, symbol: &'static str) -> CFString {
1021 unsafe { CFString::from_raw_borrowed(ptr.cast_mut().cast()) }
1022 .unwrap_or_else(|| panic!("{symbol} was NULL"))
1023}
1024
1025fn pool_pixel_buffer_attributes(
1026 width: usize,
1027 height: usize,
1028 pixel_format: u32,
1029) -> Result<CFDictionary, i32> {
1030 let width = u64::try_from(width).map_err(|_| PARAM_ERR)?;
1031 let height = u64::try_from(height).map_err(|_| PARAM_ERR)?;
1032 let width_key = retained_cf_string(
1033 unsafe { raw::kCVPixelBufferWidthKey },
1034 "kCVPixelBufferWidthKey",
1035 );
1036 let height_key = retained_cf_string(
1037 unsafe { raw::kCVPixelBufferHeightKey },
1038 "kCVPixelBufferHeightKey",
1039 );
1040 let pixel_format_key = retained_cf_string(
1041 unsafe { raw::kCVPixelBufferPixelFormatTypeKey },
1042 "kCVPixelBufferPixelFormatTypeKey",
1043 );
1044 let io_surface_key = retained_cf_string(
1045 unsafe { raw::kCVPixelBufferIOSurfacePropertiesKey },
1046 "kCVPixelBufferIOSurfacePropertiesKey",
1047 );
1048 let width_value = CFNumber::from_u64(width);
1049 let height_value = CFNumber::from_u64(height);
1050 let pixel_format_value = CFNumber::from_u64(u64::from(pixel_format));
1051 let io_surface_properties = CFDictionary::from_pairs(&[]);
1052 let pairs: [(&dyn AsCFType, &dyn AsCFType); 4] = [
1053 (&width_key, &width_value),
1054 (&height_key, &height_value),
1055 (&pixel_format_key, &pixel_format_value),
1056 (&io_surface_key, &io_surface_properties),
1057 ];
1058 Ok(CFDictionary::from_pairs(&pairs))
1059}
1060
1061pub struct CVPixelBufferPool {
1063 ptr: *mut std::ffi::c_void,
1064 policy: Arc<CVPixelBufferPoolPolicy>,
1065}
1066
1067unsafe impl Send for CVPixelBufferPool {}
1071unsafe impl Sync for CVPixelBufferPool {}
1072
1073impl PartialEq for CVPixelBufferPool {
1074 fn eq(&self, other: &Self) -> bool {
1075 self.ptr == other.ptr
1076 }
1077}
1078
1079impl Eq for CVPixelBufferPool {}
1080
1081impl std::hash::Hash for CVPixelBufferPool {
1082 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1083 unsafe { ffi::cf_type_hash(self.ptr) }.hash(state);
1084 }
1085}
1086
1087impl CVPixelBufferPool {
1088 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
1096 if ptr.is_null() {
1097 None
1098 } else {
1099 Some(Self {
1100 ptr,
1101 policy: Arc::new(CVPixelBufferPoolPolicy::unlimited()),
1102 })
1103 }
1104 }
1105
1106 pub unsafe fn from_raw_with_max_buffers(
1121 ptr: *mut std::ffi::c_void,
1122 max_buffers: usize,
1123 ) -> Result<Option<Self>, i32> {
1124 if ptr.is_null() {
1125 return Ok(None);
1126 }
1127 let policy = Arc::new(CVPixelBufferPoolPolicy::new(max_buffers)?);
1128 Ok(Some(Self { ptr, policy }))
1129 }
1130
1131 #[must_use]
1138 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
1139 if ptr.is_null() {
1140 None
1141 } else {
1142 let retained = unsafe { raw::CVPixelBufferPoolRetain(ptr.cast()) };
1143 unsafe { Self::from_raw(retained.cast()) }
1144 }
1145 }
1146
1147 pub unsafe fn from_raw_borrowed_with_max_buffers(
1158 ptr: *mut std::ffi::c_void,
1159 max_buffers: usize,
1160 ) -> Result<Option<Self>, i32> {
1161 if ptr.is_null() {
1162 return Ok(None);
1163 }
1164 let policy = Arc::new(CVPixelBufferPoolPolicy::new(max_buffers)?);
1165 let retained = unsafe { raw::CVPixelBufferPoolRetain(ptr.cast()) };
1166 Ok(Some(Self {
1167 ptr: retained.cast(),
1168 policy,
1169 }))
1170 }
1171
1172 pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
1178 Self {
1179 ptr,
1180 policy: Arc::new(CVPixelBufferPoolPolicy::unlimited()),
1181 }
1182 }
1183
1184 #[must_use]
1189 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
1190 self.ptr
1191 }
1192
1193 #[must_use]
1195 pub fn max_buffers(&self) -> usize {
1196 self.policy.max_buffers()
1197 }
1198
1199 pub fn create(
1212 width: usize,
1213 height: usize,
1214 pixel_format: u32,
1215 max_buffers: usize,
1216 ) -> Result<Self, i32> {
1217 let policy = Arc::new(CVPixelBufferPoolPolicy::new(max_buffers)?);
1218 let pool_attributes = CFDictionary::from_pairs(&[]);
1219 let pixel_buffer_attributes = pool_pixel_buffer_attributes(width, height, pixel_format)?;
1220 let mut pool_ptr: raw::CVPixelBufferPoolRef = std::ptr::null_mut();
1221 unsafe {
1222 let status = raw::CVPixelBufferPoolCreate(
1223 std::ptr::null(),
1224 pool_attributes.as_ptr().cast(),
1225 pixel_buffer_attributes.as_ptr().cast(),
1226 &raw mut pool_ptr,
1227 );
1228
1229 if status == 0 && !pool_ptr.is_null() {
1230 Ok(Self {
1231 ptr: pool_ptr.cast(),
1232 policy,
1233 })
1234 } else {
1235 Err(status)
1236 }
1237 }
1238 }
1239
1240 fn create_pixel_buffer_with_dictionary(
1241 &self,
1242 auxiliary_attributes: Option<&CFDictionary>,
1243 ) -> Result<CVPixelBuffer, i32> {
1244 let mut pixel_buffer_ptr: raw::CVPixelBufferRef = std::ptr::null_mut();
1245 let status = unsafe {
1246 if let Some(attributes) = auxiliary_attributes {
1247 raw::CVPixelBufferPoolCreatePixelBufferWithAuxAttributes(
1248 std::ptr::null(),
1249 self.ptr.cast(),
1250 attributes.as_ptr().cast(),
1251 &raw mut pixel_buffer_ptr,
1252 )
1253 } else {
1254 raw::CVPixelBufferPoolCreatePixelBuffer(
1255 std::ptr::null(),
1256 self.ptr.cast(),
1257 &raw mut pixel_buffer_ptr,
1258 )
1259 }
1260 };
1261
1262 if status == 0 && !pixel_buffer_ptr.is_null() {
1263 unsafe { CVPixelBuffer::from_raw(pixel_buffer_ptr.cast()) }.ok_or(status)
1264 } else {
1265 Err(status)
1266 }
1267 }
1268
1269 pub fn create_pixel_buffer(&self) -> Result<CVPixelBuffer, i32> {
1275 self.create_pixel_buffer_with_dictionary(self.policy.allocation_attributes.as_ref())
1276 }
1277
1278 pub fn flush(&self) {
1280 self.flush_with_flags(CVPixelBufferPoolFlushFlags::NONE);
1281 }
1282
1283 pub fn flush_with_flags(&self, flags: CVPixelBufferPoolFlushFlags) {
1285 unsafe { raw::CVPixelBufferPoolFlush(self.ptr.cast(), flags.bits()) };
1286 }
1287
1288 pub fn flush_excess_buffers(&self) {
1290 self.flush_with_flags(CVPixelBufferPoolFlushFlags::EXCESS_BUFFERS);
1291 }
1292
1293 #[must_use]
1295 pub fn type_id() -> usize {
1296 #[allow(clippy::cast_possible_truncation)]
1297 {
1298 unsafe { raw::CVPixelBufferPoolGetTypeID() as usize }
1299 }
1300 }
1301
1302 pub fn create_pixel_buffer_with_aux_attributes(
1314 &self,
1315 aux_attributes: Option<&HashMap<String, u32>>,
1316 ) -> Result<CVPixelBuffer, i32> {
1317 let Some(aux_attributes) = aux_attributes.filter(|attributes| !attributes.is_empty())
1318 else {
1319 return self.create_pixel_buffer();
1320 };
1321
1322 let threshold_key = retained_cf_string(
1323 unsafe { raw::kCVPixelBufferPoolAllocationThresholdKey },
1324 "kCVPixelBufferPoolAllocationThresholdKey",
1325 );
1326 let mut keys = Vec::with_capacity(aux_attributes.len() + 1);
1327 let mut values = Vec::with_capacity(aux_attributes.len() + 1);
1328 let mut requested_threshold = None;
1329
1330 for (key, value) in aux_attributes {
1331 if key.as_bytes().contains(&0) {
1332 return Err(PARAM_ERR);
1333 }
1334 let key = CFString::new(key);
1335 if key == threshold_key {
1336 requested_threshold = Some(usize::try_from(*value).map_err(|_| PARAM_ERR)?);
1337 } else {
1338 keys.push(key);
1339 values.push(CFNumber::from_u64(u64::from(*value)));
1340 }
1341 }
1342
1343 let effective_threshold = match (self.policy.max_buffers, requested_threshold) {
1344 (Some(configured), Some(requested)) => Some(configured.min(requested)),
1345 (Some(configured), None) => Some(configured),
1346 (None, requested) => requested,
1347 };
1348
1349 if let Some(threshold) = effective_threshold {
1350 let threshold = i64::try_from(threshold).map_err(|_| PARAM_ERR)?;
1351 keys.push(threshold_key);
1352 values.push(CFNumber::from_i64(threshold));
1353 }
1354
1355 let pairs: Vec<(&dyn AsCFType, &dyn AsCFType)> = keys
1356 .iter()
1357 .zip(&values)
1358 .map(|(key, value)| (key as &dyn AsCFType, value as &dyn AsCFType))
1359 .collect();
1360 let attributes = CFDictionary::from_pairs(&pairs);
1361 self.create_pixel_buffer_with_dictionary(Some(&attributes))
1362 }
1363
1364 pub fn try_create_pixel_buffer(&self) -> Result<Option<CVPixelBuffer>, i32> {
1373 match self.create_pixel_buffer() {
1374 Ok(buffer) => Ok(Some(buffer)),
1375 Err(CV_RETURN_WOULD_EXCEED_ALLOCATION_THRESHOLD) => Ok(None),
1376 Err(status) => Err(status),
1377 }
1378 }
1379
1380 #[must_use]
1382 pub fn attributes(&self) -> Option<CFDictionary> {
1383 let ptr = unsafe { raw::CVPixelBufferPoolGetAttributes(self.ptr.cast()) };
1384 unsafe { CFDictionary::from_raw_borrowed(ptr.cast_mut().cast()) }
1385 }
1386
1387 #[must_use]
1389 pub fn pixel_buffer_attributes(&self) -> Option<CFDictionary> {
1390 let ptr = unsafe { raw::CVPixelBufferPoolGetPixelBufferAttributes(self.ptr.cast()) };
1391 unsafe { CFDictionary::from_raw_borrowed(ptr.cast_mut().cast()) }
1392 }
1393}
1394
1395impl Clone for CVPixelBufferPool {
1396 fn clone(&self) -> Self {
1397 let ptr = unsafe { raw::CVPixelBufferPoolRetain(self.ptr.cast()) };
1398 Self {
1399 ptr: ptr.cast(),
1400 policy: Arc::clone(&self.policy),
1401 }
1402 }
1403}
1404
1405impl Drop for CVPixelBufferPool {
1406 fn drop(&mut self) {
1407 if !self.ptr.is_null() {
1408 unsafe { raw::CVPixelBufferPoolRelease(self.ptr.cast()) };
1409 }
1410 }
1411}
1412
1413impl fmt::Debug for CVPixelBufferPool {
1414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1415 f.debug_struct("CVPixelBufferPool")
1416 .field("ptr", &self.ptr)
1417 .field("max_buffers", &self.max_buffers())
1418 .finish_non_exhaustive()
1419 }
1420}
1421
1422impl fmt::Display for CVPixelBufferPool {
1423 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1424 write!(f, "CVPixelBufferPool")
1425 }
1426}
1427
1428pub trait PixelBufferCursorExt {
1430 fn seek_to_pixel(&mut self, x: usize, y: usize, bytes_per_row: usize) -> io::Result<u64>;
1438
1439 fn read_pixel(&mut self) -> io::Result<[u8; 4]>;
1445}
1446
1447impl<T: AsRef<[u8]>> PixelBufferCursorExt for io::Cursor<T> {
1448 fn seek_to_pixel(&mut self, x: usize, y: usize, bytes_per_row: usize) -> io::Result<u64> {
1449 let pos = y * bytes_per_row + x * 4; self.seek(SeekFrom::Start(pos as u64))
1451 }
1452
1453 fn read_pixel(&mut self) -> io::Result<[u8; 4]> {
1454 let mut pixel = [0u8; 4];
1455 self.read_exact(&mut pixel)?;
1456 Ok(pixel)
1457 }
1458}