new format request type, quartar way wasm cam impl

This commit is contained in:
l1npengtul
2023-08-31 15:23:19 +09:00
parent 074765f012
commit 67139b84cc
9 changed files with 703 additions and 531 deletions
-230
View File
@@ -1,230 +0,0 @@
use crate::frame_format::SourceFrameFormat;
use crate::{
frame_format::FrameFormat,
types::{ApiBackend, CameraFormat, Resolution},
};
use std::collections::{BTreeMap, BTreeSet};
/// Tells the init function what camera format to pick.
/// - `AbsoluteHighestResolution`: Pick the highest [`Resolution`], then pick the highest frame rate of those provided.
/// - `AbsoluteHighestFrameRate`: Pick the highest frame rate, then the highest [`Resolution`].
/// - `HighestResolution(Resolution)`: Pick the highest [`Resolution`] for the given framerate.
/// - `HighestFrameRate(u32)`: Pick the highest frame rate for the given [`Resolution`].
/// - `Exact`: Pick the exact [`CameraFormat`] provided.
/// - `Closest`: Pick the closest [`CameraFormat`] provided in order of [`Resolution`], and FPS.
/// - `ClosestGreater`: Pick the closest [`CameraFormat`] provided in order of [`Resolution`], and FPS. The returned format's [`Resolution`] **and** FPS will be **greater than or equal to** the provided [`CameraFormat`]
/// - `ClosestLess`: Pick the closest [`CameraFormat`] provided in order of [`Resolution`], and FPS.The returned format's [`Resolution`] **and** FPS will be **less than or equal to** the provided [`CameraFormat`]
/// - `None`: Pick a random [`CameraFormat`]
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum RequestedFormatType {
AbsoluteHighestResolution,
AbsoluteHighestFrameRate,
HighestResolution(u32),
HighestFrameRate(Resolution),
Exact(CameraFormat),
ClosestGreater(CameraFormat),
ClosestLess(CameraFormat),
Closest(CameraFormat),
None,
}
// TODO: Format Filter Builder to provide more interactive API for fulfillment of formats.
/// How you get your [`FrameFormat`] from the
#[derive(Clone, Debug)]
pub struct FormatFilter {
filter_pref: RequestedFormatType,
fcc_primary: BTreeSet<FrameFormat>,
fcc_platform: BTreeMap<ApiBackend, BTreeSet<u128>>,
}
impl FormatFilter {
pub fn new(fmt_type: RequestedFormatType) -> Self {
Self {
filter_pref: fmt_type,
fcc_primary: Default::default(),
fcc_platform: Default::default(),
}
}
pub fn add_allowed_frame_format(&mut self, frame_format: FrameFormat) {
self.fcc_primary.insert(frame_format);
}
pub fn add_allowed_frame_format_many(&mut self, frame_formats: impl AsRef<[FrameFormat]>) {
self.fcc_primary.extend(frame_formats.as_ref().iter());
}
pub fn add_allowed_platform_specific(&mut self, platform: ApiBackend, frame_format: u128) {
match self.fcc_platform.get_mut(&platform) {
Some(fccs) => {
fccs.insert(frame_format);
}
None => {
self.fcc_platform
.insert(platform, BTreeSet::from([frame_format]));
}
};
}
pub fn add_allowed_platform_specific_many(
&mut self,
platform_specifics: impl AsRef<[(ApiBackend, u128)]>,
) {
for (platform, frame_format) in platform_specifics.as_ref().into_iter() {
match self.fcc_platform.get_mut(&platform) {
Some(fccs) => {
fccs.insert(*frame_format);
}
None => {
self.fcc_platform
.insert(*platform, BTreeSet::from([*frame_format]));
}
};
}
}
pub fn with_allowed_frame_format(mut self, frame_format: FrameFormat) -> Self {
self.fcc_primary.insert(frame_format);
self
}
pub fn with_allowed_frame_format_many(
mut self,
frame_formats: impl AsRef<[FrameFormat]>,
) -> Self {
self.fcc_primary.extend(frame_formats.as_ref().iter());
self
}
pub fn with_allowed_platform_specific(
mut self,
platform: ApiBackend,
frame_format: u128,
) -> Self {
self.add_allowed_platform_specific(platform, frame_format);
self
}
pub fn with_allowed_platform_specific_many(
mut self,
platform_specifics: impl AsRef<[(ApiBackend, u128)]>,
) -> Self {
self.add_allowed_platform_specific_many(platform_specifics);
self
}
}
impl Default for FormatFilter {
fn default() -> Self {
Self {
filter_pref: RequestedFormatType::Closest(CameraFormat::new(
Resolution::new(640, 480),
FrameFormat::Yuv422.into(),
30,
)),
fcc_primary: BTreeSet::from([FrameFormat::Yuv422]),
fcc_platform: Default::default(),
}
}
}
pub fn format_fulfill(
sources: impl AsRef<[CameraFormat]>,
filter: FormatFilter,
) -> Option<CameraFormat> {
let mut sources = sources
.as_ref()
.into_iter()
.filter(|cam_filter| match cam_filter.format() {
SourceFrameFormat::FrameFormat(fmt) => filter.fcc_primary.contains(&fmt),
SourceFrameFormat::PlatformSpecific(plat) => filter
.fcc_platform
.get(&plat.backend())
.map(|x| x.contains(&plat.format()))
.unwrap_or(false),
});
match filter.filter_pref {
RequestedFormatType::AbsoluteHighestResolution => {
let mut sources = sources.collect::<Vec<&CameraFormat>>();
sources.sort_by(|a, b| a.resolution().cmp(&b.resolution()));
sources.last().copied().copied()
}
RequestedFormatType::AbsoluteHighestFrameRate => {
let mut sources = sources.collect::<Vec<&CameraFormat>>();
sources.sort_by(|a, b| a.frame_rate().cmp(&b.frame_rate()));
sources.last().copied().copied()
}
RequestedFormatType::HighestResolution(filter_fps) => {
let mut sources = sources
.filter(|format| format.frame_rate() == filter_fps)
.collect::<Vec<&CameraFormat>>();
sources.sort();
sources.last().copied().copied()
}
RequestedFormatType::HighestFrameRate(filter_res) => {
let mut sources = sources
.filter(|format| format.resolution() == filter_res)
.collect::<Vec<&CameraFormat>>();
sources.sort();
sources.last().copied().copied()
}
RequestedFormatType::Exact(exact) => {
sources.filter(|format| format == &&exact).last().copied()
}
RequestedFormatType::Closest(closest) => {
let mut sources = sources
.map(|format| {
let dist = distance_3d_camerafmt_relative(closest, *format);
(dist, *format)
})
.collect::<Vec<(f64, CameraFormat)>>();
sources.sort_by(|a, b| a.0.total_cmp(&b.0));
sources.first().copied().map(|(_, cf)| cf)
}
RequestedFormatType::ClosestGreater(closest) => {
let mut sources = sources
.filter(|format| {
format.resolution() >= closest.resolution()
&& format.frame_rate() >= closest.frame_rate()
})
.map(|format| {
let dist = distance_3d_camerafmt_relative(closest, *format);
(dist, *format)
})
.collect::<Vec<(f64, CameraFormat)>>();
sources.sort_by(|a, b| a.0.total_cmp(&b.0));
sources.first().copied().map(|(_, cf)| cf)
}
RequestedFormatType::ClosestLess(closest) => {
let mut sources = sources
.filter(|format| {
format.resolution() <= closest.resolution()
&& format.frame_rate() <= closest.frame_rate()
})
.map(|format| {
let dist = distance_3d_camerafmt_relative(closest, *format);
(dist, *format)
})
.collect::<Vec<(f64, CameraFormat)>>();
sources.sort_by(|a, b| a.0.total_cmp(&b.0));
sources.first().copied().map(|(_, cf)| cf)
}
RequestedFormatType::None => sources.nth(0).map(|x| *x),
}
}
fn distance_3d_camerafmt_relative(a: CameraFormat, b: CameraFormat) -> f64 {
let res_x_diff = b.resolution().x() - a.resolution().x();
let res_y_diff = b.resolution().y() - a.resolution().y();
let fps_diff = b.frame_rate() - a.frame_rate();
let x = res_x_diff.pow(2) as f64;
let y = res_y_diff.pow(2) as f64;
let z = fps_diff.pow(2) as f64;
x + y + z
}
+116
View File
@@ -0,0 +1,116 @@
use crate::frame_format::SourceFrameFormat;
use crate::types::Range;
use crate::{
frame_format::FrameFormat,
types::{ApiBackend, CameraFormat, Resolution},
};
use std::collections::{BTreeMap, BTreeSet};
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum CustomFormatRequestType {
HighestFPS,
HighestResolution,
Closest,
}
#[derive(Clone, Debug, Default, PartialOrd, PartialEq)]
pub struct FormatRequest {
resolution: Option<Range<Resolution>>,
frame_rate: Option<Range<u32>>,
frame_format: Option<Vec<FrameFormat>>,
req_type: Option<CustomFormatRequestType>,
}
impl FormatRequest {
pub fn new() -> Self {
Self::default()
}
pub fn with_resolution(mut self, resolution: Resolution, exact: bool) -> Self {
self.resolution = Some(resolution);
self.resolution_exact = exact;
self
}
pub fn reset_resolution(mut self) -> Self {
self.resolution = None;
self.resolution_exact = false;
self
}
pub fn with_frame_rate(mut self, frame_rate: u32, exact: bool) -> Self {
self.frame_rate = Some(frame_rate);
self.frame_rate_exact = exact;
self
}
pub fn with_standard_frame_rate() {}
pub fn reset_frame_rate(mut self) -> Self {
self.frame_rate = None;
self.frame_rate_exact = false;
self
}
pub fn with_frame_formats(mut self, frame_formats: Vec<FrameFormat>) -> Self {
self.frame_format = Some(frame_formats);
self
}
pub fn with_standard_frame_formats(mut self) -> Self {
self.append_frame_formats(&mut vec![
FrameFormat::MJpeg,
FrameFormat::Rgb8,
FrameFormat::Yuv422,
FrameFormat::Nv12,
])
}
pub fn push_frame_format(mut self, frame_format: FrameFormat) -> Self {
match &mut self.frame_format {
Some(ffs) => ffs.push(frame_format),
None => self.frame_format = Some(vec![frame_format]),
}
self
}
pub fn remove_frame_format(mut self, frame_format: FrameFormat) -> Self {
if let Some(ffs) = &mut self.frame_format {
if let Some(idx) = ffs.iter().position(frame_format) {
ffs.remove(idx)
}
}
self
}
pub fn append_frame_formats(mut self, frame_formats: &mut Vec<FrameFormat>) -> Self {
match &mut self.frame_format {
Some(ffs) => ffs.append(frame_formats),
None => self.frame_format = Some(frame_formats.clone()),
}
self
}
pub fn reset_frame_formats(mut self) -> Self {
self.frame_format = None;
self
}
pub fn with_request_type(mut self, request_type: CustomFormatRequestType) -> Self {
self.req_type = Some(request_type);
self
}
pub fn reset_request_type(mut self) -> Self {
self.req_type = None;
self
}
}
pub fn resolve_format_request(
request: FormatRequest,
availible_formats: Vec<CameraFormat>,
) -> CameraFormat {
// filter out by
}
+2 -1
View File
@@ -21,8 +21,9 @@
//! Core type definitions for `nokhwa`
pub mod buffer;
pub mod error;
pub mod format_filter;
pub mod format_request;
pub mod frame_format;
pub mod traits;
pub mod types;
pub mod decoder;
pub mod utils;
+1 -12
View File
@@ -17,7 +17,7 @@
use crate::{
buffer::Buffer,
error::NokhwaError,
format_filter::FormatFilter,
format_request::FormatFilter,
frame_format::SourceFrameFormat,
types::{
ApiBackend, CameraControl, CameraFormat, CameraInfo, ControlValueSetter,
@@ -315,17 +315,6 @@ pub trait AsyncCaptureTrait: CaptureTrait {
fourcc: SourceFrameFormat,
) -> Result<(), NokhwaError>;
/// Gets the value of [`KnownCameraControl`].
/// # Errors
/// If the `control` is not supported or there is an error while getting the camera control values (e.g. unexpected value, too high, etc)
/// this will error.
async fn camera_control_async(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError>;
/// Gets the current supported list of [`KnownCameraControl`]
/// # Errors
/// If the list cannot be collected, this will error. This can be treated as a "nothing supported".
async fn camera_controls_async(&self) -> Result<Vec<CameraControl>, NokhwaError>;
/// Sets the control to `control` in the camera.
/// Usually, the pipeline is calling [`camera_control()`](CaptureTrait::camera_control), getting a camera control that way
/// then calling [`value()`](CameraControl::value()) to get a [`ControlValueSetter`] and setting the value that way.
+93 -16
View File
@@ -1,25 +1,101 @@
use crate::{
error::NokhwaError,
format_filter::RequestedFormatType,
frame_format::{FrameFormat, SourceFrameFormat},
};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::{
borrow::Borrow,
cmp::Ordering,
fmt::{Display, Formatter},
};
impl Default for RequestedFormatType {
fn default() -> Self {
RequestedFormatType::None
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
minimum: Option<T>,
lower_inclusive: bool,
maximum: Option<T>,
upper_inclusive: bool,
preferred: T,
}
impl<T> Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
pub fn new(preferred: T, min: Option<T>, max: Option<T>) -> Self {
Self {
minimum: min,
lower_inclusive: true,
maximum: max,
upper_inclusive: false,
preferred,
}
}
pub fn with_inclusive(
preferred: T,
min: Option<T>,
lower_inclusive: bool,
max: Option<T>,
upper_inclusive: bool,
) -> Self {
Self {
minimum: min,
lower_inclusive,
maximum: max,
upper_inclusive,
preferred,
}
}
pub fn does_fit(&self, item: T) -> bool {
if item == self.preferred {
true
}
if let Some(min) = self.minimum {
let test = if self.lower_inclusive {
min >= item
} else {
min > item
};
if test {
return false;
}
}
if let Some(max) = self.maximum {
let test = if self.lower_inclusive {
max <= item
} else {
max < item
};
if test {
return false;
}
}
true
}
}
impl Display for RequestedFormatType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
impl<T> Default for Range<T>
where
T: Default,
{
fn default() -> Self {
Range {
minimum: None,
lower_inclusive: true,
maximum: None,
upper_inclusive: false,
preferred: T::default(),
}
}
}
@@ -308,7 +384,7 @@ impl CameraInfo {
// OK, i just checkeed back on this code. WTF was I on when I wrote `&(impl AsRef<str> + ?Sized)` ????
// I need to get on the same shit that my previous self was on, because holy shit that stuff is strong as FUCK!
// Finally fixed this insanity. Hopefully I didnt torment anyone by actually putting this in a stable release.
pub fn new(human_name: &str, description: &str, misc: &str, index: CameraIndex) -> Self {
pub fn new(human_name: &str, description: &str, misc: &str, index: &CameraIndex) -> Self {
CameraInfo {
human_name: human_name.to_string(),
description: description.to_string(),
@@ -563,8 +639,8 @@ pub enum ControlValueDescription {
},
StringList {
value: String,
availible: Vec<String>
}
availible: Vec<String>,
},
}
impl ControlValueDescription {
@@ -598,7 +674,9 @@ impl ControlValueDescription {
ControlValueDescription::RGB { value, .. } => {
ControlValueSetter::RGB(value.0, value.1, value.2)
}
ControlValueDescription::StringList { value, .. } => ControlValueSetter::StringList(value.clone()),
ControlValueDescription::StringList { value, .. } => {
ControlValueSetter::StringList(value.clone())
}
}
}
@@ -696,7 +774,7 @@ impl ControlValueDescription {
},
ControlValueDescription::StringList { value, availible } => {
availible.contains(setter.as_str())
},
}
}
// match setter {
@@ -864,7 +942,7 @@ impl Display for ControlValueDescription {
}
ControlValueDescription::StringList { value, availible } => {
write!(f, "Current: {value}, Availible: {availible:?}")
},
}
}
}
}
@@ -1113,7 +1191,7 @@ impl Display for ControlValueSetter {
}
ControlValueSetter::StringList(s) => {
write!(f, "StringListValue: {s}")
},
}
}
}
}
@@ -1346,7 +1424,7 @@ pub fn yuyv422_to_rgb(data: &[u8], rgba: bool) -> Result<Vec<u8>, NokhwaError> {
/// If the stream is invalid Yuv422, or the destination buffer is not large enough, this will error.
#[inline]
pub fn buf_yuyv422_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<(), NokhwaError> {
let mut buf:Vec<u8> = Vec::new();
let mut buf: Vec<u8> = Vec::new();
if data.len() % 4 != 0 {
return Err(NokhwaError::ProcessFrameError {
src: FrameFormat::Yuv422.into(),
@@ -1381,7 +1459,6 @@ pub fn buf_yuyv422_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<()
Ok(())
}
// equation from https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
/// Convert `YCbCr` 4:4:4 to a RGB888. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB)
#[allow(clippy::many_single_char_names)]