1use crate::ffi;
4use crate::iosurface::IOSurface;
5use std::fmt;
6use std::io::{self, Read, Seek, SeekFrom};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
26pub struct CVPixelBufferLockFlags(u32);
27
28impl CVPixelBufferLockFlags {
29 pub const NONE: Self = Self(0);
31
32 pub const READ_ONLY: Self = Self(0x0000_0001);
35
36 #[must_use]
38 pub const fn from_bits(bits: u32) -> Self {
39 Self(bits)
40 }
41
42 #[must_use]
44 pub const fn as_u32(self) -> u32 {
45 self.0
46 }
47
48 #[must_use]
50 pub const fn is_read_only(self) -> bool {
51 (self.0 & Self::READ_ONLY.0) != 0
52 }
53
54 #[must_use]
56 pub const fn is_empty(self) -> bool {
57 self.0 == 0
58 }
59}
60
61impl From<CVPixelBufferLockFlags> for u32 {
62 fn from(flags: CVPixelBufferLockFlags) -> Self {
63 flags.0
64 }
65}
66
67#[derive(Debug)]
68pub struct CVPixelBuffer(*mut std::ffi::c_void);
69
70impl PartialEq for CVPixelBuffer {
71 fn eq(&self, other: &Self) -> bool {
72 self.0 == other.0
73 }
74}
75
76impl Eq for CVPixelBuffer {}
77
78impl std::hash::Hash for CVPixelBuffer {
79 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
80 unsafe {
81 let hash_value = ffi::cv_pixel_buffer_hash(self.0);
82 hash_value.hash(state);
83 }
84 }
85}
86
87impl CVPixelBuffer {
88 pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
89 if ptr.is_null() {
90 None
91 } else {
92 Some(Self(ptr))
93 }
94 }
95
96 pub const unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
99 Self(ptr)
100 }
101
102 #[must_use]
103 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
104 self.0
105 }
106
107 pub fn create(width: usize, height: usize, pixel_format: u32) -> Result<Self, i32> {
133 unsafe {
134 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
135 let status =
136 ffi::cv_pixel_buffer_create(width, height, pixel_format, &mut pixel_buffer_ptr);
137
138 if status == 0 && !pixel_buffer_ptr.is_null() {
139 Ok(Self(pixel_buffer_ptr))
140 } else {
141 Err(status)
142 }
143 }
144 }
145
146 pub unsafe fn create_with_bytes(
205 width: usize,
206 height: usize,
207 pixel_format: u32,
208 base_address: *mut std::ffi::c_void,
209 bytes_per_row: usize,
210 ) -> Result<Self, i32> {
211 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
212 let status = ffi::cv_pixel_buffer_create_with_bytes(
213 width,
214 height,
215 pixel_format,
216 base_address,
217 bytes_per_row,
218 &mut pixel_buffer_ptr,
219 );
220
221 if status == 0 && !pixel_buffer_ptr.is_null() {
222 Ok(Self(pixel_buffer_ptr))
223 } else {
224 Err(status)
225 }
226 }
227
228 pub fn fill_extended_pixels(&self) -> Result<(), i32> {
237 unsafe {
238 let status = ffi::cv_pixel_buffer_fill_extended_pixels(self.0);
239 if status == 0 {
240 Ok(())
241 } else {
242 Err(status)
243 }
244 }
245 }
246
247 pub unsafe fn create_with_planar_bytes(
260 width: usize,
261 height: usize,
262 pixel_format: u32,
263 plane_base_addresses: &[*mut std::ffi::c_void],
264 plane_widths: &[usize],
265 plane_heights: &[usize],
266 plane_bytes_per_row: &[usize],
267 ) -> Result<Self, i32> {
268 if plane_base_addresses.len() != plane_widths.len()
269 || plane_widths.len() != plane_heights.len()
270 || plane_heights.len() != plane_bytes_per_row.len()
271 {
272 return Err(-50); }
274
275 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
276 let status = ffi::cv_pixel_buffer_create_with_planar_bytes(
277 width,
278 height,
279 pixel_format,
280 plane_base_addresses.len(),
281 plane_base_addresses.as_ptr(),
282 plane_widths.as_ptr(),
283 plane_heights.as_ptr(),
284 plane_bytes_per_row.as_ptr(),
285 &mut pixel_buffer_ptr,
286 );
287
288 if status == 0 && !pixel_buffer_ptr.is_null() {
289 Ok(Self(pixel_buffer_ptr))
290 } else {
291 Err(status)
292 }
293 }
294
295 pub fn create_with_io_surface(surface: &IOSurface) -> Result<Self, i32> {
301 unsafe {
302 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
303 let status = ffi::cv_pixel_buffer_create_with_io_surface(
304 surface.as_ptr(),
305 &mut pixel_buffer_ptr,
306 );
307
308 if status == 0 && !pixel_buffer_ptr.is_null() {
309 Ok(Self(pixel_buffer_ptr))
310 } else {
311 Err(status)
312 }
313 }
314 }
315
316 #[must_use]
318 pub fn type_id() -> usize {
319 unsafe { ffi::cv_pixel_buffer_get_type_id() }
320 }
321
322 #[must_use]
324 pub fn data_size(&self) -> usize {
325 unsafe { ffi::cv_pixel_buffer_get_data_size(self.0) }
326 }
327
328 #[must_use]
330 pub fn is_planar(&self) -> bool {
331 unsafe { ffi::cv_pixel_buffer_is_planar(self.0) }
332 }
333
334 #[must_use]
336 pub fn plane_count(&self) -> usize {
337 unsafe { ffi::cv_pixel_buffer_get_plane_count(self.0) }
338 }
339
340 #[must_use]
342 pub fn width_of_plane(&self, plane_index: usize) -> usize {
343 unsafe { ffi::cv_pixel_buffer_get_width_of_plane(self.0, plane_index) }
344 }
345
346 #[must_use]
348 pub fn height_of_plane(&self, plane_index: usize) -> usize {
349 unsafe { ffi::cv_pixel_buffer_get_height_of_plane(self.0, plane_index) }
350 }
351
352 fn base_address_of_plane_raw(&self, plane_index: usize) -> Option<*mut u8> {
357 unsafe {
358 let ptr = ffi::cv_pixel_buffer_get_base_address_of_plane(self.0, plane_index);
359 if ptr.is_null() {
360 None
361 } else {
362 Some(ptr.cast::<u8>())
363 }
364 }
365 }
366
367 #[must_use]
369 pub fn bytes_per_row_of_plane(&self, plane_index: usize) -> usize {
370 unsafe { ffi::cv_pixel_buffer_get_bytes_per_row_of_plane(self.0, plane_index) }
371 }
372
373 #[must_use]
375 pub fn extended_pixels(&self) -> (usize, usize, usize, usize) {
376 unsafe {
377 let mut left: usize = 0;
378 let mut right: usize = 0;
379 let mut top: usize = 0;
380 let mut bottom: usize = 0;
381 ffi::cv_pixel_buffer_get_extended_pixels(
382 self.0,
383 &mut left,
384 &mut right,
385 &mut top,
386 &mut bottom,
387 );
388 (left, right, top, bottom)
389 }
390 }
391
392 #[must_use]
394 pub fn is_backed_by_io_surface(&self) -> bool {
395 self.io_surface().is_some()
396 }
397
398 #[must_use]
400 pub fn width(&self) -> usize {
401 unsafe { ffi::cv_pixel_buffer_get_width(self.0) }
402 }
403
404 #[must_use]
405 pub fn height(&self) -> usize {
406 unsafe { ffi::cv_pixel_buffer_get_height(self.0) }
407 }
408
409 #[must_use]
410 pub fn pixel_format(&self) -> u32 {
411 unsafe { ffi::cv_pixel_buffer_get_pixel_format_type(self.0) }
412 }
413
414 #[must_use]
415 pub fn bytes_per_row(&self) -> usize {
416 unsafe { ffi::cv_pixel_buffer_get_bytes_per_row(self.0) }
417 }
418
419 pub fn lock_raw(&self, flags: CVPixelBufferLockFlags) -> Result<(), i32> {
425 unsafe {
426 let result = ffi::cv_pixel_buffer_lock_base_address(self.0, flags.as_u32());
427 if result == 0 {
428 Ok(())
429 } else {
430 Err(result)
431 }
432 }
433 }
434
435 pub fn unlock_raw(&self, flags: CVPixelBufferLockFlags) -> Result<(), i32> {
441 unsafe {
442 let result = ffi::cv_pixel_buffer_unlock_base_address(self.0, flags.as_u32());
443 if result == 0 {
444 Ok(())
445 } else {
446 Err(result)
447 }
448 }
449 }
450
451 fn base_address_raw(&self) -> Option<*mut u8> {
456 unsafe {
457 let ptr = ffi::cv_pixel_buffer_get_base_address(self.0);
458 if ptr.is_null() {
459 None
460 } else {
461 Some(ptr.cast::<u8>())
462 }
463 }
464 }
465
466 #[must_use]
468 pub fn io_surface(&self) -> Option<IOSurface> {
469 unsafe {
470 let ptr = ffi::cv_pixel_buffer_get_io_surface(self.0);
471 IOSurface::from_raw(ptr)
472 }
473 }
474
475 pub fn lock(&self, flags: CVPixelBufferLockFlags) -> Result<CVPixelBufferLockGuard<'_>, i32> {
498 self.lock_raw(flags)?;
499 Ok(CVPixelBufferLockGuard {
500 buffer: self,
501 flags,
502 })
503 }
504
505 pub fn lock_read_only(&self) -> Result<CVPixelBufferLockGuard<'_>, i32> {
513 self.lock(CVPixelBufferLockFlags::READ_ONLY)
514 }
515
516 pub fn lock_read_write(&self) -> Result<CVPixelBufferLockGuard<'_>, i32> {
524 self.lock(CVPixelBufferLockFlags::NONE)
525 }
526}
527
528pub struct CVPixelBufferLockGuard<'a> {
530 buffer: &'a CVPixelBuffer,
531 flags: CVPixelBufferLockFlags,
532}
533
534impl CVPixelBufferLockGuard<'_> {
535 #[must_use]
537 pub fn base_address(&self) -> *const u8 {
538 self.buffer
539 .base_address_raw()
540 .unwrap_or(std::ptr::null_mut())
541 .cast_const()
542 }
543
544 pub fn base_address_mut(&mut self) -> Option<*mut u8> {
548 if self.flags.is_read_only() {
549 None
550 } else {
551 self.buffer.base_address_raw()
552 }
553 }
554
555 pub fn base_address_of_plane(&self, plane_index: usize) -> Option<*const u8> {
563 self.buffer
564 .base_address_of_plane_raw(plane_index)
565 .map(<*mut u8>::cast_const)
566 }
567
568 pub fn base_address_of_plane_mut(&mut self, plane_index: usize) -> Option<*mut u8> {
572 if self.flags.is_read_only() {
573 return None;
574 }
575 self.buffer.base_address_of_plane_raw(plane_index)
576 }
577
578 #[must_use]
580 pub fn width(&self) -> usize {
581 self.buffer.width()
582 }
583
584 #[must_use]
586 pub fn height(&self) -> usize {
587 self.buffer.height()
588 }
589
590 #[must_use]
592 pub fn bytes_per_row(&self) -> usize {
593 self.buffer.bytes_per_row()
594 }
595
596 #[must_use]
600 pub fn data_size(&self) -> usize {
601 self.buffer.data_size()
602 }
603
604 #[must_use]
606 pub fn plane_count(&self) -> usize {
607 self.buffer.plane_count()
608 }
609
610 #[must_use]
612 pub fn width_of_plane(&self, plane_index: usize) -> usize {
613 self.buffer.width_of_plane(plane_index)
614 }
615
616 #[must_use]
618 pub fn height_of_plane(&self, plane_index: usize) -> usize {
619 self.buffer.height_of_plane(plane_index)
620 }
621
622 #[must_use]
624 pub fn bytes_per_row_of_plane(&self, plane_index: usize) -> usize {
625 self.buffer.bytes_per_row_of_plane(plane_index)
626 }
627
628 #[must_use]
632 pub fn as_slice(&self) -> &[u8] {
633 let ptr = self.base_address();
634 let len = self.buffer.height() * self.buffer.bytes_per_row();
635 if ptr.is_null() || len == 0 {
636 &[]
637 } else {
638 unsafe { std::slice::from_raw_parts(ptr, len) }
639 }
640 }
641
642 pub fn as_slice_mut(&mut self) -> Option<&mut [u8]> {
646 let ptr = self.base_address_mut()?;
647 let len = self.buffer.height() * self.buffer.bytes_per_row();
648 if ptr.is_null() || len == 0 {
649 Some(&mut [])
650 } else {
651 Some(unsafe { std::slice::from_raw_parts_mut(ptr, len) })
652 }
653 }
654
655 #[must_use]
661 pub fn plane_data(&self, plane_index: usize) -> Option<&[u8]> {
662 let base = self.base_address_of_plane(plane_index)?;
663 let height = self.buffer.height_of_plane(plane_index);
664 let bytes_per_row = self.buffer.bytes_per_row_of_plane(plane_index);
665 Some(unsafe { std::slice::from_raw_parts(base, height * bytes_per_row) })
666 }
667
668 #[must_use]
672 pub fn plane_row(&self, plane_index: usize, row_index: usize) -> Option<&[u8]> {
673 if !self.buffer.is_planar() || plane_index >= self.buffer.plane_count() {
674 return None;
675 }
676 let height = self.buffer.height_of_plane(plane_index);
677 if row_index >= height {
678 return None;
679 }
680 let base = self.base_address_of_plane(plane_index)?;
681 let bytes_per_row = self.buffer.bytes_per_row_of_plane(plane_index);
682 Some(unsafe {
683 std::slice::from_raw_parts(base.add(row_index * bytes_per_row), bytes_per_row)
684 })
685 }
686
687 #[must_use]
691 pub fn row(&self, row_index: usize) -> Option<&[u8]> {
692 if row_index >= self.height() {
693 return None;
694 }
695 let ptr = self.base_address();
696 if ptr.is_null() {
697 return None;
698 }
699 unsafe {
700 let row_ptr = ptr.add(row_index * self.bytes_per_row());
701 Some(std::slice::from_raw_parts(row_ptr, self.bytes_per_row()))
702 }
703 }
704
705 #[must_use]
729 pub fn cursor(&self) -> io::Cursor<&[u8]> {
730 io::Cursor::new(self.as_slice())
731 }
732
733 #[must_use]
735 pub fn as_ptr(&self) -> *const u8 {
736 self.base_address()
737 }
738
739 pub fn as_mut_ptr(&mut self) -> Option<*mut u8> {
743 self.base_address_mut()
744 }
745
746 #[must_use]
748 pub const fn is_read_only(&self) -> bool {
749 self.flags.is_read_only()
750 }
751
752 #[must_use]
754 pub const fn options(&self) -> CVPixelBufferLockFlags {
755 self.flags
756 }
757
758 #[must_use]
760 pub fn pixel_format(&self) -> u32 {
761 self.buffer.pixel_format()
762 }
763}
764
765impl Drop for CVPixelBufferLockGuard<'_> {
766 fn drop(&mut self) {
767 let _ = self.buffer.unlock_raw(self.flags);
768 }
769}
770
771impl std::fmt::Debug for CVPixelBufferLockGuard<'_> {
772 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
773 f.debug_struct("CVPixelBufferLockGuard")
774 .field("flags", &self.flags)
775 .field("buffer_size", &(self.buffer.width(), self.buffer.height()))
776 .finish()
777 }
778}
779
780impl std::ops::Deref for CVPixelBufferLockGuard<'_> {
781 type Target = [u8];
782
783 fn deref(&self) -> &Self::Target {
784 self.as_slice()
785 }
786}
787
788impl Clone for CVPixelBuffer {
789 fn clone(&self) -> Self {
790 unsafe {
791 let ptr = ffi::cv_pixel_buffer_retain(self.0);
792 Self(ptr)
793 }
794 }
795}
796
797impl Drop for CVPixelBuffer {
798 fn drop(&mut self) {
799 unsafe {
800 ffi::cv_pixel_buffer_release(self.0);
801 }
802 }
803}
804
805unsafe impl Send for CVPixelBuffer {}
806unsafe impl Sync for CVPixelBuffer {}
807
808impl fmt::Display for CVPixelBuffer {
809 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810 write!(
811 f,
812 "CVPixelBuffer({}x{}, format: 0x{:08X})",
813 self.width(),
814 self.height(),
815 self.pixel_format()
816 )
817 }
818}
819
820#[repr(transparent)]
822#[derive(Debug)]
823pub struct CVPixelBufferPool(*mut std::ffi::c_void);
824
825impl PartialEq for CVPixelBufferPool {
826 fn eq(&self, other: &Self) -> bool {
827 self.0 == other.0
828 }
829}
830
831impl Eq for CVPixelBufferPool {}
832
833impl std::hash::Hash for CVPixelBufferPool {
834 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
835 unsafe {
836 let hash_value = ffi::cv_pixel_buffer_pool_hash(self.0);
837 hash_value.hash(state);
838 }
839 }
840}
841
842impl CVPixelBufferPool {
843 pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
844 if ptr.is_null() {
845 None
846 } else {
847 Some(Self(ptr))
848 }
849 }
850
851 pub const unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
854 Self(ptr)
855 }
856
857 #[must_use]
858 pub const fn as_ptr(&self) -> *mut std::ffi::c_void {
859 self.0
860 }
861
862 pub fn create(
875 width: usize,
876 height: usize,
877 pixel_format: u32,
878 max_buffers: usize,
879 ) -> Result<Self, i32> {
880 unsafe {
881 let mut pool_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
882 let status = ffi::cv_pixel_buffer_pool_create(
883 width,
884 height,
885 pixel_format,
886 max_buffers,
887 &mut pool_ptr,
888 );
889
890 if status == 0 && !pool_ptr.is_null() {
891 Ok(Self(pool_ptr))
892 } else {
893 Err(status)
894 }
895 }
896 }
897
898 pub fn create_pixel_buffer(&self) -> Result<CVPixelBuffer, i32> {
904 unsafe {
905 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
906 let status =
907 ffi::cv_pixel_buffer_pool_create_pixel_buffer(self.0, &mut pixel_buffer_ptr);
908
909 if status == 0 && !pixel_buffer_ptr.is_null() {
910 Ok(CVPixelBuffer(pixel_buffer_ptr))
911 } else {
912 Err(status)
913 }
914 }
915 }
916
917 pub fn flush(&self) {
921 unsafe {
922 ffi::cv_pixel_buffer_pool_flush(self.0);
923 }
924 }
925
926 #[must_use]
928 pub fn type_id() -> usize {
929 unsafe { ffi::cv_pixel_buffer_pool_get_type_id() }
930 }
931
932 pub fn create_pixel_buffer_with_aux_attributes(
940 &self,
941 aux_attributes: Option<&std::collections::HashMap<String, u32>>,
942 ) -> Result<CVPixelBuffer, i32> {
943 let _ = aux_attributes;
946 self.create_pixel_buffer()
947 }
948
949 #[must_use]
953 pub fn try_create_pixel_buffer(&self) -> Option<CVPixelBuffer> {
954 self.create_pixel_buffer().ok()
955 }
956
957 pub fn flush_with_options(&self, _flags: u32) {
961 self.flush();
964 }
965
966 #[must_use]
970 pub fn is_empty(&self) -> bool {
971 self.try_create_pixel_buffer().is_none()
972 }
973
974 #[must_use]
978 pub fn attributes(&self) -> Option<*const std::ffi::c_void> {
979 unsafe {
980 let ptr = ffi::cv_pixel_buffer_pool_get_attributes(self.0);
981 if ptr.is_null() {
982 None
983 } else {
984 Some(ptr)
985 }
986 }
987 }
988
989 #[must_use]
993 pub fn pixel_buffer_attributes(&self) -> Option<*const std::ffi::c_void> {
994 unsafe {
995 let ptr = ffi::cv_pixel_buffer_pool_get_pixel_buffer_attributes(self.0);
996 if ptr.is_null() {
997 None
998 } else {
999 Some(ptr)
1000 }
1001 }
1002 }
1003}
1004
1005impl Clone for CVPixelBufferPool {
1006 fn clone(&self) -> Self {
1007 unsafe {
1008 let ptr = ffi::cv_pixel_buffer_pool_retain(self.0);
1009 Self(ptr)
1010 }
1011 }
1012}
1013
1014impl Drop for CVPixelBufferPool {
1015 fn drop(&mut self) {
1016 unsafe {
1017 ffi::cv_pixel_buffer_pool_release(self.0);
1018 }
1019 }
1020}
1021
1022unsafe impl Send for CVPixelBufferPool {}
1023unsafe impl Sync for CVPixelBufferPool {}
1024
1025impl fmt::Display for CVPixelBufferPool {
1026 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1027 write!(f, "CVPixelBufferPool")
1028 }
1029}
1030
1031pub trait PixelBufferCursorExt {
1033 fn seek_to_pixel(&mut self, x: usize, y: usize, bytes_per_row: usize) -> io::Result<u64>;
1041
1042 fn read_pixel(&mut self) -> io::Result<[u8; 4]>;
1048}
1049
1050impl<T: AsRef<[u8]>> PixelBufferCursorExt for io::Cursor<T> {
1051 fn seek_to_pixel(&mut self, x: usize, y: usize, bytes_per_row: usize) -> io::Result<u64> {
1052 let pos = y * bytes_per_row + x * 4; self.seek(SeekFrom::Start(pos as u64))
1054 }
1055
1056 fn read_pixel(&mut self) -> io::Result<[u8; 4]> {
1057 let mut pixel = [0u8; 4];
1058 self.read_exact(&mut pixel)?;
1059 Ok(pixel)
1060 }
1061}