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, &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 &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 &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 &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 &mut left,
416 &mut right,
417 &mut top,
418 &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
979unsafe impl Send for CVPixelBufferPoolPolicy {}
982unsafe impl Sync for CVPixelBufferPoolPolicy {}
983
984impl CVPixelBufferPoolPolicy {
985 const fn unlimited() -> Self {
986 Self {
987 max_buffers: None,
988 allocation_attributes: None,
989 }
990 }
991
992 fn new(max_buffers: usize) -> Result<Self, i32> {
993 if max_buffers == 0 {
994 return Ok(Self::unlimited());
995 }
996
997 let threshold = i64::try_from(max_buffers).map_err(|_| PARAM_ERR)?;
998 let key = retained_cf_string(
999 unsafe { raw::kCVPixelBufferPoolAllocationThresholdKey },
1000 "kCVPixelBufferPoolAllocationThresholdKey",
1001 );
1002 let value = CFNumber::from_i64(threshold);
1003 let attributes = CFDictionary::from_pairs(&[(&key, &value)]);
1004
1005 Ok(Self {
1006 max_buffers: Some(max_buffers),
1007 allocation_attributes: Some(attributes),
1008 })
1009 }
1010
1011 const fn max_buffers(&self) -> usize {
1012 match self.max_buffers {
1013 Some(max_buffers) => max_buffers,
1014 None => 0,
1015 }
1016 }
1017}
1018
1019fn retained_cf_string(ptr: raw::CFStringRef, symbol: &'static str) -> CFString {
1020 unsafe { CFString::from_raw_borrowed(ptr.cast_mut().cast()) }
1021 .unwrap_or_else(|| panic!("{symbol} was NULL"))
1022}
1023
1024fn pool_pixel_buffer_attributes(
1025 width: usize,
1026 height: usize,
1027 pixel_format: u32,
1028) -> Result<CFDictionary, i32> {
1029 let width = u64::try_from(width).map_err(|_| PARAM_ERR)?;
1030 let height = u64::try_from(height).map_err(|_| PARAM_ERR)?;
1031 let width_key = retained_cf_string(
1032 unsafe { raw::kCVPixelBufferWidthKey },
1033 "kCVPixelBufferWidthKey",
1034 );
1035 let height_key = retained_cf_string(
1036 unsafe { raw::kCVPixelBufferHeightKey },
1037 "kCVPixelBufferHeightKey",
1038 );
1039 let pixel_format_key = retained_cf_string(
1040 unsafe { raw::kCVPixelBufferPixelFormatTypeKey },
1041 "kCVPixelBufferPixelFormatTypeKey",
1042 );
1043 let io_surface_key = retained_cf_string(
1044 unsafe { raw::kCVPixelBufferIOSurfacePropertiesKey },
1045 "kCVPixelBufferIOSurfacePropertiesKey",
1046 );
1047 let width_value = CFNumber::from_u64(width);
1048 let height_value = CFNumber::from_u64(height);
1049 let pixel_format_value = CFNumber::from_u64(u64::from(pixel_format));
1050 let io_surface_properties = CFDictionary::from_pairs(&[]);
1051 let pairs: [(&dyn AsCFType, &dyn AsCFType); 4] = [
1052 (&width_key, &width_value),
1053 (&height_key, &height_value),
1054 (&pixel_format_key, &pixel_format_value),
1055 (&io_surface_key, &io_surface_properties),
1056 ];
1057 Ok(CFDictionary::from_pairs(&pairs))
1058}
1059
1060pub struct CVPixelBufferPool {
1062 ptr: *mut std::ffi::c_void,
1063 policy: Arc<CVPixelBufferPoolPolicy>,
1064}
1065
1066unsafe impl Send for CVPixelBufferPool {}
1070unsafe impl Sync for CVPixelBufferPool {}
1071
1072impl PartialEq for CVPixelBufferPool {
1073 fn eq(&self, other: &Self) -> bool {
1074 self.ptr == other.ptr
1075 }
1076}
1077
1078impl Eq for CVPixelBufferPool {}
1079
1080impl std::hash::Hash for CVPixelBufferPool {
1081 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1082 unsafe { ffi::cf_type_hash(self.ptr) }.hash(state);
1083 }
1084}
1085
1086impl CVPixelBufferPool {
1087 pub unsafe fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
1095 if ptr.is_null() {
1096 None
1097 } else {
1098 Some(Self {
1099 ptr,
1100 policy: Arc::new(CVPixelBufferPoolPolicy::unlimited()),
1101 })
1102 }
1103 }
1104
1105 pub unsafe fn from_raw_with_max_buffers(
1120 ptr: *mut std::ffi::c_void,
1121 max_buffers: usize,
1122 ) -> Result<Option<Self>, i32> {
1123 if ptr.is_null() {
1124 return Ok(None);
1125 }
1126 let policy = Arc::new(CVPixelBufferPoolPolicy::new(max_buffers)?);
1127 Ok(Some(Self { ptr, policy }))
1128 }
1129
1130 #[must_use]
1137 pub unsafe fn from_raw_borrowed(ptr: *mut std::ffi::c_void) -> Option<Self> {
1138 if ptr.is_null() {
1139 None
1140 } else {
1141 let retained = unsafe { raw::CVPixelBufferPoolRetain(ptr.cast()) };
1142 unsafe { Self::from_raw(retained.cast()) }
1143 }
1144 }
1145
1146 pub unsafe fn from_raw_borrowed_with_max_buffers(
1157 ptr: *mut std::ffi::c_void,
1158 max_buffers: usize,
1159 ) -> Result<Option<Self>, i32> {
1160 if ptr.is_null() {
1161 return Ok(None);
1162 }
1163 let policy = Arc::new(CVPixelBufferPoolPolicy::new(max_buffers)?);
1164 let retained = unsafe { raw::CVPixelBufferPoolRetain(ptr.cast()) };
1165 Ok(Some(Self {
1166 ptr: retained.cast(),
1167 policy,
1168 }))
1169 }
1170
1171 pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
1177 Self {
1178 ptr,
1179 policy: Arc::new(CVPixelBufferPoolPolicy::unlimited()),
1180 }
1181 }
1182
1183 #[must_use]
1188 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
1189 self.ptr
1190 }
1191
1192 #[must_use]
1194 pub fn max_buffers(&self) -> usize {
1195 self.policy.max_buffers()
1196 }
1197
1198 pub fn create(
1211 width: usize,
1212 height: usize,
1213 pixel_format: u32,
1214 max_buffers: usize,
1215 ) -> Result<Self, i32> {
1216 let policy = Arc::new(CVPixelBufferPoolPolicy::new(max_buffers)?);
1217 let pool_attributes = CFDictionary::from_pairs(&[]);
1218 let pixel_buffer_attributes = pool_pixel_buffer_attributes(width, height, pixel_format)?;
1219 let mut pool_ptr: raw::CVPixelBufferPoolRef = std::ptr::null_mut();
1220 unsafe {
1221 let status = raw::CVPixelBufferPoolCreate(
1222 std::ptr::null(),
1223 pool_attributes.as_ptr().cast(),
1224 pixel_buffer_attributes.as_ptr().cast(),
1225 &mut pool_ptr,
1226 );
1227
1228 if status == 0 && !pool_ptr.is_null() {
1229 Ok(Self {
1230 ptr: pool_ptr.cast(),
1231 policy,
1232 })
1233 } else {
1234 Err(status)
1235 }
1236 }
1237 }
1238
1239 fn create_pixel_buffer_with_dictionary(
1240 &self,
1241 auxiliary_attributes: Option<&CFDictionary>,
1242 ) -> Result<CVPixelBuffer, i32> {
1243 let mut pixel_buffer_ptr: raw::CVPixelBufferRef = std::ptr::null_mut();
1244 let status = unsafe {
1245 if let Some(attributes) = auxiliary_attributes {
1246 raw::CVPixelBufferPoolCreatePixelBufferWithAuxAttributes(
1247 std::ptr::null(),
1248 self.ptr.cast(),
1249 attributes.as_ptr().cast(),
1250 &mut pixel_buffer_ptr,
1251 )
1252 } else {
1253 raw::CVPixelBufferPoolCreatePixelBuffer(
1254 std::ptr::null(),
1255 self.ptr.cast(),
1256 &mut pixel_buffer_ptr,
1257 )
1258 }
1259 };
1260
1261 if status == 0 && !pixel_buffer_ptr.is_null() {
1262 unsafe { CVPixelBuffer::from_raw(pixel_buffer_ptr.cast()) }.ok_or(status)
1263 } else {
1264 Err(status)
1265 }
1266 }
1267
1268 pub fn create_pixel_buffer(&self) -> Result<CVPixelBuffer, i32> {
1274 self.create_pixel_buffer_with_dictionary(self.policy.allocation_attributes.as_ref())
1275 }
1276
1277 pub fn flush(&self) {
1279 self.flush_with_flags(CVPixelBufferPoolFlushFlags::NONE);
1280 }
1281
1282 pub fn flush_with_flags(&self, flags: CVPixelBufferPoolFlushFlags) {
1284 unsafe { raw::CVPixelBufferPoolFlush(self.ptr.cast(), flags.bits()) };
1285 }
1286
1287 pub fn flush_excess_buffers(&self) {
1289 self.flush_with_flags(CVPixelBufferPoolFlushFlags::EXCESS_BUFFERS);
1290 }
1291
1292 #[must_use]
1294 pub fn type_id() -> usize {
1295 #[allow(clippy::cast_possible_truncation)]
1296 {
1297 unsafe { raw::CVPixelBufferPoolGetTypeID() as usize }
1298 }
1299 }
1300
1301 pub fn create_pixel_buffer_with_aux_attributes(
1313 &self,
1314 aux_attributes: Option<&HashMap<String, u32>>,
1315 ) -> Result<CVPixelBuffer, i32> {
1316 let Some(aux_attributes) = aux_attributes.filter(|attributes| !attributes.is_empty())
1317 else {
1318 return self.create_pixel_buffer();
1319 };
1320
1321 let threshold_key = retained_cf_string(
1322 unsafe { raw::kCVPixelBufferPoolAllocationThresholdKey },
1323 "kCVPixelBufferPoolAllocationThresholdKey",
1324 );
1325 let mut keys = Vec::with_capacity(aux_attributes.len() + 1);
1326 let mut values = Vec::with_capacity(aux_attributes.len() + 1);
1327 let mut requested_threshold = None;
1328
1329 for (key, value) in aux_attributes {
1330 if key.as_bytes().contains(&0) {
1331 return Err(PARAM_ERR);
1332 }
1333 let key = CFString::new(key);
1334 if key == threshold_key {
1335 requested_threshold = Some(usize::try_from(*value).map_err(|_| PARAM_ERR)?);
1336 } else {
1337 keys.push(key);
1338 values.push(CFNumber::from_u64(u64::from(*value)));
1339 }
1340 }
1341
1342 let effective_threshold = match (self.policy.max_buffers, requested_threshold) {
1343 (Some(configured), Some(requested)) => Some(configured.min(requested)),
1344 (Some(configured), None) => Some(configured),
1345 (None, requested) => requested,
1346 };
1347
1348 if let Some(threshold) = effective_threshold {
1349 let threshold = i64::try_from(threshold).map_err(|_| PARAM_ERR)?;
1350 keys.push(threshold_key);
1351 values.push(CFNumber::from_i64(threshold));
1352 }
1353
1354 let pairs: Vec<(&dyn AsCFType, &dyn AsCFType)> = keys
1355 .iter()
1356 .zip(&values)
1357 .map(|(key, value)| (key as &dyn AsCFType, value as &dyn AsCFType))
1358 .collect();
1359 let attributes = CFDictionary::from_pairs(&pairs);
1360 self.create_pixel_buffer_with_dictionary(Some(&attributes))
1361 }
1362
1363 pub fn try_create_pixel_buffer(&self) -> Result<Option<CVPixelBuffer>, i32> {
1372 match self.create_pixel_buffer() {
1373 Ok(buffer) => Ok(Some(buffer)),
1374 Err(CV_RETURN_WOULD_EXCEED_ALLOCATION_THRESHOLD) => Ok(None),
1375 Err(status) => Err(status),
1376 }
1377 }
1378
1379 #[must_use]
1381 pub fn attributes(&self) -> Option<CFDictionary> {
1382 let ptr = unsafe { raw::CVPixelBufferPoolGetAttributes(self.ptr.cast()) };
1383 unsafe { CFDictionary::from_raw_borrowed(ptr.cast_mut().cast()) }
1384 }
1385
1386 #[must_use]
1388 pub fn pixel_buffer_attributes(&self) -> Option<CFDictionary> {
1389 let ptr = unsafe { raw::CVPixelBufferPoolGetPixelBufferAttributes(self.ptr.cast()) };
1390 unsafe { CFDictionary::from_raw_borrowed(ptr.cast_mut().cast()) }
1391 }
1392}
1393
1394impl Clone for CVPixelBufferPool {
1395 fn clone(&self) -> Self {
1396 let ptr = unsafe { raw::CVPixelBufferPoolRetain(self.ptr.cast()) };
1397 Self {
1398 ptr: ptr.cast(),
1399 policy: Arc::clone(&self.policy),
1400 }
1401 }
1402}
1403
1404impl Drop for CVPixelBufferPool {
1405 fn drop(&mut self) {
1406 if !self.ptr.is_null() {
1407 unsafe { raw::CVPixelBufferPoolRelease(self.ptr.cast()) };
1408 }
1409 }
1410}
1411
1412impl fmt::Debug for CVPixelBufferPool {
1413 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1414 f.debug_struct("CVPixelBufferPool")
1415 .field("ptr", &self.ptr)
1416 .field("max_buffers", &self.max_buffers())
1417 .finish_non_exhaustive()
1418 }
1419}
1420
1421impl fmt::Display for CVPixelBufferPool {
1422 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1423 write!(f, "CVPixelBufferPool")
1424 }
1425}
1426
1427pub trait PixelBufferCursorExt {
1429 fn seek_to_pixel(&mut self, x: usize, y: usize, bytes_per_row: usize) -> io::Result<u64>;
1437
1438 fn read_pixel(&mut self) -> io::Result<[u8; 4]>;
1444}
1445
1446impl<T: AsRef<[u8]>> PixelBufferCursorExt for io::Cursor<T> {
1447 fn seek_to_pixel(&mut self, x: usize, y: usize, bytes_per_row: usize) -> io::Result<u64> {
1448 let pos = y * bytes_per_row + x * 4; self.seek(SeekFrom::Start(pos as u64))
1450 }
1451
1452 fn read_pixel(&mut self) -> io::Result<[u8; 4]> {
1453 let mut pixel = [0u8; 4];
1454 self.read_exact(&mut pixel)?;
1455 Ok(pixel)
1456 }
1457}