fix glaring API flaw with RequestedFormat, add control detection for AVFoundation

This commit is contained in:
l1npengtul
2022-10-02 05:55:05 -07:00
parent 7c274634f4
commit ee3056d1ec
6 changed files with 673 additions and 42 deletions
+485 -8
View File
@@ -29,6 +29,7 @@ extern crate objc;
pub mod core_media {
// all of this is stolen from bindgen
// steal it idc
use crate::CGFloat;
use core_media_sys::{
CMBlockBufferRef, CMFormatDescriptionRef, CMSampleBufferRef, CMTime, CMVideoDimensions,
FourCharCode,
@@ -120,11 +121,28 @@ pub mod core_media {
pub fn CVPixelBufferGetPixelFormatType(pixelBuffer: CVPixelBufferRef) -> OSType;
}
#[repr(C)]
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct CGPoint {
pub x: CGFloat,
pub y: CGFloat,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __CVBuffer {
_unused: [u8; 0],
}
#[allow(non_snake_case)]
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
#[repr(C)]
pub struct AVCaptureWhiteBalanceGains {
pub blueGain: f32,
pub greenGain: f32,
pub redGain: f32,
}
pub type CVBufferRef = *mut __CVBuffer;
pub type CVImageBufferRef = CVBufferRef;
@@ -166,14 +184,20 @@ pub mod core_media {
pub static AVMediaTypeMuxed: AVMediaType;
pub static AVMediaTypeMetadataObject: AVMediaType;
pub static AVMediaTypeDepthData: AVMediaType;
pub static AVCaptureLensPositionCurrent: f32;
pub static AVCaptureExposureTargetBiasCurrent: f32;
pub static AVCaptureExposureDurationCurrent: CMTime;
pub static AVCaptureISOCurrent: f32;
}
}
use crate::core_media::{
dispatch_queue_create, AVMediaTypeVideo, CMSampleBufferGetImageBuffer,
CMVideoFormatDescriptionGetDimensions, CVImageBufferRef, CVPixelBufferGetBaseAddress,
CVPixelBufferGetDataSize, CVPixelBufferLockBaseAddress, CVPixelBufferUnlockBaseAddress,
NSObject,
dispatch_queue_create, AVCaptureExposureDurationCurrent, AVCaptureExposureTargetBiasCurrent,
AVCaptureISOCurrent, AVCaptureWhiteBalanceGains, AVMediaTypeVideo, CGPoint,
CMSampleBufferGetImageBuffer, CMVideoFormatDescriptionGetDimensions, CVImageBufferRef,
CVPixelBufferGetBaseAddress, CVPixelBufferGetDataSize, CVPixelBufferLockBaseAddress,
CVPixelBufferUnlockBaseAddress, NSObject,
};
use crate::core_media::{
AVMediaTypeAudio, AVMediaTypeClosedCaption, AVMediaTypeDepthData, AVMediaTypeMetadata,
@@ -185,14 +209,18 @@ use cocoa_foundation::foundation::{NSArray, NSInteger, NSString, NSUInteger};
use core_media_sys::{
kCMPixelFormat_422YpCbCr8_yuvs, kCMPixelFormat_8IndexedGray_WhiteIsZero,
kCMVideoCodecType_422YpCbCr8, kCMVideoCodecType_JPEG, kCMVideoCodecType_JPEG_OpenDML,
CMFormatDescriptionGetMediaSubType, CMFormatDescriptionRef, CMSampleBufferRef,
CMFormatDescriptionGetMediaSubType, CMFormatDescriptionRef, CMSampleBufferRef, CMTime,
CMVideoDimensions,
};
use flume::{Receiver, Sender};
use nokhwa_core::types::{
CameraControl, ControlValueDescription, KnownCameraControl, KnownCameraControlFlag,
};
use nokhwa_core::{
error::NokhwaError,
types::{ApiBackend, CameraFormat, CameraIndex, CameraInfo, FrameFormat, Resolution},
};
use objc::runtime::NO;
use objc::{
declare::ClassDecl,
runtime::{Class, Object, Protocol, Sel, BOOL, YES},
@@ -204,11 +232,12 @@ use std::{
collections::HashSet,
convert::TryFrom,
error::Error,
ffi::{c_void, CStr},
ffi::{c_float, c_void, CStr},
sync::{Arc, Mutex},
};
const UTF8_ENCODING: usize = 4;
type CGFloat = c_float;
macro_rules! create_boilerplate_impl {
{
@@ -336,8 +365,6 @@ static CALLBACK_CLASS: Lazy<&'static Class> = Lazy::new(|| {
// frame stack
// oooh scary provenannce-breaking BULLSHIT AAAAAA I LOVE TYPE ERASURE
decl.add_ivar::<*const c_void>("_arcmutptr"); // ArkMutex, the not-arknights totally not gacha totally not ripoff new vidya game from l-pleasestop-npengtul
// KILL ME KILL ME KILL ME PLEASE KILL ME I DONT WANT TO LIVE ANYMORE
// i draw myself getting hurt and murdered in various ways to distract from my urges self harm
extern "C" fn my_callback_get_arcmutptr(this: &Object, _: Sel) -> *const c_void {
unsafe { *this.get_ivar("_arcmutptr") }
@@ -1036,6 +1063,456 @@ impl AVCaptureDevice {
self.unlock();
Ok(())
}
// 0 => Focus POI
// 1 => Focus Manual Setting
// 2 => Exposure POI
// 3 => Exposure Face Driven
// 4 => Exposure Target Bias
// 5 => Exposure ISO
// 6 => Exposure Duration
pub fn get_controls(&mut self) -> Result<Vec<CameraControl>, NokhwaError> {
let active_format: *mut Object = unsafe { msg_send![self.inner, activeFormat] };
let mut controls = vec![];
// get focus modes
let focus_current: NSInteger = unsafe { msg_send![self.inner, focusMode] };
let focus_locked: BOOL =
unsafe { msg_send![self.inner, isFocusModeSupported:NSInteger::from(0)] };
let focus_auto: BOOL =
unsafe { msg_send![self.inner, isFocusModeSupported:NSInteger::from(1)] };
let focus_continuous: BOOL =
unsafe { msg_send![self.inner, isFocusModeSupported:NSInteger::from(2)] };
{
let mut supported_focus_values = vec![];
if focus_locked == YES {
supported_focus_values.push(0)
}
if focus_auto == YES {
supported_focus_values.push(1)
}
if focus_continuous == YES {
supported_focus_values.push(2)
}
controls.push(CameraControl::new(
KnownCameraControl::Focus,
"FocusMode".to_string(),
ControlValueDescription::Enum {
value: focus_current,
possible: supported_focus_values,
default: focus_current,
},
vec![],
true,
));
}
let focus_poi_supported: BOOL =
unsafe { msg_send![self.inner, isFocusPointOfInterestSupported] };
let focus_poi: CGPoint = unsafe { msg_send![self.inner, focusPointOfInterest] };
controls.push(CameraControl::new(
KnownCameraControl::Other(0),
"FocusPointOfInterest".to_string(),
ControlValueDescription::Point {
value: (focus_poi.x as f64, focus_poi.y as f64),
default: (0.5, 0.5),
},
if focus_poi_supported == NO {
vec![KnownCameraControlFlag::Disabled]
} else {
vec![]
},
focus_auto == YES || focus_continuous == YES,
));
let focus_manual: BOOL =
unsafe { msg_send![self.inner, isLockingFocusWithCustomLensPositionSupported] };
let focus_lenspos: f32 = unsafe { msg_send![self.inner, lensPosition] };
controls.push(CameraControl::new(
KnownCameraControl::Other(1),
"FocusManualLensPosition".to_string(),
ControlValueDescription::FloatRange {
min: 0.0,
max: 1.0,
value: focus_lenspos as f64,
step: f64::MIN_POSITIVE,
default: 1.0,
},
if focus_manual == YES {
vec![]
} else {
vec![KnownCameraControlFlag::Disabled]
},
focus_manual == YES,
));
// get exposures
let exposure_current: NSInteger = unsafe { msg_send![self.inner, exposureMode] };
let exposure_locked: BOOL =
unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(0)] };
let exposure_auto: BOOL =
unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(1)] };
let exposure_continuous: BOOL =
unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(2)] };
let exposure_custom: BOOL =
unsafe { msg_send![self.inner, isExposureModeSupported:NSInteger::from(3)] };
{
let mut supported_exposure_values = vec![];
if exposure_locked == YES {
supported_exposure_values.push(0);
}
if exposure_auto == YES {
supported_exposure_values.push(1);
}
if exposure_continuous == YES {
supported_exposure_values.push(2);
}
if exposure_custom == YES {
supported_exposure_values.push(3);
}
controls.push(CameraControl::new(
KnownCameraControl::Exposure,
"ExposureMode".to_string(),
ControlValueDescription::Enum {
value: exposure_current,
possible: supported_exposure_values,
default: exposure_current,
},
vec![],
true,
));
}
let exposure_poi_supported: BOOL =
unsafe { msg_send![self.inner, isExposurePointOfInterestSupported] };
let exposure_poi: CGPoint = unsafe { msg_send![self.inner, exposurePointOfInterest] };
controls.push(CameraControl::new(
KnownCameraControl::Other(2),
"ExposurePointOfInterest".to_string(),
ControlValueDescription::Point {
value: (exposure_poi.x as f64, exposure_poi.y as f64),
default: (0.5, 0.5),
},
if exposure_poi_supported == NO {
vec![KnownCameraControlFlag::Disabled]
} else {
vec![]
},
focus_auto == YES || focus_continuous == YES,
));
let expposure_face_driven_supported: BOOL =
unsafe { msg_send![self.inner, isFaceDrivenAutoExposureEnabled] };
let exposure_face_driven: BOOL = unsafe {
msg_send![
self.inner,
automaticallyAdjustsFaceDrivenAutoExposureEnabled
]
};
controls.push(CameraControl::new(
KnownCameraControl::Other(3),
"ExposureFaceDriven".to_string(),
ControlValueDescription::Boolean {
value: exposure_face_driven == YES,
default: false,
},
if expposure_face_driven_supported == NO {
vec![KnownCameraControlFlag::Disabled]
} else {
vec![]
},
exposure_poi_supported == YES,
));
let exposure_bias: f32 = unsafe { msg_send![self.inner, exposureTargetBias] };
let exposure_bias_min: f32 = unsafe { msg_send![self.inner, minExposureTargetBias] };
let exposure_bias_max: f32 = unsafe { msg_send![self.inner, maxExposureTargetBias] };
controls.push(CameraControl::new(
KnownCameraControl::Other(4),
"ExposureBiasTarget".to_string(),
ControlValueDescription::FloatRange {
min: exposure_bias_min as f64,
max: exposure_bias_max as f64,
value: exposure_bias as f64,
step: f32::MIN_POSITIVE as f64,
default: unsafe { AVCaptureExposureTargetBiasCurrent } as f64,
},
vec![],
true,
));
let exposure_duration: CMTime = unsafe { msg_send![self.inner, exposureDuration] };
let exposure_duration_min: CMTime =
unsafe { msg_send![active_format, minExposureDuration] };
let exposure_duration_max: CMTime =
unsafe { msg_send![active_format, maxExposureDuration] };
controls.push(CameraControl::new(
KnownCameraControl::Other(5),
"ExposureDuration".to_string(),
ControlValueDescription::IntegerRange {
min: exposure_duration_min.value,
max: exposure_duration_max.value,
value: exposure_duration.value,
step: 1,
default: unsafe { AVCaptureExposureDurationCurrent.value },
},
if exposure_custom == YES {
vec![
KnownCameraControlFlag::ReadOnly,
KnownCameraControlFlag::Volatile,
]
} else {
vec![KnownCameraControlFlag::Volatile]
},
exposure_custom == YES,
));
let exposure_iso: f32 = unsafe { msg_send![self.inner, ISO] };
let exposure_iso_min: f32 = unsafe { msg_send![active_format, minISO] };
let exposure_iso_max: f32 = unsafe { msg_send![active_format, maxISO] };
controls.push(CameraControl::new(
KnownCameraControl::Other(6),
"ExposureISO".to_string(),
ControlValueDescription::FloatRange {
min: exposure_iso_min as f64,
max: exposure_iso_max as f64,
value: exposure_iso as f64,
step: f32::MIN_POSITIVE as f64,
default: unsafe { AVCaptureISOCurrent } as f64,
},
if exposure_custom == YES {
vec![
KnownCameraControlFlag::ReadOnly,
KnownCameraControlFlag::Volatile,
]
} else {
vec![KnownCameraControlFlag::Volatile]
},
exposure_custom == YES,
));
let lens_aperture: f32 = unsafe { msg_send![self.inner, lensAperture] };
controls.push(CameraControl::new(
KnownCameraControl::Other(7),
"LensAperture".to_string(),
ControlValueDescription::Float {
value: lens_aperture as f64,
default: lens_aperture as f64,
step: lens_aperture as f64,
},
vec![KnownCameraControlFlag::ReadOnly],
false,
));
// get whiteblaance
let white_balance_current: NSInteger = unsafe { msg_send![self.inner, whiteBalanceMode] };
let white_balance_manual: BOOL =
unsafe { msg_send![self.inner, isWhiteBalanceModeSupported:NSInteger::from(0)] };
let white_balance_auto: BOOL =
unsafe { msg_send![self.inner, isWhiteBalanceModeSupported:NSInteger::from(1)] };
let white_balance_continuous: BOOL =
unsafe { msg_send![self.inner, isWhiteBalanceModeSupported:NSInteger::from(2)] };
{
let mut possible = vec![];
if white_balance_manual == YES {
possible.push(0);
}
if white_balance_auto == YES {
possible.push(1);
}
if white_balance_continuous == YES {
possible.push(2);
}
controls.push(CameraControl::new(
KnownCameraControl::WhiteBalance,
"WhiteBalanceMode".to_string(),
ControlValueDescription::Enum {
value: white_balance_current as i64,
possible,
default: 0,
},
vec![],
true,
));
}
let white_balance_gains: AVCaptureWhiteBalanceGains =
unsafe { msg_send![self.inner, deviceWhiteBalanceGains] };
let white_balance_default: AVCaptureWhiteBalanceGains =
unsafe { msg_send![self.inner, grayWorldDeviceWhiteBalanceGains] };
let white_balancne_max: AVCaptureWhiteBalanceGains =
unsafe { msg_send![self.inner, maxWhiteBalanceGain] };
let white_balance_gain_supported: BOOL = unsafe {
msg_send![
self.inner,
isLockingWhiteBalanceWithCustomDeviceGainsSupported
]
};
controls.push(CameraControl::new(
KnownCameraControl::Gain,
"WhiteBalanceGain".to_string(),
ControlValueDescription::RGB {
value: (
white_balance_gains.redGain as f64,
white_balance_gains.greenGain as f64,
white_balance_gains.blueGain as f64,
),
max: (
white_balancne_max.redGain as f64,
white_balancne_max.greenGain as f64,
white_balancne_max.blueGain as f64,
),
default: (
white_balance_default.redGain as f64,
white_balance_default.greenGain as f64,
white_balance_default.blueGain as f64,
),
},
if white_balance_gain_supported == YES {
vec![
KnownCameraControlFlag::Disabled,
KnownCameraControlFlag::ReadOnly,
]
} else {
vec![]
},
white_balance_gain_supported == YES,
));
// get flash
let has_torch: BOOL = unsafe { msg_send![self.inner, torchAvailible] };
let torch_active: BOOL = unsafe { msg_send![self.inner, isTorchActive] };
let torch_off: BOOL =
unsafe { msg_send![self.inner, isTorchModeSupported:NSInteger::from(0)] };
let torch_on: BOOL =
unsafe { msg_send![self.inner, isTorchModeSupported:NSInteger::from(1)] };
let torch_auto: BOOL =
unsafe { msg_send![self.inner, isTorchModeSupported:NSInteger::from(2)] };
{
let mut possible = vec![];
if torch_off == YES {
possible.push(0);
}
if torch_on == YES {
possible.push(1);
}
if torch_auto == YES {
possible.push(2);
}
controls.push(CameraControl::new(
KnownCameraControl::Other(8),
"Flash".to_string(),
ControlValueDescription::Enum {
value: (torch_active == YES) as i64,
possible,
default: 0,
},
if has_torch == YES {
vec![KnownCameraControlFlag::Disabled]
} else {
vec![]
},
has_torch == YES,
));
}
// get low light boost
let has_llb: BOOL = unsafe { msg_send![self.inner, lowLightBoostSupported] };
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,
},
if has_llb == YES {
vec![KnownCameraControlFlag::Disabled]
} else {
vec![]
},
has_llb == YES,
));
}
// get zoom factor
let zoom_current: CGFloat = unsafe { msg_send![self.inner, videoZoomFactor] };
let zoom_min: CGFloat = unsafe { msg_send![self.inner, minAvailableVideoZoomFactor] };
let zoom_max: CGFloat = unsafe { msg_send![self.inner, maxAvailableVideoZoomFactor] };
controls.push(CameraControl::new(
KnownCameraControl::Zoom,
"Zoom".to_string(),
ControlValueDescription::FloatRange {
min: zoom_min as f64,
max: zoom_max as f64,
value: zoom_current as f64,
step: f32::MIN_POSITIVE as f64,
default: 1.0,
},
vec![],
true,
));
// zoom distortion correction
let distortion_correction_supported: BOOL =
unsafe { msg_send![self.inner, geometricDistortionCorrectionSupported] };
let distortion_correction_current_value: BOOL =
unsafe { msg_send![self.inner, geometricDistortionCorrectionEnabled] };
controls.push(CameraControl::new(
KnownCameraControl::Other(9),
"DistortionCorrection".to_string(),
ControlValueDescription::Boolean {
value: distortion_correction_current_value == YES,
default: false,
},
if distortion_correction_supported == YES {
vec![
KnownCameraControlFlag::ReadOnly,
KnownCameraControlFlag::Disabled,
]
} else {
vec![]
},
distortion_correction_supported == YES,
));
Ok(controls)
}
}
impl Drop for AVCaptureDevice {
-2
View File
@@ -835,8 +835,6 @@ pub mod wmf {
control,
control.to_string(),
ctrl_value_set,
vec![is_manual],
true,
))
}
+14 -2
View File
@@ -18,10 +18,12 @@ use crate::types::{
buf_mjpeg_to_rgb, buf_yuyv422_to_rgb, mjpeg_to_rgb, yuyv422_to_rgb, FrameFormat,
};
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 {
pub trait FormatDecoder: Copy + Clone + Debug + Default + Sized + Send + Sync + {
type Output: Pixel<Subpixel = u8>;
const FORMATS: &'static [FrameFormat];
/// Allocates and returns a `Vec`
/// # Errors
@@ -49,7 +51,8 @@ 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),
@@ -105,6 +108,8 @@ pub struct RgbAFormat;
impl FormatDecoder for RgbAFormat {
type Output = Rgba<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, true),
@@ -161,6 +166,10 @@ pub struct LumaFormat;
impl FormatDecoder for LumaFormat {
type Output = Luma<u8>;
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> {
match fcc {
@@ -227,6 +236,9 @@ pub struct LumaAFormat;
impl FormatDecoder for LumaAFormat {
type Output = LumaA<u8>;
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> {
match fcc {
+1
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
use crate::types::KnownCameraControlFlag;
use crate::{
buffer::Buffer,
error::NokhwaError,
+167 -18
View File
@@ -1,4 +1,5 @@
use crate::error::NokhwaError;
use crate::pixel_format::FormatDecoder;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::{
@@ -15,7 +16,7 @@ use std::{
/// - `None`: Pick a random [`CameraFormat`]
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub enum RequestedFormat {
pub enum RequestedFormatType {
HighestResolution,
HighestFrameRate,
Exact(CameraFormat),
@@ -23,37 +24,81 @@ pub enum RequestedFormat {
None,
}
impl RequestedFormat {
impl Default for RequestedFormatType {
fn default() -> Self {
RequestedFormatType::None
}
}
impl Display for RequestedFormatType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct RequestedFormat<F>
where
F: FormatDecoder,
{
requested_format: RequestedFormatType,
wanted_decoder: F,
}
impl<F> RequestedFormat<F>
where
F: FormatDecoder,
{
pub fn new<Decoder: FormatDecoder>(requested: RequestedFormatType) -> RequestedFormat<Decoder> {
RequestedFormat {
requested_format: requested,
wanted_decoder: Decoder::default(),
}
}
/// Fulfill the requested using a list of all available formats.
pub fn fulfill(&self, all_formats: &[CameraFormat]) -> Option<CameraFormat> {
match self {
RequestedFormat::HighestResolution => {
match self.requested_format {
RequestedFormatType::HighestResolution => {
let mut formats = all_formats.to_vec();
formats.sort_by_key(|a| a.resolution());
let resolution = *formats.iter().last()?;
let mut format_resolutions = formats
.into_iter()
.filter(|fmt| fmt.resolution() == resolution.resolution())
.filter(|fmt| {
fmt.resolution() == resolution.resolution()
&& F::FORMATS.contains(&fmt.format())
})
.collect::<Vec<CameraFormat>>();
format_resolutions.sort_by_key(|a| a.frame_rate());
format_resolutions.last().copied()
}
RequestedFormat::HighestFrameRate => {
RequestedFormatType::HighestFrameRate => {
let mut formats = all_formats.to_vec();
formats.sort_by_key(|a| a.frame_rate());
let frame_rate = *formats.iter().last()?;
let mut format_framerates = formats
.into_iter()
.filter(|fmt| fmt.frame_rate() == frame_rate.frame_rate())
.filter(|fmt| {
fmt.frame_rate() == frame_rate.frame_rate()
&& F::FORMATS.contains(&fmt.format())
})
.collect::<Vec<CameraFormat>>();
format_framerates.sort_by_key(|a| a.resolution());
format_framerates.last().copied()
}
RequestedFormat::Exact(fmt) => Some(*fmt),
RequestedFormat::Closest(c) => {
RequestedFormatType::Exact(fmt) => {
if F::FORMATS.contains(&fmt.format()) {
Some(fmt)
} else {
None
}
}
RequestedFormatType::Closest(c) => {
let same_fmt_formats = all_formats
.iter()
.filter(|x| x.format() == c.format())
.filter(|x| x.format() == c.format() && F::FORMATS.contains(&x.format()))
.copied()
.collect::<Vec<CameraFormat>>();
let mut resolution_map = same_fmt_formats
@@ -91,12 +136,19 @@ impl RequestedFormat {
let frame_rate = framerate_map.first()?.1;
Some(CameraFormat::new(resolution, c.format(), frame_rate))
}
RequestedFormat::None => all_formats.first().copied(),
RequestedFormatType::None => all_formats
.iter()
.filter(|fmt| F::FORMATS.contains(&fmt.format()))
.nth(0)
.copied(),
}
}
}
impl Display for RequestedFormat {
impl<F> Display for RequestedFormat<F>
where
F: FormatDecoder,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
@@ -594,11 +646,11 @@ impl Display for KnownCameraControl {
pub enum KnownCameraControlFlag {
Automatic,
Manual,
Continuous,
ReadOnly,
WriteOnly,
Volatile,
Disabled,
Inactive,
}
impl Display for KnownCameraControlFlag {
@@ -651,6 +703,25 @@ pub enum ControlValueDescription {
value: Vec<u8>,
default: Vec<u8>,
},
KeyValuePair {
key: i128,
value: i128,
default: (i128, i128),
},
Point {
value: (f64, f64),
default: (f64, f64),
},
Enum {
value: i64,
possible: Vec<i64>,
default: i64,
},
RGB {
value: (f64, f64, f64),
max: (f64, f64, f64),
default: (f64, f64, f64),
},
}
impl ControlValueDescription {
@@ -674,6 +745,16 @@ impl ControlValueDescription {
ControlValueDescription::Bytes { value, .. } => {
ControlValueSetter::Bytes(value.clone())
}
ControlValueDescription::KeyValuePair { key, value, .. } => {
ControlValueSetter::KeyValue(*key, *value)
}
ControlValueDescription::Point { value, .. } => {
ControlValueSetter::Point(value.0, value.1)
}
ControlValueDescription::Enum { value, .. } => ControlValueSetter::EnumValue(*value),
ControlValueDescription::RGB { value, .. } => {
ControlValueSetter::RGB(value.0, value.1, value.2)
}
}
}
@@ -737,6 +818,18 @@ impl ControlValueDescription {
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 { .. })
}
}
}
}
@@ -804,6 +897,46 @@ impl Display for ControlValueDescription {
ControlValueDescription::Bytes { value, default } => {
write!(f, "(Current: {:x?}, Default: {:x?})", value, default)
}
ControlValueDescription::KeyValuePair {
key,
value,
default,
} => {
write!(
f,
"Current: ({}, {}), Default: ({}, {})",
key, value, default.0, default.1
)
}
ControlValueDescription::Point { value, default } => {
write!(
f,
"Current: ({}, {}), Default: ({}, {})",
value.0, value.1, default.0, default.1
)
}
ControlValueDescription::Enum {
value,
possible,
default,
} => {
write!(
f,
"Current: {}, Possible Values: {:?}, Default: {}",
value, possible, default
)
}
ControlValueDescription::RGB {
value,
max,
default,
} => {
write!(
f,
"Current: ({}, {}, {}), Max: ({}, {}, {}), Default: ({}, {}, {})",
value.0, value.1, value.2, max.0, max.1, max.2, default.0, default.1, default.2
)
}
}
}
}
@@ -918,6 +1051,10 @@ pub enum ControlValueSetter {
Boolean(bool),
String(String),
Bytes(Vec<u8>),
KeyValue(i128, i128),
Point(f64, f64),
EnumValue(i64),
RGB(f64, f64, f64),
}
impl Display for ControlValueSetter {
@@ -927,19 +1064,31 @@ impl Display for ControlValueSetter {
write!(f, "Value: None")
}
ControlValueSetter::Integer(i) => {
write!(f, "Value: {}", i)
write!(f, "IntegerValue: {}", i)
}
ControlValueSetter::Float(d) => {
write!(f, "Value: {}", d)
write!(f, "FloatValue: {}", d)
}
ControlValueSetter::Boolean(b) => {
write!(f, "Value: {}", b)
write!(f, "BoolValue: {}", b)
}
ControlValueSetter::String(s) => {
write!(f, "Value: {}", s)
write!(f, "StrValue: {}", s)
}
ControlValueSetter::Bytes(b) => {
write!(f, "Value: {:x?}", b)
write!(f, "BytesValue: {:x?}", b)
}
ControlValueSetter::KeyValue(k, v) => {
write!(f, "KVValue: ({}, {})", k, v)
}
ControlValueSetter::Point(x, y) => {
write!(f, "PointValue: ({}, {})", x, y)
}
ControlValueSetter::EnumValue(v) => {
write!(f, "EnumValue: {}", v)
}
ControlValueSetter::RGB(r, g, b) => {
write!(f, "RGBValue: ({}, {}, {})", r, g, b)
}
}
}
+6 -12
View File
@@ -200,26 +200,20 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
self.set_camera_format(format)
}
fn camera_control(&self, _: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
Err(NokhwaError::NotImplementedError(
"Not Implemented".to_string(),
))
fn camera_control(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
todo!()
}
fn camera_controls(&self) -> Result<Vec<CameraControl>, NokhwaError> {
Err(NokhwaError::NotImplementedError(
"Not Implemented".to_string(),
))
todo!()
}
fn set_camera_control(
&mut self,
_: KnownCameraControl,
_: ControlValueSetter,
id: KnownCameraControl,
value: ControlValueSetter,
) -> Result<(), NokhwaError> {
Err(NokhwaError::NotImplementedError(
"Not Implemented".to_string(),
))
todo!()
}
fn open_stream(&mut self) -> Result<(), NokhwaError> {