nokhwa_bindings_macos/
lib.rs

1/*
2* Copyright 2022 l1npengtul <l1npengtul@protonmail.com> / The Nokhwa Contributors
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8*     http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15*/
16
17// hello, future peng here
18// whatever is written here will induce horrors uncomprehendable.
19// save yourselves. write apple code in swift and bind it to rust.
20
21// <some change so we can call this 0.10.4>
22
23#![allow(clippy::not_unsafe_ptr_arg_deref)]
24
25#[cfg(any(target_os = "macos", target_os = "ios"))]
26#[macro_use]
27extern crate objc;
28
29#[cfg(any(target_os = "macos", target_os = "ios"))]
30mod internal {
31
32    #[allow(non_snake_case)]
33    pub mod core_media {
34        // all of this is stolen from bindgen
35        // steal it idc
36        use crate::internal::CGFloat;
37        use core_media_sys::{
38            CMBlockBufferRef, CMFormatDescriptionRef, CMSampleBufferRef, CMTime, CMVideoDimensions,
39            FourCharCode,
40        };
41        use objc::{runtime::Object, Message};
42        use std::ops::Deref;
43
44        pub type Id = *mut Object;
45
46        #[repr(transparent)]
47        #[derive(Clone)]
48        pub struct NSObject(pub Id);
49        impl Deref for NSObject {
50            type Target = Object;
51            fn deref(&self) -> &Self::Target {
52                unsafe { &*self.0 }
53            }
54        }
55        unsafe impl Message for NSObject {}
56        impl NSObject {
57            pub fn alloc() -> Self {
58                Self(unsafe { msg_send!(objc::class!(NSObject), alloc) })
59            }
60        }
61
62        #[repr(transparent)]
63        #[derive(Clone)]
64        pub struct NSString(pub Id);
65        impl Deref for NSString {
66            type Target = Object;
67            fn deref(&self) -> &Self::Target {
68                unsafe { &*self.0 }
69            }
70        }
71        unsafe impl Message for NSString {}
72        impl NSString {
73            pub fn alloc() -> Self {
74                Self(unsafe { msg_send!(objc::class!(NSString), alloc) })
75            }
76        }
77
78        pub type AVMediaType = NSString;
79
80        #[allow(non_snake_case)]
81        #[link(name = "CoreMedia", kind = "framework")]
82        extern "C" {
83            pub fn CMVideoFormatDescriptionGetDimensions(
84                videoDesc: CMFormatDescriptionRef,
85            ) -> CMVideoDimensions;
86
87            pub fn CMTimeMake(value: i64, scale: i32) -> CMTime;
88
89            pub fn CMBlockBufferGetDataLength(theBuffer: CMBlockBufferRef) -> std::os::raw::c_int;
90
91            pub fn CMBlockBufferCopyDataBytes(
92                theSourceBuffer: CMBlockBufferRef,
93                offsetToData: usize,
94                dataLength: usize,
95                destination: *mut std::os::raw::c_void,
96            ) -> std::os::raw::c_int;
97
98            pub fn CMSampleBufferGetDataBuffer(sbuf: CMSampleBufferRef) -> CMBlockBufferRef;
99
100            pub fn dispatch_queue_create(
101                label: *const std::os::raw::c_char,
102                attr: NSObject,
103            ) -> NSObject;
104
105            pub fn dispatch_release(object: NSObject);
106
107            pub fn CMSampleBufferGetImageBuffer(sbuf: CMSampleBufferRef) -> CVImageBufferRef;
108
109            pub fn CVPixelBufferLockBaseAddress(
110                pixelBuffer: CVPixelBufferRef,
111                lockFlags: CVPixelBufferLockFlags,
112            ) -> CVReturn;
113
114            pub fn CVPixelBufferUnlockBaseAddress(
115                pixelBuffer: CVPixelBufferRef,
116                unlockFlags: CVPixelBufferLockFlags,
117            ) -> CVReturn;
118
119            pub fn CVPixelBufferGetDataSize(pixelBuffer: CVPixelBufferRef)
120                -> std::os::raw::c_ulong;
121
122            pub fn CVPixelBufferGetBaseAddress(
123                pixelBuffer: CVPixelBufferRef,
124            ) -> *mut std::os::raw::c_void;
125
126            pub fn CVPixelBufferGetPixelFormatType(pixelBuffer: CVPixelBufferRef) -> OSType;
127        }
128
129        #[repr(C)]
130        #[derive(Clone, Debug, PartialEq, PartialOrd)]
131        pub struct CGPoint {
132            pub x: CGFloat,
133            pub y: CGFloat,
134        }
135
136        #[repr(C)]
137        #[derive(Debug, Copy, Clone)]
138        pub struct __CVBuffer {
139            _unused: [u8; 0],
140        }
141
142        #[allow(non_snake_case)]
143        #[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
144        #[repr(C)]
145        pub struct AVCaptureWhiteBalanceGains {
146            pub blueGain: f32,
147            pub greenGain: f32,
148            pub redGain: f32,
149        }
150
151        pub type CVBufferRef = *mut __CVBuffer;
152
153        pub type CVImageBufferRef = CVBufferRef;
154        pub type CVPixelBufferRef = CVImageBufferRef;
155        pub type CVPixelBufferLockFlags = u64;
156        pub type CVReturn = i32;
157
158        pub type OSType = FourCharCode;
159        pub type AVVideoCodecType = NSString;
160
161        #[link(name = "AVFoundation", kind = "framework")]
162        extern "C" {
163            pub static AVVideoCodecKey: NSString;
164            pub static AVVideoCodecTypeHEVC: AVVideoCodecType;
165            pub static AVVideoCodecTypeH264: AVVideoCodecType;
166            pub static AVVideoCodecTypeJPEG: AVVideoCodecType;
167            pub static AVVideoCodecTypeAppleProRes4444: AVVideoCodecType;
168            pub static AVVideoCodecTypeAppleProRes422: AVVideoCodecType;
169            pub static AVVideoCodecTypeAppleProRes422HQ: AVVideoCodecType;
170            pub static AVVideoCodecTypeAppleProRes422LT: AVVideoCodecType;
171            pub static AVVideoCodecTypeAppleProRes422Proxy: AVVideoCodecType;
172            pub static AVVideoCodecTypeHEVCWithAlpha: AVVideoCodecType;
173            pub static AVVideoCodecHEVC: NSString;
174            pub static AVVideoCodecH264: NSString;
175            pub static AVVideoCodecJPEG: NSString;
176            pub static AVVideoCodecAppleProRes4444: NSString;
177            pub static AVVideoCodecAppleProRes422: NSString;
178            pub static AVVideoWidthKey: NSString;
179            pub static AVVideoHeightKey: NSString;
180            pub static AVVideoExpectedSourceFrameRateKey: NSString;
181
182            pub static AVMediaTypeVideo: AVMediaType;
183            pub static AVMediaTypeAudio: AVMediaType;
184            pub static AVMediaTypeText: AVMediaType;
185            pub static AVMediaTypeClosedCaption: AVMediaType;
186            pub static AVMediaTypeSubtitle: AVMediaType;
187            pub static AVMediaTypeTimecode: AVMediaType;
188            pub static AVMediaTypeMetadata: AVMediaType;
189            pub static AVMediaTypeMuxed: AVMediaType;
190            pub static AVMediaTypeMetadataObject: AVMediaType;
191            pub static AVMediaTypeDepthData: AVMediaType;
192
193            pub static AVCaptureLensPositionCurrent: f32;
194            pub static AVCaptureExposureTargetBiasCurrent: f32;
195            pub static AVCaptureExposureDurationCurrent: CMTime;
196            pub static AVCaptureISOCurrent: f32;
197        }
198    }
199
200    use crate::core_media::{
201        dispatch_queue_create, AVCaptureExposureDurationCurrent,
202        AVCaptureExposureTargetBiasCurrent, AVCaptureISOCurrent, AVCaptureWhiteBalanceGains,
203        AVMediaTypeAudio, AVMediaTypeClosedCaption, AVMediaTypeDepthData, AVMediaTypeMetadata,
204        AVMediaTypeMetadataObject, AVMediaTypeMuxed, AVMediaTypeSubtitle, AVMediaTypeText,
205        AVMediaTypeTimecode, AVMediaTypeVideo, CGPoint, CMSampleBufferGetImageBuffer,
206        CMVideoFormatDescriptionGetDimensions, CVImageBufferRef, CVPixelBufferGetBaseAddress,
207        CVPixelBufferGetDataSize, CVPixelBufferLockBaseAddress, CVPixelBufferUnlockBaseAddress,
208        NSObject, OSType,
209    };
210
211    use block::ConcreteBlock;
212    use cocoa_foundation::{
213        base::Nil,
214        foundation::{NSArray, NSDictionary, NSInteger, NSString, NSUInteger},
215    };
216    use core_media_sys::{
217        kCMPixelFormat_24RGB, kCMPixelFormat_422YpCbCr8_yuvs,
218        kCMPixelFormat_8IndexedGray_WhiteIsZero, kCMVideoCodecType_422YpCbCr8,
219        kCMVideoCodecType_JPEG, kCMVideoCodecType_JPEG_OpenDML, CMFormatDescriptionGetMediaSubType,
220        CMFormatDescriptionRef, CMSampleBufferRef, CMTime, CMVideoDimensions,
221    };
222    use core_video_sys::{
223        kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange,
224        kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
225        kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
226    };
227    use flume::{Receiver, Sender};
228    use nokhwa_core::{
229        error::NokhwaError,
230        types::{
231            ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo,
232            ControlValueDescription, ControlValueSetter, FrameFormat, KnownCameraControl,
233            KnownCameraControlFlag, Resolution,
234        },
235    };
236    use objc::runtime::objc_getClass;
237    use objc::{
238        declare::ClassDecl,
239        runtime::{Class, Object, Protocol, Sel, BOOL, NO, YES},
240    };
241    use once_cell::sync::Lazy;
242    use std::ffi::CString;
243    use std::{
244        borrow::Cow,
245        cmp::Ordering,
246        collections::BTreeMap,
247        convert::TryFrom,
248        error::Error,
249        ffi::{c_float, c_void, CStr},
250        sync::Arc,
251    };
252
253    const UTF8_ENCODING: usize = 4;
254    type CGFloat = c_float;
255
256    macro_rules! create_boilerplate_impl {
257        {
258            $( [$class_vis:vis $class_name:ident : $( {$field_vis:vis $field_name:ident : $field_type:ty} ),*] ),+
259        } => {
260            $(
261                $class_vis struct $class_name {
262                    inner: *mut Object,
263                    $(
264                        $field_vis $field_name : $field_type
265                    )*
266                }
267
268                impl $class_name {
269                    pub fn inner(&self) -> *mut Object {
270                        self.inner
271                    }
272                }
273            )+
274        };
275
276        {
277            $( [$class_vis:vis $class_name:ident ] ),+
278        } => {
279            $(
280                $class_vis struct $class_name {
281                    inner: *mut Object,
282                }
283
284                impl $class_name {
285                    pub fn inner(&self) -> *mut Object {
286                        self.inner
287                    }
288                }
289
290                impl From<*mut Object> for $class_name {
291                    fn from(obj: *mut Object) -> Self {
292                        $class_name {
293                            inner: obj,
294                        }
295                    }
296                }
297            )+
298        };
299    }
300
301    fn str_to_nsstr(string: &str) -> *mut Object {
302        let cls = class!(NSString);
303        let bytes = string.as_ptr() as *const c_void;
304        unsafe {
305            let obj: *mut Object = msg_send![cls, alloc];
306            let obj: *mut Object = msg_send![
307                obj,
308                initWithBytes:bytes
309                length:string.len()
310                encoding:UTF8_ENCODING
311            ];
312            obj
313        }
314    }
315
316    fn nsstr_to_str<'a>(nsstr: *mut Object) -> Cow<'a, str> {
317        let data = unsafe { CStr::from_ptr(nsstr.UTF8String()) };
318        data.to_string_lossy()
319    }
320
321    fn vec_to_ns_arr<T: Into<*mut Object>>(data: Vec<T>) -> *mut Object {
322        let cstr = CString::new("NSMutableArray").unwrap();
323        let ns_arr_cls = unsafe { objc_getClass(cstr.as_ptr()) };
324        let mutable_array: *mut Object = unsafe { msg_send![ns_arr_cls, array] };
325        data.into_iter().for_each(|item| {
326            let item_obj: *mut Object = item.into();
327            let _: () = unsafe { msg_send![mutable_array, addObject: item_obj] };
328        });
329        mutable_array
330    }
331
332    fn ns_arr_to_vec<T: From<*mut Object>>(data: *mut Object) -> Vec<T> {
333        let length = unsafe { NSArray::count(data) };
334
335        let mut out_vec: Vec<T> = Vec::with_capacity(length as usize);
336        for index in 0..length {
337            let item = unsafe { NSArray::objectAtIndex(data, index) };
338            out_vec.push(T::from(item));
339        }
340        out_vec
341    }
342
343    fn try_ns_arr_to_vec<T, TE>(data: *mut Object) -> Result<Vec<T>, TE>
344    where
345        TE: Error,
346        T: TryFrom<*mut Object, Error = TE>,
347    {
348        let length = unsafe { NSArray::count(data) };
349
350        let mut out_vec: Vec<T> = Vec::with_capacity(length as usize);
351        for index in 0..length {
352            let item = unsafe { NSArray::objectAtIndex(data, index) };
353            out_vec.push(T::try_from(item)?);
354        }
355        Ok(out_vec)
356    }
357
358    fn compare_ns_string(this: *mut Object, other: core_media::NSString) -> bool {
359        unsafe {
360            let equal: BOOL = msg_send![this, isEqualToString: other];
361            equal == YES
362        }
363    }
364
365    #[allow(non_upper_case_globals)]
366    fn raw_fcc_to_frameformat(raw: OSType) -> Option<FrameFormat> {
367        match raw {
368            kCMVideoCodecType_422YpCbCr8 | kCMPixelFormat_422YpCbCr8_yuvs => {
369                Some(FrameFormat::YUYV)
370            }
371            kCMVideoCodecType_JPEG | kCMVideoCodecType_JPEG_OpenDML => Some(FrameFormat::MJPEG),
372            kCMPixelFormat_8IndexedGray_WhiteIsZero => Some(FrameFormat::GRAY),
373            kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange
374            | kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
375            | kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange => Some(FrameFormat::YUYV),
376            kCMPixelFormat_24RGB => Some(FrameFormat::RAWRGB),
377            _ => None,
378        }
379    }
380
381    pub type CompressionData<'a> = (Cow<'a, [u8]>, FrameFormat);
382    pub type DataPipe<'a> = (Sender<CompressionData<'a>>, Receiver<CompressionData<'a>>);
383
384    static CALLBACK_CLASS: Lazy<&'static Class> = Lazy::new(|| {
385        {
386            let mut decl = ClassDecl::new("MyCaptureCallback", class!(NSObject)).unwrap();
387
388            // frame stack
389            // oooh scary provenannce-breaking BULLSHIT AAAAAA I LOVE TYPE ERASURE
390            decl.add_ivar::<*const c_void>("_arcmutptr"); // ArkMutex, the not-arknights totally not gacha totally not ripoff new vidya game from l-pleasestop-npengtul
391
392            extern "C" fn my_callback_get_arcmutptr(this: &Object, _: Sel) -> *const c_void {
393                unsafe { *this.get_ivar("_arcmutptr") }
394            }
395            extern "C" fn my_callback_set_arcmutptr(
396                this: &mut Object,
397                _: Sel,
398                new_arcmutptr: *const c_void,
399            ) {
400                unsafe {
401                    this.set_ivar("_arcmutptr", new_arcmutptr);
402                }
403            }
404
405            // Delegate compliance method
406            // SAFETY: This assumes that the buffer byte size is a u8. Any other size will cause unsafety.
407            #[allow(non_snake_case)]
408            #[allow(non_upper_case_globals)]
409            extern "C" fn capture_out_callback(
410                this: &mut Object,
411                _: Sel,
412                _: *mut Object,
413                didOutputSampleBuffer: CMSampleBufferRef,
414                _: *mut Object,
415            ) {
416                let image_buffer: CVImageBufferRef =
417                    unsafe { CMSampleBufferGetImageBuffer(didOutputSampleBuffer) };
418                unsafe {
419                    CVPixelBufferLockBaseAddress(image_buffer, 0);
420                };
421
422                let buffer_length = unsafe { CVPixelBufferGetDataSize(image_buffer) };
423                let buffer_ptr = unsafe { CVPixelBufferGetBaseAddress(image_buffer) };
424                let buffer_as_vec = unsafe {
425                    std::slice::from_raw_parts_mut(buffer_ptr as *mut u8, buffer_length as usize)
426                        .to_vec()
427                };
428
429                unsafe { CVPixelBufferUnlockBaseAddress(image_buffer, 0) };
430                // oooooh scarey unsafe
431                // AAAAAAAAAAAAAAAAAAAAAAAAA
432                // https://c.tenor.com/0e_zWtFLOzQAAAAC/needy-streamer-overload-needy-girl-overdose.gif
433                let bufferlck_cv: *const c_void = unsafe { msg_send![this, bufferPtr] };
434                let buffer_sndr = unsafe {
435                    let ptr = bufferlck_cv.cast::<Sender<(Vec<u8>, FrameFormat)>>();
436                    Arc::from_raw(ptr)
437                };
438                if let Err(_) = buffer_sndr.send((buffer_as_vec, FrameFormat::GRAY)) {
439                    // FIXME: dont, what the fuck???
440                    return;
441                }
442                std::mem::forget(buffer_sndr);
443            }
444
445            #[allow(non_snake_case)]
446            extern "C" fn capture_drop_callback(
447                _: &mut Object,
448                _: Sel,
449                _: *mut Object,
450                _: *mut Object,
451                _: *mut Object,
452            ) {
453            }
454
455            unsafe {
456                decl.add_method(
457                    sel!(bufferPtr),
458                    my_callback_get_arcmutptr as extern "C" fn(&Object, Sel) -> *const c_void,
459                );
460                decl.add_method(
461                    sel!(SetBufferPtr:),
462                    my_callback_set_arcmutptr as extern "C" fn(&mut Object, Sel, *const c_void),
463                );
464                decl.add_method(
465                    sel!(captureOutput:didOutputSampleBuffer:fromConnection:),
466                    capture_out_callback
467                        as extern "C" fn(
468                            &mut Object,
469                            Sel,
470                            *mut Object,
471                            CMSampleBufferRef,
472                            *mut Object,
473                        ),
474                );
475                decl.add_method(
476                    sel!(captureOutput:didDropSampleBuffer:fromConnection:),
477                    capture_drop_callback
478                        as extern "C" fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object),
479                );
480
481                decl.add_protocol(
482                    Protocol::get("AVCaptureVideoDataOutputSampleBufferDelegate").unwrap(),
483                );
484            }
485
486            decl.register()
487        }
488    });
489
490    pub fn request_permission_with_callback(callback: impl Fn(bool) + Send + Sync + 'static) {
491        let cls = class!(AVCaptureDevice);
492
493        let wrapper = move |bool: BOOL| {
494            callback(bool == YES);
495        };
496
497        let objc_fn_block: ConcreteBlock<(BOOL,), (), _> = ConcreteBlock::new(wrapper);
498        let objc_fn_pass = objc_fn_block.copy();
499
500        unsafe {
501            let _: () = msg_send![cls, requestAccessForMediaType:(AVMediaTypeVideo.clone()) completionHandler:objc_fn_pass];
502        }
503    }
504
505    pub fn current_authorization_status() -> AVAuthorizationStatus {
506        let cls = class!(AVCaptureDevice);
507        let status: AVAuthorizationStatus = unsafe {
508            msg_send![cls, authorizationStatusForMediaType:AVMediaType::Video.into_ns_str()]
509        };
510        status
511    }
512
513    // fuck it, use deprecated APIs
514    pub fn query_avfoundation() -> Result<Vec<CameraInfo>, NokhwaError> {
515        Ok(AVCaptureDeviceDiscoverySession::new(vec![
516            AVCaptureDeviceType::UltraWide,
517            AVCaptureDeviceType::WideAngle,
518            AVCaptureDeviceType::Telephoto,
519            AVCaptureDeviceType::TrueDepth,
520            AVCaptureDeviceType::External,
521        ])?
522        .devices())
523    }
524
525    pub fn get_raw_device_info(index: CameraIndex, device: *mut Object) -> CameraInfo {
526        let name = nsstr_to_str(unsafe { msg_send![device, localizedName] });
527        let manufacturer = nsstr_to_str(unsafe { msg_send![device, manufacturer] });
528        let position: AVCaptureDevicePosition = unsafe { msg_send![device, position] };
529        let lens_aperture: f64 = unsafe { msg_send![device, lensAperture] };
530        let device_type = nsstr_to_str(unsafe { msg_send![device, deviceType] });
531        let model_id = nsstr_to_str(unsafe { msg_send![device, modelID] });
532        let description = format!(
533            "{}: {} - {}, {:?} f{}",
534            manufacturer, model_id, device_type, position, lens_aperture
535        );
536        let misc = nsstr_to_str(unsafe { msg_send![device, uniqueID] });
537
538        CameraInfo::new(name.as_ref(), &description, misc.as_ref(), index)
539    }
540
541    #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
542    pub enum AVCaptureDeviceType {
543        Dual,
544        DualWide,
545        Triple,
546        WideAngle,
547        UltraWide,
548        Telephoto,
549        TrueDepth,
550        External,
551    }
552
553    impl From<AVCaptureDeviceType> for *mut Object {
554        fn from(device_type: AVCaptureDeviceType) -> Self {
555            match device_type {
556                AVCaptureDeviceType::Dual => str_to_nsstr("AVCaptureDeviceTypeBuiltInDualCamera"),
557                AVCaptureDeviceType::DualWide => {
558                    str_to_nsstr("AVCaptureDeviceTypeBuiltInDualWideCamera")
559                }
560                AVCaptureDeviceType::Triple => {
561                    str_to_nsstr("AVCaptureDeviceTypeBuiltInTripleCamera")
562                }
563                AVCaptureDeviceType::WideAngle => {
564                    str_to_nsstr("AVCaptureDeviceTypeBuiltInWideAngleCamera")
565                }
566                AVCaptureDeviceType::UltraWide => {
567                    str_to_nsstr("AVCaptureDeviceTypeBuiltInUltraWideCamera")
568                }
569                AVCaptureDeviceType::Telephoto => {
570                    str_to_nsstr("AVCaptureDeviceTypeBuiltInTelephotoCamera")
571                }
572                AVCaptureDeviceType::TrueDepth => {
573                    str_to_nsstr("AVCaptureDeviceTypeBuiltInTrueDepthCamera")
574                }
575                AVCaptureDeviceType::External => str_to_nsstr("AVCaptureDeviceTypeExternal"),
576            }
577        }
578    }
579
580    impl AVCaptureDeviceType {
581        pub fn into_ns_str(self) -> *mut Object {
582            <*mut Object>::from(self)
583        }
584    }
585
586    #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
587    pub enum AVMediaType {
588        Audio,
589        ClosedCaption,
590        DepthData,
591        Metadata,
592        MetadataObject,
593        Muxed,
594        Subtitle,
595        Text,
596        Timecode,
597        Video,
598    }
599
600    impl From<AVMediaType> for *mut Object {
601        fn from(media_type: AVMediaType) -> Self {
602            match media_type {
603                AVMediaType::Audio => unsafe { AVMediaTypeAudio.0 },
604                AVMediaType::ClosedCaption => unsafe { AVMediaTypeClosedCaption.0 },
605                AVMediaType::DepthData => unsafe { AVMediaTypeDepthData.0 },
606                AVMediaType::Metadata => unsafe { AVMediaTypeMetadata.0 },
607                AVMediaType::MetadataObject => unsafe { AVMediaTypeMetadataObject.0 },
608                AVMediaType::Muxed => unsafe { AVMediaTypeMuxed.0 },
609                AVMediaType::Subtitle => unsafe { AVMediaTypeSubtitle.0 },
610                AVMediaType::Text => unsafe { AVMediaTypeText.0 },
611                AVMediaType::Timecode => unsafe { AVMediaTypeTimecode.0 },
612                AVMediaType::Video => unsafe { AVMediaTypeVideo.0 },
613            }
614        }
615    }
616
617    impl TryFrom<*mut Object> for AVMediaType {
618        type Error = NokhwaError;
619
620        fn try_from(value: *mut Object) -> Result<Self, Self::Error> {
621            unsafe {
622                if compare_ns_string(value, (AVMediaTypeAudio).clone()) {
623                    Ok(AVMediaType::Audio)
624                } else if compare_ns_string(value, (AVMediaTypeClosedCaption).clone()) {
625                    Ok(AVMediaType::ClosedCaption)
626                } else if compare_ns_string(value, (AVMediaTypeDepthData).clone()) {
627                    Ok(AVMediaType::DepthData)
628                } else if compare_ns_string(value, (AVMediaTypeMetadata).clone()) {
629                    Ok(AVMediaType::Metadata)
630                } else if compare_ns_string(value, (AVMediaTypeMetadataObject).clone()) {
631                    Ok(AVMediaType::MetadataObject)
632                } else if compare_ns_string(value, (AVMediaTypeMuxed).clone()) {
633                    Ok(AVMediaType::Muxed)
634                } else if compare_ns_string(value, (AVMediaTypeSubtitle).clone()) {
635                    Ok(AVMediaType::Subtitle)
636                } else if compare_ns_string(value, (AVMediaTypeText).clone()) {
637                    Ok(AVMediaType::Text)
638                } else if compare_ns_string(value, (AVMediaTypeTimecode).clone()) {
639                    Ok(AVMediaType::Timecode)
640                } else if compare_ns_string(value, (AVMediaTypeVideo).clone()) {
641                    Ok(AVMediaType::Video)
642                } else {
643                    let name = nsstr_to_str(value);
644                    Err(NokhwaError::GetPropertyError {
645                        property: "AVMediaType".to_string(),
646                        error: format!("Invalid AVMediaType {name}"),
647                    })
648                }
649            }
650        }
651    }
652
653    impl AVMediaType {
654        pub fn into_ns_str(self) -> *mut Object {
655            <*mut Object>::from(self)
656        }
657    }
658
659    #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
660    #[repr(isize)]
661    pub enum AVCaptureDevicePosition {
662        Unspecified = 0,
663        Back = 1,
664        Front = 2,
665    }
666
667    #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
668    #[repr(isize)]
669    pub enum AVAuthorizationStatus {
670        NotDetermined = 0,
671        Restricted = 1,
672        Denied = 2,
673        Authorized = 3,
674    }
675
676    pub struct AVCaptureVideoCallback {
677        delegate: *mut Object,
678        queue: NSObject,
679    }
680
681    impl AVCaptureVideoCallback {
682        pub fn new(
683            device_spec: &CStr,
684            buffer: &Arc<Sender<(Vec<u8>, FrameFormat)>>,
685        ) -> Result<Self, NokhwaError> {
686            let cls = &CALLBACK_CLASS as &Class;
687            let delegate: *mut Object = unsafe { msg_send![cls, alloc] };
688            let delegate: *mut Object = unsafe { msg_send![delegate, init] };
689            let buffer_as_ptr = {
690                let arc_raw = Arc::as_ptr(buffer);
691                arc_raw.cast::<c_void>()
692            };
693            unsafe {
694                let _: () = msg_send![delegate, SetBufferPtr: buffer_as_ptr];
695            }
696
697            let queue = unsafe {
698                dispatch_queue_create(device_spec.as_ptr(), NSObject(std::ptr::null_mut()))
699            };
700
701            Ok(AVCaptureVideoCallback { delegate, queue })
702        }
703
704        pub fn data_len(&self) -> usize {
705            unsafe { msg_send![self.delegate, dataLength] }
706        }
707
708        pub fn inner(&self) -> *mut Object {
709            self.delegate
710        }
711
712        pub fn queue(&self) -> &NSObject {
713            &self.queue
714        }
715    }
716
717    create_boilerplate_impl! {
718        [pub AVFrameRateRange],
719        [pub AVCaptureDeviceDiscoverySession],
720        [pub AVCaptureDeviceInput],
721        [pub AVCaptureSession]
722    }
723
724    impl AVFrameRateRange {
725        pub fn max(&self) -> f64 {
726            unsafe { msg_send![self.inner, maxFrameRate] }
727        }
728
729        pub fn min(&self) -> f64 {
730            unsafe { msg_send![self.inner, minFrameRate] }
731        }
732    }
733
734    #[derive(Debug)]
735    pub struct AVCaptureDeviceFormat {
736        pub(crate) internal: *mut Object,
737        pub resolution: CMVideoDimensions,
738        pub fps_list: Vec<f64>,
739        pub fourcc: FrameFormat,
740    }
741
742    impl TryFrom<*mut Object> for AVCaptureDeviceFormat {
743        type Error = NokhwaError;
744
745        fn try_from(value: *mut Object) -> Result<Self, Self::Error> {
746            let media_type_raw: *mut Object = unsafe { msg_send![value, mediaType] };
747            let media_type = AVMediaType::try_from(media_type_raw)?;
748            if media_type != AVMediaType::Video {
749                return Err(NokhwaError::StructureError {
750                    structure: "AVMediaType".to_string(),
751                    error: "Not Video".to_string(),
752                });
753            }
754            let mut fps_list = ns_arr_to_vec::<AVFrameRateRange>(unsafe {
755                msg_send![value, videoSupportedFrameRateRanges]
756            })
757            .into_iter()
758            .flat_map(|v| {
759                if v.min() != 0_f64 && v.min() != 1_f64 {
760                    vec![v.min(), v.max()]
761                } else {
762                    vec![v.max()] // this gets deduped!
763                }
764            })
765            .collect::<Vec<f64>>();
766            fps_list.sort_by(|n, m| n.partial_cmp(m).unwrap_or(Ordering::Equal));
767            fps_list.dedup();
768            let description_obj: *mut Object = unsafe { msg_send![value, formatDescription] };
769            let resolution =
770                unsafe { CMVideoFormatDescriptionGetDimensions(description_obj as *mut c_void) };
771            let fcc_raw =
772                unsafe { CMFormatDescriptionGetMediaSubType(description_obj as *mut c_void) };
773            #[allow(non_upper_case_globals)]
774            let fourcc = match raw_fcc_to_frameformat(fcc_raw) {
775                Some(fcc) => fcc,
776                None => {
777                    return Err(NokhwaError::StructureError {
778                        structure: "FourCharCode".to_string(),
779                        error: format!("Unknown FourCharCode {fcc_raw:?}"),
780                    })
781                }
782            };
783
784            Ok(AVCaptureDeviceFormat {
785                internal: value,
786                resolution,
787                fps_list,
788                fourcc,
789            })
790        }
791    }
792
793    impl AVCaptureDeviceDiscoverySession {
794        pub fn new(device_types: Vec<AVCaptureDeviceType>) -> Result<Self, NokhwaError> {
795            let device_types = vec_to_ns_arr(device_types);
796            let position = 0 as NSInteger;
797
798            let media_type_video = unsafe { AVMediaTypeVideo.clone() }.0;
799
800            let discovery_session_cls = class!(AVCaptureDeviceDiscoverySession);
801            let discovery_session: *mut Object = unsafe {
802                msg_send![discovery_session_cls, discoverySessionWithDeviceTypes:device_types mediaType:media_type_video position:position]
803            };
804
805            Ok(AVCaptureDeviceDiscoverySession {
806                inner: discovery_session,
807            })
808        }
809
810        pub fn default() -> Result<Self, NokhwaError> {
811            AVCaptureDeviceDiscoverySession::new(vec![
812                AVCaptureDeviceType::UltraWide,
813                AVCaptureDeviceType::Telephoto,
814                AVCaptureDeviceType::External,
815                AVCaptureDeviceType::Dual,
816                AVCaptureDeviceType::DualWide,
817                AVCaptureDeviceType::Triple,
818            ])
819        }
820
821        pub fn devices(&self) -> Vec<CameraInfo> {
822            let device_ns_array: *mut Object = unsafe { msg_send![self.inner, devices] };
823            let objects_len: NSUInteger = unsafe { NSArray::count(device_ns_array) };
824            let mut devices = Vec::with_capacity(objects_len as usize);
825            for index in 0..objects_len {
826                let device = unsafe { device_ns_array.objectAtIndex(index) };
827                devices.push(get_raw_device_info(
828                    CameraIndex::Index(index as u32),
829                    device,
830                ));
831            }
832
833            devices
834        }
835    }
836
837    pub struct AVCaptureDevice {
838        inner: *mut Object,
839        device: CameraInfo,
840        locked: bool,
841    }
842
843    impl AVCaptureDevice {
844        pub fn inner(&self) -> *mut Object {
845            self.inner
846        }
847    }
848
849    impl AVCaptureDevice {
850        pub fn new(index: &CameraIndex) -> Result<Self, NokhwaError> {
851            match &index {
852                CameraIndex::Index(idx) => {
853                    let devices = query_avfoundation()?;
854
855                    match devices.get(*idx as usize) {
856                        Some(device) => Ok(AVCaptureDevice::from_id(
857                            &device.misc(),
858                            Some(index.clone()),
859                        )?),
860                        None => Err(NokhwaError::OpenDeviceError(
861                            idx.to_string(),
862                            "Not Found".to_string(),
863                        )),
864                    }
865                }
866                CameraIndex::String(id) => Ok(AVCaptureDevice::from_id(id, None)?),
867            }
868        }
869
870        pub fn from_id(id: &str, index_hint: Option<CameraIndex>) -> Result<Self, NokhwaError> {
871            let nsstr_id = str_to_nsstr(id);
872            let avfoundation_capture_cls = class!(AVCaptureDevice);
873            let capture: *mut Object =
874                unsafe { msg_send![avfoundation_capture_cls, deviceWithUniqueID: nsstr_id] };
875            if capture.is_null() {
876                return Err(NokhwaError::OpenDeviceError(
877                    id.to_string(),
878                    "Device is null".to_string(),
879                ));
880            }
881            let camera_info = get_raw_device_info(
882                index_hint.unwrap_or_else(|| CameraIndex::String(id.to_string())),
883                capture,
884            );
885
886            Ok(AVCaptureDevice {
887                inner: capture,
888                device: camera_info,
889                locked: false,
890            })
891        }
892
893        pub fn info(&self) -> &CameraInfo {
894            &self.device
895        }
896
897        pub fn supported_formats_raw(&self) -> Result<Vec<AVCaptureDeviceFormat>, NokhwaError> {
898            try_ns_arr_to_vec::<AVCaptureDeviceFormat, NokhwaError>(unsafe {
899                msg_send![self.inner, formats]
900            })
901        }
902
903        pub fn supported_formats(&self) -> Result<Vec<CameraFormat>, NokhwaError> {
904            Ok(self
905                .supported_formats_raw()?
906                .iter()
907                .flat_map(|av_fmt| {
908                    let resolution = av_fmt.resolution;
909                    av_fmt.fps_list.iter().map(move |fps_f64| {
910                        let fps = *fps_f64 as u32;
911
912                        let resolution =
913                            Resolution::new(resolution.width as u32, resolution.height as u32); // FIXME: what the fuck?
914                        CameraFormat::new(resolution, av_fmt.fourcc, fps)
915                    })
916                })
917                .filter(|x| x.frame_rate() != 0)
918                .collect())
919        }
920
921        pub fn already_in_use(&self) -> bool {
922            unsafe {
923                let result: BOOL = msg_send![self.inner(), isInUseByAnotherApplication];
924                result == YES
925            }
926        }
927
928        pub fn is_suspended(&self) -> bool {
929            unsafe {
930                let result: BOOL = msg_send![self.inner, isSuspended];
931                result == YES
932            }
933        }
934
935        pub fn lock(&self) -> Result<(), NokhwaError> {
936            if self.locked {
937                return Ok(());
938            }
939            if self.already_in_use() {
940                return Err(NokhwaError::InitializeError {
941                    backend: ApiBackend::AVFoundation,
942                    error: "Already in use".to_string(),
943                });
944            }
945            let err_ptr: *mut c_void = std::ptr::null_mut();
946            let accepted: BOOL = unsafe { msg_send![self.inner, lockForConfiguration: err_ptr] };
947            if !err_ptr.is_null() {
948                return Err(NokhwaError::SetPropertyError {
949                    property: "lockForConfiguration".to_string(),
950                    value: "Locked".to_string(),
951                    error: "Cannot lock for configuration".to_string(),
952                });
953            }
954            // Space these out for debug purposes
955            if !accepted == YES {
956                return Err(NokhwaError::SetPropertyError {
957                    property: "lockForConfiguration".to_string(),
958                    value: "Locked".to_string(),
959                    error: "Lock Rejected".to_string(),
960                });
961            }
962            Ok(())
963        }
964
965        pub fn unlock(&mut self) {
966            if self.locked {
967                self.locked = false;
968                unsafe { msg_send![self.inner, unlockForConfiguration] }
969            }
970        }
971
972        // thank you ffmpeg
973        pub fn set_all(&mut self, descriptor: CameraFormat) -> Result<(), NokhwaError> {
974            self.lock()?;
975            let format_list = try_ns_arr_to_vec::<AVCaptureDeviceFormat, NokhwaError>(unsafe {
976                msg_send![self.inner, formats]
977            })?;
978            let format_description_sel = sel!(formatDescription);
979
980            let mut selected_format: *mut Object = std::ptr::null_mut();
981            let mut selected_range: *mut Object = std::ptr::null_mut();
982
983            for format in format_list {
984                let format_desc_ref: CMFormatDescriptionRef =
985                    unsafe { msg_send![format.internal, performSelector: format_description_sel] };
986                let dimensions = unsafe { CMVideoFormatDescriptionGetDimensions(format_desc_ref) };
987
988                if dimensions.height == descriptor.resolution().height() as i32
989                    && dimensions.width == descriptor.resolution().width() as i32
990                {
991                    selected_format = format.internal;
992
993                    for range in ns_arr_to_vec::<AVFrameRateRange>(unsafe {
994                        msg_send![format.internal, videoSupportedFrameRateRanges]
995                    }) {
996                        let max_fps: f64 = unsafe { msg_send![range.inner, maxFrameRate] };
997                        // Older Apple cameras (i.e. iMac 2013) return 29.97000002997 as FPS.
998                        if (f64::from(descriptor.frame_rate()) - max_fps).abs() < 0.999 {
999                            selected_range = range.inner;
1000                            break;
1001                        }
1002                    }
1003                }
1004            }
1005            if selected_range.is_null() || selected_format.is_null() {
1006                return Err(NokhwaError::SetPropertyError {
1007                    property: "CameraFormat".to_string(),
1008                    value: descriptor.to_string(),
1009                    error: "Not Found/Rejected/Unsupported".to_string(),
1010                });
1011            }
1012
1013            let activefmtkey = str_to_nsstr("activeFormat");
1014            let min_frame_duration = str_to_nsstr("minFrameDuration");
1015            let active_video_min_frame_duration = str_to_nsstr("activeVideoMinFrameDuration");
1016            let active_video_max_frame_duration = str_to_nsstr("activeVideoMaxFrameDuration");
1017            let _: () =
1018                unsafe { msg_send![self.inner, setValue:selected_format forKey:activefmtkey] };
1019            let min_frame_duration: *mut Object =
1020                unsafe { msg_send![selected_range, valueForKey: min_frame_duration] };
1021            let _: () = unsafe {
1022                msg_send![self.inner, setValue:min_frame_duration forKey:active_video_min_frame_duration]
1023            };
1024            let _: () = unsafe {
1025                msg_send![self.inner, setValue:min_frame_duration forKey:active_video_max_frame_duration]
1026            };
1027            self.unlock();
1028            Ok(())
1029        }
1030
1031        // 0 => Focus POI
1032        // 1 => Focus Manual Setting
1033        // 2 => Exposure POI
1034        // 3 => Exposure Face Driven
1035        // 4 => Exposure Target Bias
1036        // 5 => Exposure ISO
1037        // 6 => Exposure Duration
1038        pub fn get_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
1039            let active_format: *mut Object = unsafe { msg_send![self.inner, activeFormat] };
1040
1041            let mut controls = vec![];
1042            // get focus modes
1043
1044            let focus_current: NSInteger = unsafe { msg_send![self.inner, focusMode] };
1045            let focus_locked: BOOL =
1046                unsafe { msg_send![self.inner, isFocusModeSupported:NSInteger::from(0)] };
1047            let focus_auto: BOOL =
1048                unsafe { msg_send![self.inner, isFocusModeSupported:NSInteger::from(1)] };
1049            let focus_continuous: BOOL =
1050                unsafe { msg_send![self.inner, isFocusModeSupported:NSInteger::from(2)] };
1051
1052            {
1053                let mut supported_focus_values = vec![];
1054
1055                if focus_locked == YES {
1056                    supported_focus_values.push(0)
1057                }
1058                if focus_auto == YES {
1059                    supported_focus_values.push(1)
1060                }
1061                if focus_continuous == YES {
1062                    supported_focus_values.push(2)
1063                }
1064
1065                controls.push(CameraControl::new(
1066                    KnownCameraControl::Focus,
1067                    "FocusMode".to_string(),
1068                    ControlValueDescription::Enum {
1069                        value: focus_current,
1070                        possible: supported_focus_values,
1071                        default: focus_current,
1072                    },
1073                    vec![],
1074                    true,
1075                ));
1076            }
1077
1078            let focus_poi_supported: BOOL =
1079                unsafe { msg_send![self.inner, isFocusPointOfInterestSupported] };
1080            let focus_poi: CGPoint = unsafe { msg_send![self.inner, focusPointOfInterest] };
1081
1082            controls.push(CameraControl::new(
1083                KnownCameraControl::Other(0),
1084                "FocusPointOfInterest".to_string(),
1085                ControlValueDescription::Point {
1086                    value: (focus_poi.x as f64, focus_poi.y as f64),
1087                    default: (0.5, 0.5),
1088                },
1089                if focus_poi_supported == NO {
1090                    vec![
1091                        KnownCameraControlFlag::Disabled,
1092                        KnownCameraControlFlag::ReadOnly,
1093                    ]
1094                } else {
1095                    vec![]
1096                },
1097                focus_auto == YES || focus_continuous == YES,
1098            ));
1099
1100            let focus_manual: BOOL =
1101                unsafe { msg_send![self.inner, isLockingFocusWithCustomLensPositionSupported] };
1102            let focus_lenspos: f32 = unsafe { msg_send![self.inner, lensPosition] };
1103
1104            controls.push(CameraControl::new(
1105                KnownCameraControl::Other(1),
1106                "FocusManualLensPosition".to_string(),
1107                ControlValueDescription::FloatRange {
1108                    min: 0.0,
1109                    max: 1.0,
1110                    value: focus_lenspos as f64,
1111                    step: f64::MIN_POSITIVE,
1112                    default: 1.0,
1113                },
1114                if focus_manual == YES {
1115                    vec![]
1116                } else {
1117                    vec![
1118                        KnownCameraControlFlag::Disabled,
1119                        KnownCameraControlFlag::ReadOnly,
1120                    ]
1121                },
1122                focus_manual == YES,
1123            ));
1124
1125            // get exposures
1126            let exposure_current: NSInteger = unsafe { msg_send![self.inner, exposureMode] };
1127            let exposure_locked: BOOL =
1128                unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(0)] };
1129            let exposure_auto: BOOL =
1130                unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(1)] };
1131            let exposure_continuous: BOOL =
1132                unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(2)] };
1133            let exposure_custom: BOOL =
1134                unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(3)] };
1135
1136            {
1137                let mut supported_exposure_values = vec![];
1138
1139                if exposure_locked == YES {
1140                    supported_exposure_values.push(0);
1141                }
1142                if exposure_auto == YES {
1143                    supported_exposure_values.push(1);
1144                }
1145                if exposure_continuous == YES {
1146                    supported_exposure_values.push(2);
1147                }
1148                if exposure_custom == YES {
1149                    supported_exposure_values.push(3);
1150                }
1151
1152                controls.push(CameraControl::new(
1153                    KnownCameraControl::Exposure,
1154                    "ExposureMode".to_string(),
1155                    ControlValueDescription::Enum {
1156                        value: exposure_current,
1157                        possible: supported_exposure_values,
1158                        default: exposure_current,
1159                    },
1160                    vec![],
1161                    true,
1162                ));
1163            }
1164
1165            let exposure_poi_supported: BOOL =
1166                unsafe { msg_send![self.inner, isExposurePointOfInterestSupported] };
1167            let exposure_poi: CGPoint = unsafe { msg_send![self.inner, exposurePointOfInterest] };
1168
1169            controls.push(CameraControl::new(
1170                KnownCameraControl::Other(2),
1171                "ExposurePointOfInterest".to_string(),
1172                ControlValueDescription::Point {
1173                    value: (exposure_poi.x as f64, exposure_poi.y as f64),
1174                    default: (0.5, 0.5),
1175                },
1176                if exposure_poi_supported == NO {
1177                    vec![
1178                        KnownCameraControlFlag::Disabled,
1179                        KnownCameraControlFlag::ReadOnly,
1180                    ]
1181                } else {
1182                    vec![]
1183                },
1184                focus_auto == YES || focus_continuous == YES,
1185            ));
1186
1187            let expposure_face_driven_supported: BOOL =
1188                unsafe { msg_send![self.inner, isFaceDrivenAutoExposureEnabled] };
1189            let exposure_face_driven: BOOL = unsafe {
1190                msg_send![
1191                    self.inner,
1192                    automaticallyAdjustsFaceDrivenAutoExposureEnabled
1193                ]
1194            };
1195
1196            controls.push(CameraControl::new(
1197                KnownCameraControl::Other(3),
1198                "ExposureFaceDriven".to_string(),
1199                ControlValueDescription::Boolean {
1200                    value: exposure_face_driven == YES,
1201                    default: false,
1202                },
1203                if expposure_face_driven_supported == NO {
1204                    vec![
1205                        KnownCameraControlFlag::Disabled,
1206                        KnownCameraControlFlag::ReadOnly,
1207                    ]
1208                } else {
1209                    vec![]
1210                },
1211                exposure_poi_supported == YES,
1212            ));
1213
1214            let exposure_bias: f32 = unsafe { msg_send![self.inner, exposureTargetBias] };
1215            let exposure_bias_min: f32 = unsafe { msg_send![self.inner, minExposureTargetBias] };
1216            let exposure_bias_max: f32 = unsafe { msg_send![self.inner, maxExposureTargetBias] };
1217
1218            controls.push(CameraControl::new(
1219                KnownCameraControl::Other(4),
1220                "ExposureBiasTarget".to_string(),
1221                ControlValueDescription::FloatRange {
1222                    min: exposure_bias_min as f64,
1223                    max: exposure_bias_max as f64,
1224                    value: exposure_bias as f64,
1225                    step: f32::MIN_POSITIVE as f64,
1226                    default: unsafe { AVCaptureExposureTargetBiasCurrent } as f64,
1227                },
1228                vec![],
1229                true,
1230            ));
1231
1232            let exposure_duration: CMTime = unsafe { msg_send![self.inner, exposureDuration] };
1233            let exposure_duration_min: CMTime =
1234                unsafe { msg_send![active_format, minExposureDuration] };
1235            let exposure_duration_max: CMTime =
1236                unsafe { msg_send![active_format, maxExposureDuration] };
1237
1238            controls.push(CameraControl::new(
1239                KnownCameraControl::Gamma,
1240                "ExposureDuration".to_string(),
1241                ControlValueDescription::IntegerRange {
1242                    min: exposure_duration_min.value,
1243                    max: exposure_duration_max.value,
1244                    value: exposure_duration.value,
1245                    step: 1,
1246                    default: unsafe { AVCaptureExposureDurationCurrent.value },
1247                },
1248                if exposure_custom == YES {
1249                    vec![
1250                        KnownCameraControlFlag::ReadOnly,
1251                        KnownCameraControlFlag::Volatile,
1252                    ]
1253                } else {
1254                    vec![KnownCameraControlFlag::Volatile]
1255                },
1256                exposure_custom == YES,
1257            ));
1258
1259            let exposure_iso: f32 = unsafe { msg_send![self.inner, ISO] };
1260            let exposure_iso_min: f32 = unsafe { msg_send![active_format, minISO] };
1261            let exposure_iso_max: f32 = unsafe { msg_send![active_format, maxISO] };
1262
1263            controls.push(CameraControl::new(
1264                KnownCameraControl::Brightness,
1265                "ExposureISO".to_string(),
1266                ControlValueDescription::FloatRange {
1267                    min: exposure_iso_min as f64,
1268                    max: exposure_iso_max as f64,
1269                    value: exposure_iso as f64,
1270                    step: f32::MIN_POSITIVE as f64,
1271                    default: unsafe { AVCaptureISOCurrent } as f64,
1272                },
1273                if exposure_custom == YES {
1274                    vec![
1275                        KnownCameraControlFlag::ReadOnly,
1276                        KnownCameraControlFlag::Volatile,
1277                    ]
1278                } else {
1279                    vec![KnownCameraControlFlag::Volatile]
1280                },
1281                exposure_custom == YES,
1282            ));
1283
1284            let lens_aperture: f32 = unsafe { msg_send![self.inner, lensAperture] };
1285
1286            controls.push(CameraControl::new(
1287                KnownCameraControl::Iris,
1288                "LensAperture".to_string(),
1289                ControlValueDescription::Float {
1290                    value: lens_aperture as f64,
1291                    default: lens_aperture as f64,
1292                    step: lens_aperture as f64,
1293                },
1294                vec![KnownCameraControlFlag::ReadOnly],
1295                false,
1296            ));
1297
1298            // get whiteblaance
1299            let white_balance_current: NSInteger =
1300                unsafe { msg_send![self.inner, whiteBalanceMode] };
1301            let white_balance_manual: BOOL =
1302                unsafe { msg_send![self.inner, isWhiteBalanceModeSupported:NSInteger::from(0)] };
1303            let white_balance_auto: BOOL =
1304                unsafe { msg_send![self.inner, isWhiteBalanceModeSupported:NSInteger::from(1)] };
1305            let white_balance_continuous: BOOL =
1306                unsafe { msg_send![self.inner, isWhiteBalanceModeSupported:NSInteger::from(2)] };
1307
1308            {
1309                let mut possible = vec![];
1310
1311                if white_balance_manual == YES {
1312                    possible.push(0);
1313                }
1314                if white_balance_auto == YES {
1315                    possible.push(1);
1316                }
1317                if white_balance_continuous == YES {
1318                    possible.push(2);
1319                }
1320
1321                controls.push(CameraControl::new(
1322                    KnownCameraControl::WhiteBalance,
1323                    "WhiteBalanceMode".to_string(),
1324                    ControlValueDescription::Enum {
1325                        value: white_balance_current as i64,
1326                        possible,
1327                        default: 0,
1328                    },
1329                    vec![],
1330                    true,
1331                ));
1332            }
1333
1334            let white_balance_gains: AVCaptureWhiteBalanceGains =
1335                unsafe { msg_send![self.inner, deviceWhiteBalanceGains] };
1336            let white_balance_default: AVCaptureWhiteBalanceGains =
1337                unsafe { msg_send![self.inner, grayWorldDeviceWhiteBalanceGains] };
1338            let white_balancne_max: AVCaptureWhiteBalanceGains =
1339                unsafe { msg_send![self.inner, maxWhiteBalanceGain] };
1340            let white_balance_gain_supported: BOOL = unsafe {
1341                msg_send![
1342                    self.inner,
1343                    isLockingWhiteBalanceWithCustomDeviceGainsSupported
1344                ]
1345            };
1346
1347            controls.push(CameraControl::new(
1348                KnownCameraControl::Gain,
1349                "WhiteBalanceGain".to_string(),
1350                ControlValueDescription::RGB {
1351                    value: (
1352                        white_balance_gains.redGain as f64,
1353                        white_balance_gains.greenGain as f64,
1354                        white_balance_gains.blueGain as f64,
1355                    ),
1356                    max: (
1357                        white_balancne_max.redGain as f64,
1358                        white_balancne_max.greenGain as f64,
1359                        white_balancne_max.blueGain as f64,
1360                    ),
1361                    default: (
1362                        white_balance_default.redGain as f64,
1363                        white_balance_default.greenGain as f64,
1364                        white_balance_default.blueGain as f64,
1365                    ),
1366                },
1367                if white_balance_gain_supported == YES {
1368                    vec![
1369                        KnownCameraControlFlag::Disabled,
1370                        KnownCameraControlFlag::ReadOnly,
1371                    ]
1372                } else {
1373                    vec![]
1374                },
1375                white_balance_gain_supported == YES,
1376            ));
1377
1378            // get flash
1379            let has_torch: BOOL = unsafe { msg_send![self.inner, isTorchAvailable] };
1380            let torch_active: BOOL = unsafe { msg_send![self.inner, isTorchActive] };
1381            let torch_off: BOOL =
1382                unsafe { msg_send![self.inner, isTorchModeSupported:NSInteger::from(0)] };
1383            let torch_on: BOOL =
1384                unsafe { msg_send![self.inner, isTorchModeSupported:NSInteger::from(1)] };
1385            let torch_auto: BOOL =
1386                unsafe { msg_send![self.inner, isTorchModeSupported:NSInteger::from(2)] };
1387
1388            {
1389                let mut possible = vec![];
1390
1391                if torch_off == YES {
1392                    possible.push(0);
1393                }
1394                if torch_on == YES {
1395                    possible.push(1);
1396                }
1397                if torch_auto == YES {
1398                    possible.push(2);
1399                }
1400
1401                controls.push(CameraControl::new(
1402                    KnownCameraControl::Other(5),
1403                    "TorchMode".to_string(),
1404                    ControlValueDescription::Enum {
1405                        value: (torch_active == YES) as i64,
1406                        possible,
1407                        default: 0,
1408                    },
1409                    if has_torch == YES {
1410                        vec![
1411                            KnownCameraControlFlag::Disabled,
1412                            KnownCameraControlFlag::ReadOnly,
1413                        ]
1414                    } else {
1415                        vec![]
1416                    },
1417                    has_torch == YES,
1418                ));
1419            }
1420
1421            // get low light boost
1422            let has_llb: BOOL = unsafe { msg_send![self.inner, isLowLightBoostSupported] };
1423            let llb_enabled: BOOL = unsafe { msg_send![self.inner, isLowLightBoostEnabled] };
1424
1425            {
1426                controls.push(CameraControl::new(
1427                    KnownCameraControl::BacklightComp,
1428                    "LowLightCompensation".to_string(),
1429                    ControlValueDescription::Boolean {
1430                        value: llb_enabled == YES,
1431                        default: false,
1432                    },
1433                    if has_llb == NO {
1434                        vec![
1435                            KnownCameraControlFlag::Disabled,
1436                            KnownCameraControlFlag::ReadOnly,
1437                        ]
1438                    } else {
1439                        vec![]
1440                    },
1441                    has_llb == YES,
1442                ));
1443            }
1444
1445            // get zoom factor
1446            let zoom_current: CGFloat = unsafe { msg_send![self.inner, videoZoomFactor] };
1447            let zoom_min: CGFloat = unsafe { msg_send![self.inner, minAvailableVideoZoomFactor] };
1448            let zoom_max: CGFloat = unsafe { msg_send![self.inner, maxAvailableVideoZoomFactor] };
1449
1450            controls.push(CameraControl::new(
1451                KnownCameraControl::Zoom,
1452                "Zoom".to_string(),
1453                ControlValueDescription::FloatRange {
1454                    min: zoom_min as f64,
1455                    max: zoom_max as f64,
1456                    value: zoom_current as f64,
1457                    step: f32::MIN_POSITIVE as f64,
1458                    default: 1.0,
1459                },
1460                vec![],
1461                true,
1462            ));
1463
1464            // zoom distortion correction
1465            let distortion_correction_supported: BOOL =
1466                unsafe { msg_send![self.inner, isGeometricDistortionCorrectionSupported] };
1467            let distortion_correction_current_value: BOOL =
1468                unsafe { msg_send![self.inner, isGeometricDistortionCorrectionEnabled] };
1469
1470            controls.push(CameraControl::new(
1471                KnownCameraControl::Other(6),
1472                "DistortionCorrection".to_string(),
1473                ControlValueDescription::Boolean {
1474                    value: distortion_correction_current_value == YES,
1475                    default: false,
1476                },
1477                if distortion_correction_supported == YES {
1478                    vec![
1479                        KnownCameraControlFlag::ReadOnly,
1480                        KnownCameraControlFlag::Disabled,
1481                    ]
1482                } else {
1483                    vec![]
1484                },
1485                distortion_correction_supported == YES,
1486            ));
1487
1488            Ok(controls)
1489        }
1490
1491        pub fn set_control(
1492            &mut self,
1493            id: KnownCameraControl,
1494            value: ControlValueSetter,
1495        ) -> Result<(), NokhwaError> {
1496            let rc = self.get_controls()?;
1497            let controls = rc
1498                .iter()
1499                .map(|cc| (cc.control(), cc))
1500                .collect::<BTreeMap<_, _>>();
1501
1502            match id {
1503                KnownCameraControl::Brightness => {
1504                    let isoctrl = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1505                        property: id.to_string(),
1506                        value: value.to_string(),
1507                        error: "Control does not exist".to_string(),
1508                    })?;
1509
1510                    if isoctrl.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1511                        return Err(NokhwaError::SetPropertyError {
1512                            property: id.to_string(),
1513                            value: value.to_string(),
1514                            error:
1515                                "Exposure is in improper state to set ISO (Please set to `custom`!)"
1516                                    .to_string(),
1517                        });
1518                    }
1519
1520                    if isoctrl.flag().contains(&KnownCameraControlFlag::Disabled) {
1521                        return Err(NokhwaError::SetPropertyError {
1522                            property: id.to_string(),
1523                            value: value.to_string(),
1524                            error: "Disabled".to_string(),
1525                        });
1526                    }
1527
1528                    let current_duration = unsafe { AVCaptureExposureDurationCurrent };
1529                    let new_iso = *value.as_float().ok_or(NokhwaError::SetPropertyError {
1530                        property: id.to_string(),
1531                        value: value.to_string(),
1532                        error: "Expected float".to_string(),
1533                    })? as f32;
1534
1535                    if !isoctrl.description().verify_setter(&value) {
1536                        return Err(NokhwaError::SetPropertyError {
1537                            property: id.to_string(),
1538                            value: value.to_string(),
1539                            error: "Failed to verify value".to_string(),
1540                        });
1541                    }
1542
1543                    let _: () = unsafe {
1544                        msg_send![self.inner, setExposureModeCustomWithDuration:current_duration ISO:new_iso completionHandler:Nil]
1545                    };
1546
1547                    Ok(())
1548                }
1549                KnownCameraControl::Gamma => {
1550                    let duration_ctrl = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1551                        property: id.to_string(),
1552                        value: value.to_string(),
1553                        error: "Control does not exist".to_string(),
1554                    })?;
1555
1556                    if duration_ctrl
1557                        .flag()
1558                        .contains(&KnownCameraControlFlag::ReadOnly)
1559                    {
1560                        return Err(NokhwaError::SetPropertyError {
1561                            property: id.to_string(),
1562                            value: value.to_string(),
1563                            error: "Exposure is in improper state to set Duration (Please set to `custom`!)"
1564                                .to_string(),
1565                        });
1566                    }
1567
1568                    if duration_ctrl
1569                        .flag()
1570                        .contains(&KnownCameraControlFlag::Disabled)
1571                    {
1572                        return Err(NokhwaError::SetPropertyError {
1573                            property: id.to_string(),
1574                            value: value.to_string(),
1575                            error: "Disabled".to_string(),
1576                        });
1577                    }
1578                    let current_duration: CMTime =
1579                        unsafe { msg_send![self.inner, exposureDuration] };
1580
1581                    let current_iso = unsafe { AVCaptureISOCurrent };
1582                    let new_duration = CMTime {
1583                        value: *value.as_integer().ok_or(NokhwaError::SetPropertyError {
1584                            property: id.to_string(),
1585                            value: value.to_string(),
1586                            error: "Expected i64".to_string(),
1587                        })?,
1588                        timescale: current_duration.timescale,
1589                        flags: current_duration.flags,
1590                        epoch: current_duration.epoch,
1591                    };
1592
1593                    if !duration_ctrl.description().verify_setter(&value) {
1594                        return Err(NokhwaError::SetPropertyError {
1595                            property: id.to_string(),
1596                            value: value.to_string(),
1597                            error: "Failed to verify value".to_string(),
1598                        });
1599                    }
1600
1601                    let _: () = unsafe {
1602                        msg_send![self.inner, setExposureModeCustomWithDuration:new_duration ISO:current_iso completionHandler:Nil]
1603                    };
1604
1605                    Ok(())
1606                }
1607                KnownCameraControl::WhiteBalance => {
1608                    let wb_enum_value = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1609                        property: id.to_string(),
1610                        value: value.to_string(),
1611                        error: "Control does not exist".to_string(),
1612                    })?;
1613
1614                    if wb_enum_value
1615                        .flag()
1616                        .contains(&KnownCameraControlFlag::ReadOnly)
1617                    {
1618                        return Err(NokhwaError::SetPropertyError {
1619                            property: id.to_string(),
1620                            value: value.to_string(),
1621                            error: "Read Only".to_string(),
1622                        });
1623                    }
1624
1625                    if wb_enum_value
1626                        .flag()
1627                        .contains(&KnownCameraControlFlag::Disabled)
1628                    {
1629                        return Err(NokhwaError::SetPropertyError {
1630                            property: id.to_string(),
1631                            value: value.to_string(),
1632                            error: "Disabled".to_string(),
1633                        });
1634                    }
1635                    let setter =
1636                        NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
1637                            property: id.to_string(),
1638                            value: value.to_string(),
1639                            error: "Expected Enum".to_string(),
1640                        })? as i32);
1641
1642                    if !wb_enum_value.description().verify_setter(&value) {
1643                        return Err(NokhwaError::SetPropertyError {
1644                            property: id.to_string(),
1645                            value: value.to_string(),
1646                            error: "Failed to verify value".to_string(),
1647                        });
1648                    }
1649
1650                    let _: () = unsafe { msg_send![self.inner, whiteBalanceMode: setter] };
1651
1652                    Ok(())
1653                }
1654                KnownCameraControl::BacklightComp => {
1655                    let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1656                        property: id.to_string(),
1657                        value: value.to_string(),
1658                        error: "Control does not exist".to_string(),
1659                    })?;
1660
1661                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1662                        return Err(NokhwaError::SetPropertyError {
1663                            property: id.to_string(),
1664                            value: value.to_string(),
1665                            error: "Read Only".to_string(),
1666                        });
1667                    }
1668
1669                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1670                        return Err(NokhwaError::SetPropertyError {
1671                            property: id.to_string(),
1672                            value: value.to_string(),
1673                            error: "Disabled".to_string(),
1674                        });
1675                    }
1676
1677                    let setter =
1678                        NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
1679                            property: id.to_string(),
1680                            value: value.to_string(),
1681                            error: "Expected Enum".to_string(),
1682                        })? as i32);
1683
1684                    if !ctrlvalue.description().verify_setter(&value) {
1685                        return Err(NokhwaError::SetPropertyError {
1686                            property: id.to_string(),
1687                            value: value.to_string(),
1688                            error: "Failed to verify value".to_string(),
1689                        });
1690                    }
1691
1692                    let _: () = unsafe { msg_send![self.inner, whiteBalanceMode: setter] };
1693
1694                    Ok(())
1695                }
1696                KnownCameraControl::Gain => {
1697                    let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1698                        property: id.to_string(),
1699                        value: value.to_string(),
1700                        error: "Control does not exist".to_string(),
1701                    })?;
1702
1703                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1704                        return Err(NokhwaError::SetPropertyError {
1705                            property: id.to_string(),
1706                            value: value.to_string(),
1707                            error: "Read Only".to_string(),
1708                        });
1709                    }
1710
1711                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1712                        return Err(NokhwaError::SetPropertyError {
1713                            property: id.to_string(),
1714                            value: value.to_string(),
1715                            error: "Disabled".to_string(),
1716                        });
1717                    }
1718
1719                    let setter = NSInteger::from(*value.as_boolean().ok_or(
1720                        NokhwaError::SetPropertyError {
1721                            property: id.to_string(),
1722                            value: value.to_string(),
1723                            error: "Expected Boolean".to_string(),
1724                        },
1725                    )? as i32);
1726
1727                    if !ctrlvalue.description().verify_setter(&value) {
1728                        return Err(NokhwaError::SetPropertyError {
1729                            property: id.to_string(),
1730                            value: value.to_string(),
1731                            error: "Failed to verify value".to_string(),
1732                        });
1733                    }
1734
1735                    let _: () = unsafe { msg_send![self.inner, whiteBalanceMode: setter] };
1736
1737                    Ok(())
1738                }
1739                KnownCameraControl::Zoom => {
1740                    let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1741                        property: id.to_string(),
1742                        value: value.to_string(),
1743                        error: "Control does not exist".to_string(),
1744                    })?;
1745
1746                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1747                        return Err(NokhwaError::SetPropertyError {
1748                            property: id.to_string(),
1749                            value: value.to_string(),
1750                            error: "Read Only".to_string(),
1751                        });
1752                    }
1753
1754                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1755                        return Err(NokhwaError::SetPropertyError {
1756                            property: id.to_string(),
1757                            value: value.to_string(),
1758                            error: "Disabled".to_string(),
1759                        });
1760                    }
1761
1762                    let setter = *value.as_float().ok_or(NokhwaError::SetPropertyError {
1763                        property: id.to_string(),
1764                        value: value.to_string(),
1765                        error: "Expected float".to_string(),
1766                    })? as c_float;
1767
1768                    if !ctrlvalue.description().verify_setter(&value) {
1769                        return Err(NokhwaError::SetPropertyError {
1770                            property: id.to_string(),
1771                            value: value.to_string(),
1772                            error: "Failed to verify value".to_string(),
1773                        });
1774                    }
1775
1776                    let _: () = unsafe {
1777                        msg_send![self.inner, rampToVideoZoomFactor: setter withRate: 1.0_f32]
1778                    };
1779
1780                    Ok(())
1781                }
1782                KnownCameraControl::Exposure => {
1783                    let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1784                        property: id.to_string(),
1785                        value: value.to_string(),
1786                        error: "Control does not exist".to_string(),
1787                    })?;
1788
1789                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1790                        return Err(NokhwaError::SetPropertyError {
1791                            property: id.to_string(),
1792                            value: value.to_string(),
1793                            error: "Read Only".to_string(),
1794                        });
1795                    }
1796
1797                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1798                        return Err(NokhwaError::SetPropertyError {
1799                            property: id.to_string(),
1800                            value: value.to_string(),
1801                            error: "Disabled".to_string(),
1802                        });
1803                    }
1804
1805                    let setter =
1806                        NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
1807                            property: id.to_string(),
1808                            value: value.to_string(),
1809                            error: "Expected Enum".to_string(),
1810                        })? as i32);
1811
1812                    if !ctrlvalue.description().verify_setter(&value) {
1813                        return Err(NokhwaError::SetPropertyError {
1814                            property: id.to_string(),
1815                            value: value.to_string(),
1816                            error: "Failed to verify value".to_string(),
1817                        });
1818                    }
1819
1820                    let _: () = unsafe { msg_send![self.inner, exposureMode: setter] };
1821
1822                    Ok(())
1823                }
1824                KnownCameraControl::Iris => Err(NokhwaError::SetPropertyError {
1825                    property: id.to_string(),
1826                    value: value.to_string(),
1827                    error: "Read Only".to_string(),
1828                }),
1829                KnownCameraControl::Focus => {
1830                    let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1831                        property: id.to_string(),
1832                        value: value.to_string(),
1833                        error: "Control does not exist".to_string(),
1834                    })?;
1835
1836                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1837                        return Err(NokhwaError::SetPropertyError {
1838                            property: id.to_string(),
1839                            value: value.to_string(),
1840                            error: "Read Only".to_string(),
1841                        });
1842                    }
1843
1844                    if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1845                        return Err(NokhwaError::SetPropertyError {
1846                            property: id.to_string(),
1847                            value: value.to_string(),
1848                            error: "Disabled".to_string(),
1849                        });
1850                    }
1851
1852                    let setter =
1853                        NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
1854                            property: id.to_string(),
1855                            value: value.to_string(),
1856                            error: "Expected Enum".to_string(),
1857                        })? as i32);
1858
1859                    if !ctrlvalue.description().verify_setter(&value) {
1860                        return Err(NokhwaError::SetPropertyError {
1861                            property: id.to_string(),
1862                            value: value.to_string(),
1863                            error: "Failed to verify value".to_string(),
1864                        });
1865                    }
1866
1867                    let _: () = unsafe { msg_send![self.inner, focusMode: setter] };
1868
1869                    Ok(())
1870                }
1871                KnownCameraControl::Other(i) => match i {
1872                    0 => {
1873                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1874                            property: id.to_string(),
1875                            value: value.to_string(),
1876                            error: "Control does not exist".to_string(),
1877                        })?;
1878
1879                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1880                            return Err(NokhwaError::SetPropertyError {
1881                                property: id.to_string(),
1882                                value: value.to_string(),
1883                                error: "Read Only".to_string(),
1884                            });
1885                        }
1886
1887                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1888                            return Err(NokhwaError::SetPropertyError {
1889                                property: id.to_string(),
1890                                value: value.to_string(),
1891                                error: "Disabled".to_string(),
1892                            });
1893                        }
1894
1895                        let setter = value
1896                            .as_point()
1897                            .ok_or(NokhwaError::SetPropertyError {
1898                                property: id.to_string(),
1899                                value: value.to_string(),
1900                                error: "Expected Point".to_string(),
1901                            })
1902                            .map(|(x, y)| CGPoint {
1903                                x: *x as f32,
1904                                y: *y as f32,
1905                            })?;
1906
1907                        if !ctrlvalue.description().verify_setter(&value) {
1908                            return Err(NokhwaError::SetPropertyError {
1909                                property: id.to_string(),
1910                                value: value.to_string(),
1911                                error: "Failed to verify value".to_string(),
1912                            });
1913                        }
1914
1915                        let _: () = unsafe { msg_send![self.inner, focusPointOfInterest: setter] };
1916
1917                        Ok(())
1918                    }
1919                    1 => {
1920                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1921                            property: id.to_string(),
1922                            value: value.to_string(),
1923                            error: "Control does not exist".to_string(),
1924                        })?;
1925
1926                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1927                            return Err(NokhwaError::SetPropertyError {
1928                                property: id.to_string(),
1929                                value: value.to_string(),
1930                                error: "Read Only".to_string(),
1931                            });
1932                        }
1933
1934                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1935                            return Err(NokhwaError::SetPropertyError {
1936                                property: id.to_string(),
1937                                value: value.to_string(),
1938                                error: "Disabled".to_string(),
1939                            });
1940                        }
1941
1942                        let setter = *value.as_float().ok_or(NokhwaError::SetPropertyError {
1943                            property: id.to_string(),
1944                            value: value.to_string(),
1945                            error: "Expected float".to_string(),
1946                        })? as c_float;
1947
1948                        if !ctrlvalue.description().verify_setter(&value) {
1949                            return Err(NokhwaError::SetPropertyError {
1950                                property: id.to_string(),
1951                                value: value.to_string(),
1952                                error: "Failed to verify value".to_string(),
1953                            });
1954                        }
1955
1956                        let _: () = unsafe {
1957                            msg_send![self.inner, setFocusModeLockedWithLensPosition: setter handler: Nil]
1958                        };
1959
1960                        Ok(())
1961                    }
1962                    2 => {
1963                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
1964                            property: id.to_string(),
1965                            value: value.to_string(),
1966                            error: "Control does not exist".to_string(),
1967                        })?;
1968
1969                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
1970                            return Err(NokhwaError::SetPropertyError {
1971                                property: id.to_string(),
1972                                value: value.to_string(),
1973                                error: "Read Only".to_string(),
1974                            });
1975                        }
1976
1977                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
1978                            return Err(NokhwaError::SetPropertyError {
1979                                property: id.to_string(),
1980                                value: value.to_string(),
1981                                error: "Disabled".to_string(),
1982                            });
1983                        }
1984
1985                        let setter = value
1986                            .as_point()
1987                            .ok_or(NokhwaError::SetPropertyError {
1988                                property: id.to_string(),
1989                                value: value.to_string(),
1990                                error: "Expected Point".to_string(),
1991                            })
1992                            .map(|(x, y)| CGPoint {
1993                                x: *x as f32,
1994                                y: *y as f32,
1995                            })?;
1996
1997                        if !ctrlvalue.description().verify_setter(&value) {
1998                            return Err(NokhwaError::SetPropertyError {
1999                                property: id.to_string(),
2000                                value: value.to_string(),
2001                                error: "Failed to verify value".to_string(),
2002                            });
2003                        }
2004
2005                        let _: () =
2006                            unsafe { msg_send![self.inner, exposurePointOfInterest: setter] };
2007
2008                        Ok(())
2009                    }
2010                    3 => {
2011                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
2012                            property: id.to_string(),
2013                            value: value.to_string(),
2014                            error: "Control does not exist".to_string(),
2015                        })?;
2016
2017                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
2018                            return Err(NokhwaError::SetPropertyError {
2019                                property: id.to_string(),
2020                                value: value.to_string(),
2021                                error: "Read Only".to_string(),
2022                            });
2023                        }
2024
2025                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
2026                            return Err(NokhwaError::SetPropertyError {
2027                                property: id.to_string(),
2028                                value: value.to_string(),
2029                                error: "Disabled".to_string(),
2030                            });
2031                        }
2032
2033                        let setter =
2034                            if *value.as_boolean().ok_or(NokhwaError::SetPropertyError {
2035                                property: id.to_string(),
2036                                value: value.to_string(),
2037                                error: "Expected Boolean".to_string(),
2038                            })? {
2039                                YES
2040                            } else {
2041                                NO
2042                            };
2043
2044                        if !ctrlvalue.description().verify_setter(&value) {
2045                            return Err(NokhwaError::SetPropertyError {
2046                                property: id.to_string(),
2047                                value: value.to_string(),
2048                                error: "Failed to verify value".to_string(),
2049                            });
2050                        }
2051
2052                        let _: () = unsafe {
2053                            msg_send![
2054                                self.inner,
2055                                automaticallyAdjustsFaceDrivenAutoExposureEnabled: setter
2056                            ]
2057                        };
2058
2059                        Ok(())
2060                    }
2061                    4 => {
2062                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
2063                            property: id.to_string(),
2064                            value: value.to_string(),
2065                            error: "Control does not exist".to_string(),
2066                        })?;
2067
2068                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
2069                            return Err(NokhwaError::SetPropertyError {
2070                                property: id.to_string(),
2071                                value: value.to_string(),
2072                                error: "Read Only".to_string(),
2073                            });
2074                        }
2075
2076                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
2077                            return Err(NokhwaError::SetPropertyError {
2078                                property: id.to_string(),
2079                                value: value.to_string(),
2080                                error: "Disabled".to_string(),
2081                            });
2082                        }
2083
2084                        let setter = *value.as_float().ok_or(NokhwaError::SetPropertyError {
2085                            property: id.to_string(),
2086                            value: value.to_string(),
2087                            error: "Expected Float".to_string(),
2088                        })? as f32;
2089
2090                        if !ctrlvalue.description().verify_setter(&value) {
2091                            return Err(NokhwaError::SetPropertyError {
2092                                property: id.to_string(),
2093                                value: value.to_string(),
2094                                error: "Failed to verify value".to_string(),
2095                            });
2096                        }
2097
2098                        let _: () = unsafe {
2099                            msg_send![self.inner, setExposureTargetBias: setter handler: Nil]
2100                        };
2101
2102                        Ok(())
2103                    }
2104                    5 => {
2105                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
2106                            property: id.to_string(),
2107                            value: value.to_string(),
2108                            error: "Control does not exist".to_string(),
2109                        })?;
2110
2111                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
2112                            return Err(NokhwaError::SetPropertyError {
2113                                property: id.to_string(),
2114                                value: value.to_string(),
2115                                error: "Read Only".to_string(),
2116                            });
2117                        }
2118
2119                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
2120                            return Err(NokhwaError::SetPropertyError {
2121                                property: id.to_string(),
2122                                value: value.to_string(),
2123                                error: "Disabled".to_string(),
2124                            });
2125                        }
2126
2127                        let setter = NSInteger::from(*value.as_enum().ok_or(
2128                            NokhwaError::SetPropertyError {
2129                                property: id.to_string(),
2130                                value: value.to_string(),
2131                                error: "Expected Enum".to_string(),
2132                            },
2133                        )? as i32);
2134
2135                        if !ctrlvalue.description().verify_setter(&value) {
2136                            return Err(NokhwaError::SetPropertyError {
2137                                property: id.to_string(),
2138                                value: value.to_string(),
2139                                error: "Failed to verify value".to_string(),
2140                            });
2141                        }
2142
2143                        let _: () = unsafe { msg_send![self.inner, torchMode: setter] };
2144
2145                        Ok(())
2146                    }
2147                    6 => {
2148                        let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
2149                            property: id.to_string(),
2150                            value: value.to_string(),
2151                            error: "Control does not exist".to_string(),
2152                        })?;
2153
2154                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
2155                            return Err(NokhwaError::SetPropertyError {
2156                                property: id.to_string(),
2157                                value: value.to_string(),
2158                                error: "Read Only".to_string(),
2159                            });
2160                        }
2161
2162                        if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
2163                            return Err(NokhwaError::SetPropertyError {
2164                                property: id.to_string(),
2165                                value: value.to_string(),
2166                                error: "Disabled".to_string(),
2167                            });
2168                        }
2169
2170                        let setter =
2171                            if *value.as_boolean().ok_or(NokhwaError::SetPropertyError {
2172                                property: id.to_string(),
2173                                value: value.to_string(),
2174                                error: "Expected Boolean".to_string(),
2175                            })? {
2176                                YES
2177                            } else {
2178                                NO
2179                            };
2180
2181                        if !ctrlvalue.description().verify_setter(&value) {
2182                            return Err(NokhwaError::SetPropertyError {
2183                                property: id.to_string(),
2184                                value: value.to_string(),
2185                                error: "Failed to verify value".to_string(),
2186                            });
2187                        }
2188
2189                        let _: () = unsafe {
2190                            msg_send![self.inner, geometricDistortionCorrectionEnabled: setter]
2191                        };
2192
2193                        Ok(())
2194                    }
2195                    _ => Err(NokhwaError::SetPropertyError {
2196                        property: id.to_string(),
2197                        value: value.to_string(),
2198                        error: "Unknown Control".to_string(),
2199                    }),
2200                },
2201                _ => Err(NokhwaError::SetPropertyError {
2202                    property: id.to_string(),
2203                    value: value.to_string(),
2204                    error: "Unknown Control".to_string(),
2205                }),
2206            }
2207        }
2208
2209        pub fn active_format(&self) -> Result<CameraFormat, NokhwaError> {
2210            let af: *mut Object = unsafe { msg_send![self.inner, activeFormat] };
2211            let avf_format = AVCaptureDeviceFormat::try_from(af)?;
2212            let resolution = avf_format.resolution;
2213            let fourcc = avf_format.fourcc;
2214            let mut a = avf_format
2215                .fps_list
2216                .into_iter()
2217                .map(move |fps_f64| {
2218                    let fps = fps_f64 as u32;
2219
2220                    let resolution =
2221                        Resolution::new(resolution.width as u32, resolution.height as u32); // FIXME: what the fuck?
2222                    CameraFormat::new(resolution, fourcc, fps)
2223                })
2224                .collect::<Vec<_>>();
2225            a.sort_by(|a, b| a.frame_rate().cmp(&b.frame_rate()));
2226
2227            if a.len() != 0 {
2228                Ok(a[a.len() - 1])
2229            } else {
2230                Err(NokhwaError::GetPropertyError {
2231                    property: "activeFormat".to_string(),
2232                    error: "None??".to_string(),
2233                })
2234            }
2235        }
2236    }
2237
2238    impl AVCaptureDeviceInput {
2239        pub fn new(capture_device: &AVCaptureDevice) -> Result<Self, NokhwaError> {
2240            let cls = class!(AVCaptureDeviceInput);
2241            let err_ptr: *mut c_void = std::ptr::null_mut();
2242            let capture_input: *mut Object = unsafe {
2243                let allocated: *mut Object = msg_send![cls, alloc];
2244                msg_send![allocated, initWithDevice:capture_device.inner() error:err_ptr]
2245            };
2246            if !err_ptr.is_null() {
2247                return Err(NokhwaError::InitializeError {
2248                    backend: ApiBackend::AVFoundation,
2249                    error: "Failed to create input".to_string(),
2250                });
2251            }
2252
2253            Ok(AVCaptureDeviceInput {
2254                inner: capture_input,
2255            })
2256        }
2257    }
2258
2259    pub struct AVCaptureVideoDataOutput {
2260        inner: *mut Object,
2261    }
2262
2263    impl AVCaptureVideoDataOutput {
2264        pub fn new() -> Self {
2265            AVCaptureVideoDataOutput::default()
2266        }
2267
2268        pub fn add_delegate(&self, delegate: &AVCaptureVideoCallback) -> Result<(), NokhwaError> {
2269            unsafe {
2270                let _: () = msg_send![
2271                    self.inner,
2272                    setSampleBufferDelegate: delegate.delegate
2273                    queue: delegate.queue().0
2274                ];
2275            };
2276            Ok(())
2277        }
2278
2279        pub fn set_frame_format(&self, format: FrameFormat) -> Result<(), NokhwaError> {
2280            let cmpixelfmt = match format {
2281                FrameFormat::YUYV => kCMPixelFormat_422YpCbCr8_yuvs,
2282                FrameFormat::MJPEG => kCMVideoCodecType_JPEG,
2283                FrameFormat::GRAY => kCMPixelFormat_8IndexedGray_WhiteIsZero,
2284                FrameFormat::NV12 => kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange,
2285                FrameFormat::RAWRGB => kCMPixelFormat_24RGB,
2286                FrameFormat::RAWBGR => {
2287                    return Err(NokhwaError::SetPropertyError {
2288                        property: "setVideoSettings".to_string(),
2289                        value: "set frame format".to_string(),
2290                        error: "Unsupported frame format BGR".to_string(),
2291                    });
2292                }
2293            };
2294            let obj = CFNumber::from(cmpixelfmt as i32);
2295            let obj = obj.as_CFTypeRef() as *mut Object;
2296            let key = unsafe { kCVPixelBufferPixelFormatTypeKey } as *mut Object;
2297            let dict = unsafe { NSDictionary::dictionaryWithObject_forKey_(nil, obj, key) };
2298            let _: () = unsafe { msg_send![self.inner, setVideoSettings:dict] };
2299            Ok(())
2300        }
2301    }
2302
2303    use cocoa_foundation::base::nil;
2304    use core_foundation::base::TCFType;
2305    use core_foundation::number::CFNumber;
2306    use core_video_sys::kCVPixelBufferPixelFormatTypeKey;
2307    impl Default for AVCaptureVideoDataOutput {
2308        fn default() -> Self {
2309            let cls = class!(AVCaptureVideoDataOutput);
2310            let inner: *mut Object = unsafe { msg_send![cls, new] };
2311
2312            AVCaptureVideoDataOutput { inner }
2313        }
2314    }
2315
2316    impl AVCaptureSession {
2317        pub fn new() -> Self {
2318            AVCaptureSession::default()
2319        }
2320
2321        pub fn begin_configuration(&self) {
2322            unsafe { msg_send![self.inner, beginConfiguration] }
2323        }
2324
2325        pub fn commit_configuration(&self) {
2326            unsafe { msg_send![self.inner, commitConfiguration] }
2327        }
2328
2329        pub fn can_add_input(&self, input: &AVCaptureDeviceInput) -> bool {
2330            let result: BOOL = unsafe { msg_send![self.inner, canAddInput:input.inner] };
2331            result == YES
2332        }
2333
2334        pub fn add_input(&self, input: &AVCaptureDeviceInput) -> Result<(), NokhwaError> {
2335            if self.can_add_input(input) {
2336                let _: () = unsafe { msg_send![self.inner, addInput:input.inner] };
2337                return Ok(());
2338            }
2339            Err(NokhwaError::SetPropertyError {
2340                property: "AVCaptureDeviceInput".to_string(),
2341                value: "add new input".to_string(),
2342                error: "Rejected".to_string(),
2343            })
2344        }
2345
2346        pub fn remove_input(&self, input: &AVCaptureDeviceInput) {
2347            unsafe { msg_send![self.inner, removeInput:input.inner] }
2348        }
2349
2350        pub fn can_add_output(&self, output: &AVCaptureVideoDataOutput) -> bool {
2351            let result: BOOL = unsafe { msg_send![self.inner, canAddOutput:output.inner] };
2352            result == YES
2353        }
2354
2355        pub fn add_output(&self, output: &AVCaptureVideoDataOutput) -> Result<(), NokhwaError> {
2356            if self.can_add_output(output) {
2357                let _: () = unsafe { msg_send![self.inner, addOutput:output.inner] };
2358                return Ok(());
2359            }
2360            Err(NokhwaError::SetPropertyError {
2361                property: "AVCaptureVideoDataOutput".to_string(),
2362                value: "add new output".to_string(),
2363                error: "Rejected".to_string(),
2364            })
2365        }
2366
2367        pub fn remove_output(&self, output: &AVCaptureVideoDataOutput) {
2368            unsafe { msg_send![self.inner, removeOutput:output.inner] }
2369        }
2370
2371        pub fn is_running(&self) -> bool {
2372            let running: BOOL = unsafe { msg_send![self.inner, isRunning] };
2373            running == YES
2374        }
2375
2376        pub fn start(&self) -> Result<(), NokhwaError> {
2377            let start_stream_fn = || {
2378                let _: () = unsafe { msg_send![self.inner, startRunning] };
2379            };
2380
2381            if std::panic::catch_unwind(start_stream_fn).is_err() {
2382                return Err(NokhwaError::OpenStreamError(
2383                    "Cannot run AVCaptureSession".to_string(),
2384                ));
2385            }
2386            Ok(())
2387        }
2388
2389        pub fn stop(&self) {
2390            unsafe { msg_send![self.inner, stopRunning] }
2391        }
2392
2393        pub fn is_interrupted(&self) -> bool {
2394            let interrupted: BOOL = unsafe { msg_send![self.inner, isInterrupted] };
2395            interrupted == YES
2396        }
2397    }
2398
2399    impl Default for AVCaptureSession {
2400        fn default() -> Self {
2401            let cls = class!(AVCaptureSession);
2402            let session: *mut Object = {
2403                let alloc: *mut Object = unsafe { msg_send![cls, alloc] };
2404                unsafe { msg_send![alloc, init] }
2405            };
2406            AVCaptureSession { inner: session }
2407        }
2408    }
2409}
2410
2411#[cfg(any(target_os = "macos", target_os = "ios"))]
2412pub use crate::internal::*;