Skip to content

Commit

Permalink
v0.2.0 core
Browse files Browse the repository at this point in the history
  • Loading branch information
l1npengtul committed Jan 6, 2025
1 parent 0e2d000 commit 021e4e1
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 181 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion nokhwa-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ test-fail-warnings = []
[dependencies]
thiserror = "2.0"
bytes = "1.3"
paste = "1.0"
flume = "0.11"
num-traits = "0.2"

Expand Down
3 changes: 3 additions & 0 deletions nokhwa-core/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub trait Setting {
}

#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncSetting {
async fn enumerate_formats_async(&self) -> Result<Vec<CameraFormat>, NokhwaError>;

Expand Down Expand Up @@ -53,6 +54,7 @@ pub trait Capture {
}

#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncStream {
async fn open_stream_async(&mut self) -> Result<Stream, NokhwaError>;

Expand All @@ -62,4 +64,5 @@ pub trait AsyncStream {
pub trait Camera: Setting + Capture {}

#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncCamera: Camera + AsyncSetting + AsyncStream {}
6 changes: 3 additions & 3 deletions nokhwa-core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::{frame_format::FrameFormat, types::ApiBackend};
use crate::{frame_format::FrameFormat};
use std::fmt::{Debug};
use thiserror::Error;
use crate::platform::Backends;
Expand All @@ -27,9 +27,9 @@ pub enum NokhwaError {
#[error("Unitialized Camera. Call `init()` first!")]
UnitializedError,
#[error("Could not initialize {backend}: {error}")]
InitializeError { backend: ApiBackend, error: String },
InitializeError { backend: Backends, error: String },
#[error("Could not shutdown {backend}: {error}")]
ShutdownError { backend: ApiBackend, error: String },
ShutdownError { backend: Backends, error: String },
#[error("Error: {0}")]
GeneralError(String),
#[error("Could not generate required structure {structure}: {error}")]
Expand Down
177 changes: 89 additions & 88 deletions nokhwa-core/src/format_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,139 +4,140 @@ use crate::{
ranges::Range,
types::{CameraFormat, FrameRate, Resolution},
};
use std::cmp::Ordering;
use crate::ranges::ValidatableRange;

#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
enum ClosestType {
Resolution,
FrameRate,
Both,
None,
}

#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum CustomFormatRequestType {
HighestFrameRate,
HighestResolution,
Closest,
Exact,
}

/// A helper for choosing a [`CameraFormat`].
/// The use of this is completely optional - for a simpler way try [`crate::camera::Camera::enumerate_formats`].
///
/// The `frame_format` field filters out the [`CameraFormat`]s by [`FrameFormat`].
pub enum FormatRequest {
#[derive(Clone, Debug, PartialEq)]
pub enum FormatRequestType {
/// Pick the closest [`CameraFormat`] to the one requested
Closest {
resolution: Option<Range<Resolution>>,
frame_rate: Option<Range<FrameRate>>,
frame_format: Vec<FrameFormat>,
},
HighestFrameRate {
frame_rate: Range<FrameRate>,
frame_format: Vec<FrameFormat>,
},
HighestResolution {
resolution: Range<Resolution>,
frame_format: Vec<FrameFormat>,
},
Exact {
resolution: Resolution,
frame_rate: FrameRate,
frame_format: Vec<FrameFormat>,
},
Any,
}

#[derive(Clone, Debug)]
pub struct FormatRequest {
request_type: FormatRequestType,
allowed_frame_formats: Vec<FrameFormat>,
}

impl FormatRequest {
pub fn sort_formats(&self, list_of_formats: &[CameraFormat]) -> Vec<CameraFormat> {
if list_of_formats.is_empty() {
return vec![];
pub fn new(format_request_type: FormatRequestType, allowed_frame_formats: Vec<FrameFormat>) -> Self {
Self {
request_type: format_request_type,
allowed_frame_formats,
}
}

match self {
FormatRequest::Closest {
pub fn best<'a>(&self, camera_formats: &'a Vec<CameraFormat>) -> Option<&'a CameraFormat> {
camera_formats.first()
}

pub fn sort_foramts(&self, mut camera_formats: Vec<CameraFormat>) -> Vec<CameraFormat> {
if camera_formats.is_empty() {
return camera_formats;
}

match self.request_type {
FormatRequestType::Closest {
resolution,
frame_rate,
frame_format,
..
} => {
let resolution_point = resolution.map(|x| x.preferred());
let frame_rate_point = frame_rate.map(|x| x.preferred());
// lets calcuate distance in 3 dimensions (add both resolution and frame_rate together)

let mut distances = list_of_formats
.iter()
.filter(|x| frame_format.contains(&x.format()))
.map(|fmt| {
let frame_rate_distance = match frame_rate_point {
Some(f_point) => (fmt.frame_rate() - f_point).approximate_float().unwrap_or(f32::INFINITY).abs(),
None => 0_f32,
};
let resolution_point_distance = match resolution_point {
Some(res_pt) => fmt.resolution().distance_from(&res_pt) as f32,
None => 0_f32,
};
(frame_rate_distance + resolution_point_distance, fmt)
})
.collect::<Vec<(f32, &CameraFormat)>>();
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
distances.into_iter().map(|x| x.1).copied().collect()
camera_formats.sort_by(|a, b| {
let a_distance = format_distance_to_point(&resolution_point, &frame_rate_point, a);
let b_distance = format_distance_to_point(&resolution_point, &frame_rate_point, b);

a_distance.total_cmp(&b_distance)
});

camera_formats.into_iter().filter(|fmt| {
self.allowed_frame_formats.contains(fmt.format())
}).filter(|cam_fmt| {
if let Some(res_range) = resolution {
return res_range.validate(cam_fmt.resolution())
}

if let Some(frame_rate_range) = frame_rate {
return frame_rate_range.validate(&cam_fmt.frame_rate())
}
true
}).collect()
}
FormatRequest::HighestFrameRate {
frame_rate,
frame_format,
FormatRequestType::HighestFrameRate {
frame_rate
} => {
let mut formats = list_of_formats
.iter()
.filter(|x| {
frame_format.contains(&x.format()) && frame_rate.validate(&x.frame_rate()).is_ok()
})
.collect::<Vec<_>>();
formats.sort();
formats.into_iter().copied().collect()
camera_formats.sort_by(|a, b| {
a.frame_rate().cmp(b.frame_rate())
});

camera_formats.into_iter().filter(|fmt| {
self.allowed_frame_formats.contains(fmt.format())
}).filter(|a| {
frame_rate.validate(a.frame_rate())
}).collect()
}
FormatRequest::HighestResolution {
resolution,
frame_format,
FormatRequestType::HighestResolution {
resolution
} => {
let mut formats = list_of_formats
.iter()
.filter(|x| {
frame_format.contains(&x.format()) && resolution.validate(&x.resolution()).is_ok()
})
.collect::<Vec<_>>();
formats.sort();
formats.into_iter().copied().collect()
camera_formats.sort_by(|a, b| {
a.resolution().cmp(b.resolution())
});

camera_formats.into_iter().filter(|fmt| {
self.allowed_frame_formats.contains(fmt.format())
}).filter(|a| {
resolution.validate(a.resolution())
}).collect()
}
FormatRequest::Exact {
FormatRequestType::Exact {
resolution,
frame_rate,
frame_format,
} => {
let mut formats = list_of_formats
.iter()
.filter(|x| {
frame_format.contains(&x.format())
&& resolution == &x.resolution()
&& frame_rate == &x.frame_rate()
})
.collect::<Vec<_>>();
formats.sort();
formats.into_iter().copied().collect()
camera_formats.into_iter().filter(|fmt| {
self.allowed_frame_formats.contains(fmt.format())
}).filter(|a| {
resolution.eq(a.resolution()) && frame_rate.eq(a.frame_rate())
}).collect()
}
FormatRequestType::Any => {
// return as-is
camera_formats
}
}
}
}

///
#[must_use]
pub fn resolve(&self, list_of_formats: &[CameraFormat]) -> Option<CameraFormat> {
if list_of_formats.is_empty() {
return None;
}
pub fn format_distance_to_point(resolution: &Option<Resolution>, frame_rate: &Option<FrameRate>, format: &CameraFormat) -> f32 {
let frame_rate_distance = match frame_rate {
Some(f_point) => (format.frame_rate() - f_point).approximate_float().unwrap_or(f32::INFINITY).abs(),
None => 0_f32,
};

Some(self.sort_formats(list_of_formats).remove(0))
}
let resolution_point_distance = match resolution {
Some(res_pt) => format.resolution().distance_from(&res_pt) as f32,
None => 0_f32,
};

frame_rate_distance + resolution_point_distance
}
5 changes: 2 additions & 3 deletions nokhwa-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cast_possible_truncation)]
#![cfg_attr(feature = "test-fail-warning", deny(warnings))]
#![cfg_attr(feature = "docs-features", feature(doc_cfg))]
// #![cfg_attr(feature = "docs-features", feature(doc_cfg))]
/*
* Copyright 2022 l1npengtul <[email protected]> / The Nokhwa Contributors
*
Expand All @@ -29,10 +29,9 @@ pub mod format_request;
pub mod frame_buffer;
pub mod frame_format;
pub mod properties;
pub mod query;
pub mod ranges;
pub mod traits;
pub mod types;
pub mod utils;
pub mod stream;
mod platform;
pub mod platform;
9 changes: 9 additions & 0 deletions nokhwa-core/src/platform.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fmt::{Display, Formatter};
use crate::camera::{AsyncCamera, Camera};
use crate::error::NokhwaResult;
use crate::types::{CameraIndex, CameraInformation};
Expand All @@ -8,9 +9,16 @@ pub enum Backends {
WebWASM,
AVFoundation,
MicrosoftMediaFoundation,
OpenCV,
Custom(&'static str)
}

impl Display for Backends {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

pub trait PlatformTrait {
const PLATFORM: Backends;
type Camera: Camera;
Expand All @@ -26,6 +34,7 @@ pub trait PlatformTrait {
}

#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncPlatformTrait {
const PLATFORM: Backends;
type AsyncCamera: AsyncCamera;
Expand Down
Loading

0 comments on commit 021e4e1

Please sign in to comment.