Add controls support for AVFoundation

This commit is contained in:
l1npengtul
2022-10-03 07:31:31 -07:00
parent 34b2b73981
commit 02e91fa951
5 changed files with 1007 additions and 131 deletions
+759 -40
View File
@@ -194,17 +194,15 @@ pub mod core_media {
use crate::core_media::{
dispatch_queue_create, AVCaptureExposureDurationCurrent, AVCaptureExposureTargetBiasCurrent,
AVCaptureISOCurrent, AVCaptureWhiteBalanceGains, AVMediaTypeVideo, CGPoint,
AVCaptureISOCurrent, AVCaptureWhiteBalanceGains, AVMediaTypeAudio, AVMediaTypeClosedCaption,
AVMediaTypeDepthData, AVMediaTypeMetadata, AVMediaTypeMetadataObject, AVMediaTypeMuxed,
AVMediaTypeSubtitle, AVMediaTypeText, AVMediaTypeTimecode, AVMediaTypeVideo, CGPoint,
CMSampleBufferGetImageBuffer, CMVideoFormatDescriptionGetDimensions, CVImageBufferRef,
CVPixelBufferGetBaseAddress, CVPixelBufferGetDataSize, CVPixelBufferLockBaseAddress,
CVPixelBufferUnlockBaseAddress, NSObject,
};
use crate::core_media::{
AVMediaTypeAudio, AVMediaTypeClosedCaption, AVMediaTypeDepthData, AVMediaTypeMetadata,
AVMediaTypeMetadataObject, AVMediaTypeMuxed, AVMediaTypeSubtitle, AVMediaTypeText,
AVMediaTypeTimecode, CVPixelBufferGetPixelFormatType,
CVPixelBufferGetBaseAddress, CVPixelBufferGetDataSize, CVPixelBufferGetPixelFormatType,
CVPixelBufferLockBaseAddress, CVPixelBufferUnlockBaseAddress, NSObject,
};
use block::ConcreteBlock;
use cocoa_foundation::base::Nil;
use cocoa_foundation::foundation::{NSArray, NSInteger, NSString, NSUInteger};
use core_media_sys::{
kCMPixelFormat_422YpCbCr8_yuvs, kCMPixelFormat_8IndexedGray_WhiteIsZero,
@@ -213,19 +211,20 @@ use core_media_sys::{
CMVideoDimensions,
};
use flume::{Receiver, Sender};
use nokhwa_core::types::{
CameraControl, ControlValueDescription, KnownCameraControl, KnownCameraControlFlag,
};
use nokhwa_core::types::ControlValueSetter;
use nokhwa_core::{
error::NokhwaError,
types::{ApiBackend, CameraFormat, CameraIndex, CameraInfo, FrameFormat, Resolution},
types::{
ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription,
FrameFormat, KnownCameraControl, KnownCameraControlFlag, Resolution,
},
};
use objc::runtime::NO;
use objc::{
declare::ClassDecl,
runtime::{Class, Object, Protocol, Sel, BOOL, YES},
runtime::{Class, Object, Protocol, Sel, BOOL, NO, YES},
};
use once_cell::sync::Lazy;
use std::collections::BTreeMap;
use std::{
borrow::Cow,
cmp::Ordering,
@@ -1071,7 +1070,7 @@ impl AVCaptureDevice {
// 4 => Exposure Target Bias
// 5 => Exposure ISO
// 6 => Exposure Duration
pub fn get_controls(&mut self) -> Result<Vec<CameraControl>, NokhwaError> {
pub fn get_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
let active_format: *mut Object = unsafe { msg_send![self.inner, activeFormat] };
let mut controls = vec![];
@@ -1123,7 +1122,10 @@ impl AVCaptureDevice {
default: (0.5, 0.5),
},
if focus_poi_supported == NO {
vec![KnownCameraControlFlag::Disabled]
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
} else {
vec![]
},
@@ -1147,7 +1149,10 @@ impl AVCaptureDevice {
if focus_manual == YES {
vec![]
} else {
vec![KnownCameraControlFlag::Disabled]
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
},
focus_manual == YES,
));
@@ -1204,7 +1209,10 @@ impl AVCaptureDevice {
default: (0.5, 0.5),
},
if exposure_poi_supported == NO {
vec![KnownCameraControlFlag::Disabled]
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
} else {
vec![]
},
@@ -1228,7 +1236,10 @@ impl AVCaptureDevice {
default: false,
},
if expposure_face_driven_supported == NO {
vec![KnownCameraControlFlag::Disabled]
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
} else {
vec![]
},
@@ -1260,7 +1271,7 @@ impl AVCaptureDevice {
unsafe { msg_send![active_format, maxExposureDuration] };
controls.push(CameraControl::new(
KnownCameraControl::Other(5),
KnownCameraControl::Gamma,
"ExposureDuration".to_string(),
ControlValueDescription::IntegerRange {
min: exposure_duration_min.value,
@@ -1285,7 +1296,7 @@ impl AVCaptureDevice {
let exposure_iso_max: f32 = unsafe { msg_send![active_format, maxISO] };
controls.push(CameraControl::new(
KnownCameraControl::Other(6),
KnownCameraControl::Brightness,
"ExposureISO".to_string(),
ControlValueDescription::FloatRange {
min: exposure_iso_min as f64,
@@ -1308,7 +1319,7 @@ impl AVCaptureDevice {
let lens_aperture: f32 = unsafe { msg_send![self.inner, lensAperture] };
controls.push(CameraControl::new(
KnownCameraControl::Other(7),
KnownCameraControl::Iris,
"LensAperture".to_string(),
ControlValueDescription::Float {
value: lens_aperture as f64,
@@ -1422,15 +1433,18 @@ impl AVCaptureDevice {
}
controls.push(CameraControl::new(
KnownCameraControl::Other(8),
"Flash".to_string(),
KnownCameraControl::Other(5),
"TorchMode".to_string(),
ControlValueDescription::Enum {
value: (torch_active == YES) as i64,
possible,
default: 0,
},
if has_torch == YES {
vec![KnownCameraControlFlag::Disabled]
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
} else {
vec![]
},
@@ -1443,24 +1457,18 @@ impl AVCaptureDevice {
let llb_enabled: BOOL = unsafe { msg_send![self.inner, lowLightBoostEnabled] };
{
let mut possible = vec![];
if has_llb == YES {
possible.push(0); // off
possible.push(1); // on
possible.push(2); // auto
}
controls.push(CameraControl::new(
KnownCameraControl::BacklightComp,
"LowLightCompensation".to_string(),
ControlValueDescription::Enum {
value: (llb_enabled == YES) as i64,
possible,
default: 0,
ControlValueDescription::Boolean {
value: llb_enabled == YES,
default: false,
},
if has_llb == YES {
vec![KnownCameraControlFlag::Disabled]
if has_llb == NO {
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
} else {
vec![]
},
@@ -1494,7 +1502,7 @@ impl AVCaptureDevice {
unsafe { msg_send![self.inner, geometricDistortionCorrectionEnabled] };
controls.push(CameraControl::new(
KnownCameraControl::Other(9),
KnownCameraControl::Other(6),
"DistortionCorrection".to_string(),
ControlValueDescription::Boolean {
value: distortion_correction_current_value == YES,
@@ -1513,6 +1521,717 @@ impl AVCaptureDevice {
Ok(controls)
}
pub fn set_control(
&mut self,
id: KnownCameraControl,
value: ControlValueSetter,
) -> Result<(), NokhwaError> {
let rc = self.get_controls()?;
let controls = rc
.iter()
.map(|cc| (cc.control(), cc))
.collect::<BTreeMap<_, _>>();
match id {
KnownCameraControl::Brightness => {
let isoctrl = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if isoctrl.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Exposure is in improper state to set ISO (Please set to `custom`!)"
.to_string(),
});
}
if isoctrl.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let current_duration = unsafe { AVCaptureExposureDurationCurrent };
let new_iso = *value.as_float().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected float".to_string(),
})? as f32;
if !isoctrl.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![self.inner, setExposureModeCustomWithDuration:current_duration ISO:new_iso completionHandler:Nil]
};
Ok(())
}
KnownCameraControl::Gamma => {
let duration_ctrl = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if duration_ctrl
.flag()
.contains(&KnownCameraControlFlag::ReadOnly)
{
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Exposure is in improper state to set Duration (Please set to `custom`!)"
.to_string(),
});
}
if duration_ctrl
.flag()
.contains(&KnownCameraControlFlag::Disabled)
{
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let current_duration: CMTime = unsafe { msg_send![self.inner, exposureDuration] };
let current_iso = unsafe { AVCaptureISOCurrent };
let new_duration = CMTime {
value: *value.as_integer().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected i64".to_string(),
})?,
timescale: current_duration.timescale,
flags: current_duration.flags,
epoch: current_duration.epoch,
};
if !duration_ctrl.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![self.inner, setExposureModeCustomWithDuration:new_duration ISO:current_iso completionHandler:Nil]
};
Ok(())
}
KnownCameraControl::WhiteBalance => {
let wb_enum_value = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if wb_enum_value
.flag()
.contains(&KnownCameraControlFlag::ReadOnly)
{
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if wb_enum_value
.flag()
.contains(&KnownCameraControlFlag::Disabled)
{
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter =
NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Enum".to_string(),
})? as i32);
if !wb_enum_value.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, whiteBalanceMode: setter] };
Ok(())
}
KnownCameraControl::BacklightComp => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter =
NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Enum".to_string(),
})? as i32);
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, whiteBalanceMode: setter] };
Ok(())
}
KnownCameraControl::Gain => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter =
NSInteger::from(*value.as_boolean().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Boolean".to_string(),
})? as i32);
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, whiteBalanceMode: setter] };
Ok(())
}
KnownCameraControl::Zoom => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = *value.as_float().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected float".to_string(),
})? as c_float;
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![self.inner, rampToVideoZoomFactor: setter withRate: 1.0_f32]
};
Ok(())
}
KnownCameraControl::Exposure => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter =
NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Enum".to_string(),
})? as i32);
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, exposureMode: setter] };
Ok(())
}
KnownCameraControl::Iris => Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
}),
KnownCameraControl::Focus => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter =
NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Enum".to_string(),
})? as i32);
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, focusMode: setter] };
Ok(())
}
KnownCameraControl::Other(i) => match i {
0 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = value
.as_point()
.ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Point".to_string(),
})
.map(|(x, y)| CGPoint {
x: *x as f32,
y: *y as f32,
})?;
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, focusPointOfInterest: setter] };
Ok(())
}
1 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = *value.as_float().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected float".to_string(),
})? as c_float;
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![self.inner, setFocusModeLockedWithLensPosition: setter handler: Nil]
};
Ok(())
}
2 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = value
.as_point()
.ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Point".to_string(),
})
.map(|(x, y)| CGPoint {
x: *x as f32,
y: *y as f32,
})?;
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, exposurePointOfInterest: setter] };
Ok(())
}
3 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = if *value.as_boolean().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Boolean".to_string(),
})? {
YES
} else {
NO
};
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![
self.inner,
automaticallyAdjustsFaceDrivenAutoExposureEnabled: setter
]
};
Ok(())
}
4 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = *value.as_float().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Float".to_string(),
})? as f32;
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![self.inner, setExposureTargetBias: setter handler: Nil]
};
Ok(())
}
5 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter =
NSInteger::from(*value.as_enum().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Enum".to_string(),
})? as i32);
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe { msg_send![self.inner, torchMode: setter] };
Ok(())
}
6 => {
let ctrlvalue = controls.get(&id).ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Control does not exist".to_string(),
})?;
if ctrlvalue.flag().contains(&KnownCameraControlFlag::ReadOnly) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Read Only".to_string(),
});
}
if ctrlvalue.flag().contains(&KnownCameraControlFlag::Disabled) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Disabled".to_string(),
});
}
let setter = if *value.as_boolean().ok_or(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Expected Boolean".to_string(),
})? {
YES
} else {
NO
};
if !ctrlvalue.description().verify_setter(&value) {
return Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Failed to verify value".to_string(),
});
}
let _: () = unsafe {
msg_send![self.inner, geometricDistortionCorrectionEnabled: setter]
};
Ok(())
}
_ => Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Unknown Control".to_string(),
}),
},
_ => Err(NokhwaError::SetPropertyError {
property: id.to_string(),
value: value.to_string(),
error: "Unknown Control".to_string(),
}),
}
}
}
impl Drop for AVCaptureDevice {
+1
View File
@@ -1,5 +1,6 @@
//! Core type definitions for `nokhwa`
extern crate core;
extern crate core;
pub mod buffer;
+2 -3
View File
@@ -21,7 +21,7 @@ use image::{Luma, LumaA, Pixel, Rgb, Rgba};
use std::fmt::Debug;
/// Trait that has methods to convert raw data from the webcam to a proper raw image.
pub trait FormatDecoder: Copy + Clone + Debug + Default + Sized + Send + Sync + {
pub trait FormatDecoder: Copy + Clone + Debug + Default + Sized + Send + Sync {
type Output: Pixel<Subpixel = u8>;
const FORMATS: &'static [FrameFormat];
@@ -52,7 +52,7 @@ pub struct RgbFormat;
impl FormatDecoder for RgbFormat {
type Output = Rgb<u8>;
const FORMATS: &'static [FrameFormat] = &[FrameFormat::MJPEG, FrameFormat::YUYV];
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
match fcc {
FrameFormat::MJPEG => mjpeg_to_rgb(data, false),
@@ -168,7 +168,6 @@ impl FormatDecoder for LumaFormat {
const FORMATS: &'static [FrameFormat] =
&[FrameFormat::MJPEG, FrameFormat::YUYV, FrameFormat::GRAY];
#[allow(clippy::cast_possible_truncation)]
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
+229 -85
View File
@@ -37,23 +37,26 @@ impl Display for RequestedFormatType {
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct RequestedFormat<F>
where
F: FormatDecoder,
{
pub struct RequestedFormat {
requested_format: RequestedFormatType,
wanted_decoder: F,
wanted_decoder: &'static [FrameFormat],
}
impl<F> RequestedFormat<F>
where
F: FormatDecoder,
{
pub fn new<Decoder: FormatDecoder>(requested: RequestedFormatType) -> RequestedFormat<Decoder> {
impl RequestedFormat {
pub fn new<Decoder: FormatDecoder>(requested: RequestedFormatType) -> RequestedFormat {
RequestedFormat {
requested_format: requested,
wanted_decoder: Decoder::default(),
wanted_decoder: Decoder::FORMATS,
}
}
pub fn with_formats(
requested: RequestedFormatType,
decoder: &'static [FrameFormat],
) -> RequestedFormat {
RequestedFormat {
requested_format: requested,
wanted_decoder: decoder,
}
}
@@ -68,7 +71,7 @@ where
.into_iter()
.filter(|fmt| {
fmt.resolution() == resolution.resolution()
&& F::FORMATS.contains(&fmt.format())
&& self.wanted_decoder.contains(&fmt.format())
})
.collect::<Vec<CameraFormat>>();
format_resolutions.sort_by_key(|a| a.frame_rate());
@@ -82,14 +85,14 @@ where
.into_iter()
.filter(|fmt| {
fmt.frame_rate() == frame_rate.frame_rate()
&& F::FORMATS.contains(&fmt.format())
&& self.wanted_decoder.contains(&fmt.format())
})
.collect::<Vec<CameraFormat>>();
format_framerates.sort_by_key(|a| a.resolution());
format_framerates.last().copied()
}
RequestedFormatType::Exact(fmt) => {
if F::FORMATS.contains(&fmt.format()) {
if self.wanted_decoder.contains(&fmt.format()) {
Some(fmt)
} else {
None
@@ -98,7 +101,9 @@ where
RequestedFormatType::Closest(c) => {
let same_fmt_formats = all_formats
.iter()
.filter(|x| x.format() == c.format() && F::FORMATS.contains(&x.format()))
.filter(|x| {
x.format() == c.format() && self.wanted_decoder.contains(&x.format())
})
.copied()
.collect::<Vec<CameraFormat>>();
let mut resolution_map = same_fmt_formats
@@ -138,17 +143,14 @@ where
}
RequestedFormatType::None => all_formats
.iter()
.filter(|fmt| F::FORMATS.contains(&fmt.format()))
.filter(|fmt| self.wanted_decoder.contains(&fmt.format()))
.nth(0)
.copied(),
}
}
}
impl<F> Display for RequestedFormat<F>
where
F: FormatDecoder,
{
impl Display for RequestedFormat {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
@@ -763,74 +765,138 @@ impl ControlValueDescription {
/// - `false` => Is not valid.
#[must_use]
pub fn verify_setter(&self, setter: &ControlValueSetter) -> bool {
match setter {
ControlValueSetter::None => {
matches!(self, ControlValueDescription::None)
}
ControlValueSetter::Integer(i) => match self {
ControlValueDescription::Integer {
value,
default,
step,
} => (i - default).abs() % step == 0 || (i - value) % step == 0,
ControlValueDescription::IntegerRange {
min,
max,
value,
step,
default,
} => {
if value > max || value < min {
return false;
}
(i - default) % step == 0 || (i - value) % step == 0
}
_ => false,
match self {
ControlValueDescription::None => return setter.as_none().is_some(),
ControlValueDescription::Integer {
value,
default,
step,
} => match setter.as_integer() {
Some(i) => (i + default) % step == 0 || (i + value) % step == 0,
None => false,
},
ControlValueSetter::Float(f) => match self {
ControlValueDescription::Float {
value,
default,
step,
} => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64,
ControlValueDescription::FloatRange {
min,
max,
value,
step,
default,
} => {
if value > max || value < min {
return false;
}
(f - default) % step == 0_f64 || (f - value) % step == 0_f64
ControlValueDescription::IntegerRange {
min,
max,
value,
step,
default,
} => match setter.as_integer() {
Some(i) => {
((i + default) % step == 0 || (i + value) % step == 0) && i >= min && i <= max
}
_ => false,
None => false,
},
ControlValueDescription::Float {
value,
default,
step,
} => match setter.as_float() {
Some(f) => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64,
None => false,
},
ControlValueDescription::FloatRange {
min,
max,
value,
step,
default,
} => match setter.as_float() {
Some(f) => {
((f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64)
&& f >= min
&& f <= max
}
None => false,
},
ControlValueDescription::Boolean { .. } => setter.as_boolean().is_some(),
ControlValueDescription::String { .. } => setter.as_str().is_some(),
ControlValueDescription::Bytes { .. } => setter.as_bytes().is_some(),
ControlValueDescription::KeyValuePair { .. } => setter.as_key_value().is_some(),
ControlValueDescription::Point { .. } => match setter.as_point() {
Some(pt) => {
!pt.0.is_nan() && !pt.1.is_nan() && pt.0.is_finite() && pt.1.is_finite()
}
None => false,
},
ControlValueDescription::Enum { possible, .. } => match setter.as_enum() {
Some(e) => possible.contains(e),
None => false,
},
ControlValueDescription::RGB { max, .. } => match setter.as_rgb() {
Some(v) => *v.0 >= max.0 && *v.1 >= max.1 && *v.2 >= max.2,
None => false,
},
ControlValueSetter::Boolean(_) => {
matches!(self, ControlValueDescription::Boolean { .. })
}
ControlValueSetter::String(_) => {
matches!(self, ControlValueDescription::String { .. })
}
ControlValueSetter::Bytes(_) => {
matches!(self, ControlValueDescription::Bytes { .. })
}
ControlValueSetter::KeyValue(_, _) => {
matches!(self, ControlValueDescription::KeyValuePair { .. })
}
ControlValueSetter::Point(_, _) => {
matches!(self, ControlValueDescription::Point { .. })
}
ControlValueSetter::EnumValue(_) => {
matches!(self, ControlValueDescription::Enum { .. })
}
ControlValueSetter::RGB(_, _, _) => {
matches!(self, ControlValueDescription::RGB { .. })
}
}
// match setter {
// ControlValueSetter::None => {
// matches!(self, ControlValueDescription::None)
// }
// ControlValueSetter::Integer(i) => match self {
// ControlValueDescription::Integer {
// value,
// default,
// step,
// } => (i - default).abs() % step == 0 || (i - value) % step == 0,
// ControlValueDescription::IntegerRange {
// min,
// max,
// value,
// step,
// default,
// } => {
// if value > max || value < min {
// return false;
// }
//
// (i - default) % step == 0 || (i - value) % step == 0
// }
// _ => false,
// },
// ControlValueSetter::Float(f) => match self {
// ControlValueDescription::Float {
// value,
// default,
// step,
// } => (f - default).abs() % step == 0_f64 || (f - value) % step == 0_f64,
// ControlValueDescription::FloatRange {
// min,
// max,
// value,
// step,
// default,
// } => {
// if value > max || value < min {
// return false;
// }
//
// (f - default) % step == 0_f64 || (f - value) % step == 0_f64
// }
// _ => false,
// },
// ControlValueSetter::Boolean(b) => {
//
// }
// ControlValueSetter::String(_) => {
// matches!(self, ControlValueDescription::String { .. })
// }
// ControlValueSetter::Bytes(_) => {
// matches!(self, ControlValueDescription::Bytes { .. })
// }
// ControlValueSetter::KeyValue(_, _) => {
// matches!(self, ControlValueDescription::KeyValuePair { .. })
// }
// ControlValueSetter::Point(_, _) => {
// matches!(self, ControlValueDescription::Point { .. })
// }
// ControlValueSetter::EnumValue(_) => {
// matches!(self, ControlValueDescription::Enum { .. })
// }
// ControlValueSetter::RGB(_, _, _) => {
// matches!(self, ControlValueDescription::RGB { .. })
// }
// }
}
}
@@ -1057,6 +1123,84 @@ pub enum ControlValueSetter {
RGB(f64, f64, f64),
}
impl ControlValueSetter {
pub fn as_none(&self) -> Option<()> {
if let ControlValueSetter::None = self {
Some(())
} else {
None
}
}
pub fn as_integer(&self) -> Option<&i64> {
if let ControlValueSetter::Integer(i) = self {
Some(i)
} else {
None
}
}
pub fn as_float(&self) -> Option<&f64> {
if let ControlValueSetter::Float(f) = self {
Some(f)
} else {
None
}
}
pub fn as_boolean(&self) -> Option<&bool> {
if let ControlValueSetter::Boolean(f) = self {
Some(f)
} else {
None
}
}
pub fn as_str(&self) -> Option<&str> {
if let ControlValueSetter::String(s) = self {
Some(s)
} else {
None
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
if let ControlValueSetter::Bytes(b) = self {
Some(b)
} else {
None
}
}
pub fn as_key_value(&self) -> Option<(&i128, &i128)> {
if let ControlValueSetter::KeyValue(k, v) = self {
Some((k, v))
} else {
None
}
}
pub fn as_point(&self) -> Option<(&f64, &f64)> {
if let ControlValueSetter::Point(x, y) = self {
Some((x, y))
} else {
None
}
}
pub fn as_enum(&self) -> Option<&i64> {
if let ControlValueSetter::EnumValue(e) = self {
Some(e)
} else {
None
}
}
pub fn as_rgb(&self) -> Option<(&f64, &f64, &f64)> {
if let ControlValueSetter::RGB(r, g, b) = self {
Some((r, g, b))
} else {
None
}
}
}
impl Display for ControlValueSetter {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
+16 -3
View File
@@ -27,6 +27,7 @@ use nokhwa_core::{
FrameFormat, KnownCameraControl, RequestedFormat, Resolution,
},
};
use std::collections::BTreeMap;
use std::ffi::CString;
use std::{
borrow::Cow,
@@ -201,11 +202,20 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
}
fn camera_control(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
todo!()
for ctrl in self.device.get_controls()? {
if ctrl.control() == control {
return Ok(ctrl);
}
}
return Err(NokhwaError::GetPropertyError {
property: control.to_string(),
error: "Not Found".to_string(),
});
}
fn camera_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
todo!()
self.device.get_controls()
}
fn set_camera_control(
@@ -213,7 +223,10 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
id: KnownCameraControl,
value: ControlValueSetter,
) -> Result<(), NokhwaError> {
todo!()
self.device.lock()?;
let res = self.device.set_control(id, value);
self.device.unlock()?;
res
}
fn open_stream(&mut self) -> Result<(), NokhwaError> {