1use super::ffi;
4use super::IOSurface;
5use std::fmt;
6
7pub struct CVPixelBuffer(*mut std::ffi::c_void);
8
9impl PartialEq for CVPixelBuffer {
10 fn eq(&self, other: &Self) -> bool {
11 self.0 == other.0
12 }
13}
14
15impl Eq for CVPixelBuffer {}
16
17impl std::hash::Hash for CVPixelBuffer {
18 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
19 unsafe {
20 let hash_value = ffi::cv_pixel_buffer_hash(self.0);
21 hash_value.hash(state);
22 }
23 }
24}
25
26impl CVPixelBuffer {
27 pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
28 if ptr.is_null() {
29 None
30 } else {
31 Some(Self(ptr))
32 }
33 }
34
35 pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
38 Self(ptr)
39 }
40
41 pub fn as_ptr(&self) -> *mut std::ffi::c_void {
42 self.0
43 }
44
45 pub fn create(width: usize, height: usize, pixel_format: u32) -> Result<Self, i32> {
71 unsafe {
72 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
73 let status =
74 ffi::cv_pixel_buffer_create(width, height, pixel_format, &mut pixel_buffer_ptr);
75
76 if status == 0 && !pixel_buffer_ptr.is_null() {
77 Ok(Self(pixel_buffer_ptr))
78 } else {
79 Err(status)
80 }
81 }
82 }
83
84 pub unsafe fn create_with_bytes(
143 width: usize,
144 height: usize,
145 pixel_format: u32,
146 base_address: *mut std::ffi::c_void,
147 bytes_per_row: usize,
148 ) -> Result<Self, i32> {
149 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
150 let status = ffi::cv_pixel_buffer_create_with_bytes(
151 width,
152 height,
153 pixel_format,
154 base_address,
155 bytes_per_row,
156 &mut pixel_buffer_ptr,
157 );
158
159 if status == 0 && !pixel_buffer_ptr.is_null() {
160 Ok(Self(pixel_buffer_ptr))
161 } else {
162 Err(status)
163 }
164 }
165
166 pub fn fill_extended_pixels(&self) -> Result<(), i32> {
175 unsafe {
176 let status = ffi::cv_pixel_buffer_fill_extended_pixels(self.0);
177 if status == 0 {
178 Ok(())
179 } else {
180 Err(status)
181 }
182 }
183 }
184
185 pub unsafe fn create_with_planar_bytes(
198 width: usize,
199 height: usize,
200 pixel_format: u32,
201 plane_base_addresses: &[*mut std::ffi::c_void],
202 plane_widths: &[usize],
203 plane_heights: &[usize],
204 plane_bytes_per_row: &[usize],
205 ) -> Result<Self, i32> {
206 if plane_base_addresses.len() != plane_widths.len()
207 || plane_widths.len() != plane_heights.len()
208 || plane_heights.len() != plane_bytes_per_row.len()
209 {
210 return Err(-50); }
212
213 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
214 let status = ffi::cv_pixel_buffer_create_with_planar_bytes(
215 width,
216 height,
217 pixel_format,
218 plane_base_addresses.len(),
219 plane_base_addresses.as_ptr(),
220 plane_widths.as_ptr(),
221 plane_heights.as_ptr(),
222 plane_bytes_per_row.as_ptr(),
223 &mut pixel_buffer_ptr,
224 );
225
226 if status == 0 && !pixel_buffer_ptr.is_null() {
227 Ok(Self(pixel_buffer_ptr))
228 } else {
229 Err(status)
230 }
231 }
232
233 pub fn create_with_io_surface(surface: &IOSurface) -> Result<Self, i32> {
239 unsafe {
240 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
241 let status = ffi::cv_pixel_buffer_create_with_io_surface(
242 surface.as_ptr(),
243 &mut pixel_buffer_ptr,
244 );
245
246 if status == 0 && !pixel_buffer_ptr.is_null() {
247 Ok(Self(pixel_buffer_ptr))
248 } else {
249 Err(status)
250 }
251 }
252 }
253
254 pub fn get_type_id() -> usize {
256 unsafe { ffi::cv_pixel_buffer_get_type_id() }
257 }
258
259 pub fn get_data_size(&self) -> usize {
261 unsafe { ffi::cv_pixel_buffer_get_data_size(self.0) }
262 }
263
264 pub fn is_planar(&self) -> bool {
266 unsafe { ffi::cv_pixel_buffer_is_planar(self.0) }
267 }
268
269 pub fn get_plane_count(&self) -> usize {
271 unsafe { ffi::cv_pixel_buffer_get_plane_count(self.0) }
272 }
273
274 pub fn get_width_of_plane(&self, plane_index: usize) -> usize {
276 unsafe { ffi::cv_pixel_buffer_get_width_of_plane(self.0, plane_index) }
277 }
278
279 pub fn get_height_of_plane(&self, plane_index: usize) -> usize {
281 unsafe { ffi::cv_pixel_buffer_get_height_of_plane(self.0, plane_index) }
282 }
283
284 pub fn get_base_address_of_plane(&self, plane_index: usize) -> Option<*mut u8> {
286 unsafe {
287 let ptr = ffi::cv_pixel_buffer_get_base_address_of_plane(self.0, plane_index);
288 if ptr.is_null() {
289 None
290 } else {
291 Some(ptr.cast::<u8>())
292 }
293 }
294 }
295
296 pub fn get_bytes_per_row_of_plane(&self, plane_index: usize) -> usize {
298 unsafe { ffi::cv_pixel_buffer_get_bytes_per_row_of_plane(self.0, plane_index) }
299 }
300
301 pub fn get_extended_pixels(&self) -> (usize, usize, usize, usize) {
303 unsafe {
304 let mut left: usize = 0;
305 let mut right: usize = 0;
306 let mut top: usize = 0;
307 let mut bottom: usize = 0;
308 ffi::cv_pixel_buffer_get_extended_pixels(
309 self.0,
310 &mut left,
311 &mut right,
312 &mut top,
313 &mut bottom,
314 );
315 (left, right, top, bottom)
316 }
317 }
318
319 pub fn is_backed_by_io_surface(&self) -> bool {
321 self.get_io_surface().is_some()
322 }
323
324 pub fn get_width(&self) -> usize {
325 self.width()
326 }
327
328 pub fn get_height(&self) -> usize {
329 self.height()
330 }
331
332 pub fn get_pixel_format_type(&self) -> u32 {
333 self.pixel_format()
334 }
335
336 pub fn get_bytes_per_row(&self) -> usize {
337 self.bytes_per_row()
338 }
339
340 pub fn get_base_address(&self) -> Option<*mut u8> {
341 self.base_address()
342 }
343
344 pub fn get_iosurface(&self) -> Option<IOSurface> {
345 self.get_io_surface()
346 }
347
348 pub fn width(&self) -> usize {
349 unsafe { ffi::cv_pixel_buffer_get_width(self.0) }
350 }
351
352 pub fn height(&self) -> usize {
353 unsafe { ffi::cv_pixel_buffer_get_height(self.0) }
354 }
355
356 pub fn pixel_format(&self) -> u32 {
357 unsafe { ffi::cv_pixel_buffer_get_pixel_format_type(self.0) }
358 }
359
360 pub fn bytes_per_row(&self) -> usize {
361 unsafe { ffi::cv_pixel_buffer_get_bytes_per_row(self.0) }
362 }
363
364 pub fn lock_raw(&self, flags: u32) -> Result<(), i32> {
370 unsafe {
371 let result = ffi::cv_pixel_buffer_lock_base_address(self.0, flags);
372 if result == 0 {
373 Ok(())
374 } else {
375 Err(result)
376 }
377 }
378 }
379
380 pub fn unlock_raw(&self, flags: u32) -> Result<(), i32> {
386 unsafe {
387 let result = ffi::cv_pixel_buffer_unlock_base_address(self.0, flags);
388 if result == 0 {
389 Ok(())
390 } else {
391 Err(result)
392 }
393 }
394 }
395
396 pub fn base_address(&self) -> Option<*mut u8> {
397 unsafe {
398 let ptr = ffi::cv_pixel_buffer_get_base_address(self.0);
399 if ptr.is_null() {
400 None
401 } else {
402 Some(ptr.cast::<u8>())
403 }
404 }
405 }
406
407 pub fn get_io_surface(&self) -> Option<IOSurface> {
408 unsafe {
409 let ptr = ffi::cv_pixel_buffer_get_io_surface(self.0);
410 IOSurface::from_raw(ptr)
411 }
412 }
413
414 pub fn lock_base_address(&self, read_only: bool) -> Result<CVPixelBufferLockGuard<'_>, i32> {
420 let flags = u32::from(read_only);
421 self.lock_raw(flags)?;
422 Ok(CVPixelBufferLockGuard {
423 buffer: self,
424 read_only,
425 })
426 }
427}
428
429pub struct CVPixelBufferLockGuard<'a> {
431 buffer: &'a CVPixelBuffer,
432 read_only: bool,
433}
434
435impl CVPixelBufferLockGuard<'_> {
436 pub fn get_base_address(&self) -> *const u8 {
437 self.buffer
438 .base_address()
439 .unwrap_or(std::ptr::null_mut())
440 .cast_const()
441 }
442
443 pub fn get_base_address_mut(&mut self) -> *mut u8 {
444 if self.read_only {
445 std::ptr::null_mut()
446 } else {
447 self.buffer.base_address().unwrap_or(std::ptr::null_mut())
448 }
449 }
450}
451
452impl Drop for CVPixelBufferLockGuard<'_> {
453 fn drop(&mut self) {
454 let flags = u32::from(self.read_only);
455 let _ = self.buffer.unlock_raw(flags);
456 }
457}
458
459impl Clone for CVPixelBuffer {
460 fn clone(&self) -> Self {
461 unsafe {
462 let ptr = ffi::cv_pixel_buffer_retain(self.0);
463 Self(ptr)
464 }
465 }
466}
467
468impl Drop for CVPixelBuffer {
469 fn drop(&mut self) {
470 unsafe {
471 ffi::cv_pixel_buffer_release(self.0);
472 }
473 }
474}
475
476unsafe impl Send for CVPixelBuffer {}
477unsafe impl Sync for CVPixelBuffer {}
478
479impl fmt::Display for CVPixelBuffer {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 write!(
482 f,
483 "CVPixelBuffer({}x{}, format: 0x{:08X})",
484 self.width(),
485 self.height(),
486 self.pixel_format()
487 )
488 }
489}
490
491#[repr(transparent)]
493#[derive(Debug)]
494pub struct CVPixelBufferPool(*mut std::ffi::c_void);
495
496impl PartialEq for CVPixelBufferPool {
497 fn eq(&self, other: &Self) -> bool {
498 self.0 == other.0
499 }
500}
501
502impl Eq for CVPixelBufferPool {}
503
504impl std::hash::Hash for CVPixelBufferPool {
505 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
506 unsafe {
507 let hash_value = ffi::cv_pixel_buffer_pool_hash(self.0);
508 hash_value.hash(state);
509 }
510 }
511}
512
513impl CVPixelBufferPool {
514 pub fn from_raw(ptr: *mut std::ffi::c_void) -> Option<Self> {
515 if ptr.is_null() {
516 None
517 } else {
518 Some(Self(ptr))
519 }
520 }
521
522 pub unsafe fn from_ptr(ptr: *mut std::ffi::c_void) -> Self {
525 Self(ptr)
526 }
527
528 pub fn as_ptr(&self) -> *mut std::ffi::c_void {
529 self.0
530 }
531
532 pub fn create(
545 width: usize,
546 height: usize,
547 pixel_format: u32,
548 max_buffers: usize,
549 ) -> Result<Self, i32> {
550 unsafe {
551 let mut pool_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
552 let status = ffi::cv_pixel_buffer_pool_create(
553 width,
554 height,
555 pixel_format,
556 max_buffers,
557 &mut pool_ptr,
558 );
559
560 if status == 0 && !pool_ptr.is_null() {
561 Ok(Self(pool_ptr))
562 } else {
563 Err(status)
564 }
565 }
566 }
567
568 pub fn create_pixel_buffer(&self) -> Result<CVPixelBuffer, i32> {
574 unsafe {
575 let mut pixel_buffer_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
576 let status =
577 ffi::cv_pixel_buffer_pool_create_pixel_buffer(self.0, &mut pixel_buffer_ptr);
578
579 if status == 0 && !pixel_buffer_ptr.is_null() {
580 Ok(CVPixelBuffer(pixel_buffer_ptr))
581 } else {
582 Err(status)
583 }
584 }
585 }
586
587 pub fn flush(&self) {
591 unsafe {
592 ffi::cv_pixel_buffer_pool_flush(self.0);
593 }
594 }
595
596 pub fn get_type_id() -> usize {
598 unsafe { ffi::cv_pixel_buffer_pool_get_type_id() }
599 }
600
601 pub fn create_pixel_buffer_with_aux_attributes(
609 &self,
610 aux_attributes: Option<&std::collections::HashMap<String, u32>>,
611 ) -> Result<CVPixelBuffer, i32> {
612 let _ = aux_attributes;
615 self.create_pixel_buffer()
616 }
617
618 pub fn try_create_pixel_buffer(&self) -> Option<CVPixelBuffer> {
622 self.create_pixel_buffer().ok()
623 }
624
625 pub fn flush_with_options(&self, _flags: u32) {
629 self.flush();
632 }
633
634 pub fn is_empty(&self) -> bool {
638 self.try_create_pixel_buffer().is_none()
639 }
640
641 pub fn get_attributes(&self) -> Option<*const std::ffi::c_void> {
645 unsafe {
646 let ptr = ffi::cv_pixel_buffer_pool_get_attributes(self.0);
647 if ptr.is_null() {
648 None
649 } else {
650 Some(ptr)
651 }
652 }
653 }
654
655 pub fn get_pixel_buffer_attributes(&self) -> Option<*const std::ffi::c_void> {
659 unsafe {
660 let ptr = ffi::cv_pixel_buffer_pool_get_pixel_buffer_attributes(self.0);
661 if ptr.is_null() {
662 None
663 } else {
664 Some(ptr)
665 }
666 }
667 }
668}
669
670impl Clone for CVPixelBufferPool {
671 fn clone(&self) -> Self {
672 unsafe {
673 let ptr = ffi::cv_pixel_buffer_pool_retain(self.0);
674 Self(ptr)
675 }
676 }
677}
678
679impl Drop for CVPixelBufferPool {
680 fn drop(&mut self) {
681 unsafe {
682 ffi::cv_pixel_buffer_pool_release(self.0);
683 }
684 }
685}
686
687unsafe impl Send for CVPixelBufferPool {}
688unsafe impl Sync for CVPixelBufferPool {}
689
690impl fmt::Display for CVPixelBufferPool {
691 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692 write!(f, "CVPixelBufferPool")
693 }
694}