finish decoder and frame format searcher implementation

This commit is contained in:
l1npengtul
2024-04-16 12:56:44 +09:00
parent 32c8a9eff4
commit fd5559a710
9 changed files with 978 additions and 1277 deletions
Generated
+741 -1004
View File
File diff suppressed because it is too large Load Diff
+10 -9
View File
@@ -30,8 +30,7 @@ input-native = ["input-avfoundation", "input-v4l", "input-msmf"]
# Re-enable it once soundness has been proven + mozjpeg is updated to 0.9.x
# input-uvc = ["uvc", "uvc/vendor", "usb_enumeration", "lazy_static"]
input-opencv = ["opencv", "opencv/rgb", "rgb", "nokhwa-core/opencv-mat"]
# FIXME: Change me back to web-sys being optional! People will be mad otherwise peg!
input-jscam = [ "wasm-bindgen-futures", "wasm-rs-async-executor", "output-async"]
input-jscam = [ "wasm-bindgen-futures", "wasm-rs-async-executor", "output-async", "js-sys", "web-sys"]
output-wgpu = ["wgpu", "nokhwa-core/wgpu-types"]
#output-wasm = ["input-jscam"]
output-threaded = []
@@ -46,11 +45,11 @@ thiserror = "1.0"
paste = "1.0"
[dependencies.mozjpeg]
version = "0.9"
version = "0.10"
optional = true
[dependencies.dcv-color-primitives]
version = "0.5"
version = "0.6"
optional = true
[dependencies.nokhwa-core]
@@ -62,11 +61,11 @@ version = "1.0"
optional = true
[dependencies.flume]
version = "0.10"
version = "0.11"
optional = true
[dependencies.image]
version = "0.24"
version = "0.25"
default-features = false
[dependencies.usb_enumeration]
@@ -74,11 +73,11 @@ version = "0.2"
optional = true
[dependencies.wgpu]
version = "0.17"
version = "0.19"
optional = true
[dependencies.opencv]
version = "0.84"
version = "0.89"
default-features = false
features = ["videoio"]
optional = true
@@ -106,7 +105,6 @@ optional = true
version = "1.7"
optional = true
# TODO: Change me back!
[dependencies.web-sys]
version = "0.3"
features = [
@@ -126,13 +124,16 @@ features = [
"Plugin", "PluginArray",
"Window"
]
optional = true
# FIXME: Change me back! Pls! REMEMBER PEG!
[dependencies.js-sys]
version = "0.3"
optional = true
[dependencies.wasm-bindgen]
version = "0.2"
optional = true
[dependencies.wasm-bindgen-futures]
version = "0.4"
+2 -2
View File
@@ -15,5 +15,5 @@ version = "0.2"
path = "../nokhwa-core"
[target.'cfg(target_os="linux")'.dependencies]
v4l = "0.13"
v4l2-sys-mit = "0.2"
v4l = "0.14"
v4l2-sys-mit = "0.3"
+10 -6
View File
@@ -14,10 +14,8 @@
* limitations under the License.
*/
use crate::{frame_format::SourceFrameFormat, types::Resolution};
use crate::{ types::Resolution};
use bytes::Bytes;
use image::ImageBuffer;
use crate::error::NokhwaError;
/// A buffer returned by a camera to accommodate custom decoding.
/// Contains information of Resolution, the buffer's [`FrameFormat`], and the buffer.
@@ -27,14 +25,14 @@ use crate::error::NokhwaError;
pub struct Buffer {
resolution: Resolution,
buffer: Bytes,
source_frame_format: SourceFrameFormat,
source_frame_format: FrameFormat,
}
impl Buffer {
/// Creates a new buffer with a [`&[u8]`].
#[must_use]
#[inline]
pub fn new(res: Resolution, buf: &[u8], source_frame_format: SourceFrameFormat) -> Self {
pub fn new(res: Resolution, buf: &[u8], source_frame_format: FrameFormat) -> Self {
Self {
resolution: res,
buffer: Bytes::copy_from_slice(buf),
@@ -62,13 +60,19 @@ impl Buffer {
/// Get the [`SourceFrameFormat`] of this buffer.
#[must_use]
pub fn source_frame_format(&self) -> SourceFrameFormat {
pub fn source_frame_format(&self) -> FrameFormat {
self.source_frame_format
}
}
#[cfg(feature = "opencv-mat")]
use crate::error::NokhwaError;
#[cfg(feature = "opencv-mat")]
use image::ImageBuffer;
#[cfg(feature = "opencv-mat")]
impl Buffer {
/// Decodes a image with allocation using the provided [`FormatDecoder`].
/// # Errors
/// Will error when the decoding fails.
+16 -18
View File
@@ -1,6 +1,4 @@
use std::ops::Deref;
use image::{ImageBuffer, Pixel};
use serde::de::Error;
use crate::buffer::Buffer;
use crate::frame_format::FrameFormat;
@@ -9,19 +7,19 @@ pub trait Decoder {
/// Formats that the decoder can decode.
const ALLOWED_FORMATS: &'static FrameFormat;
/// Output pixel type (e.g. [`Rgb<u8>`](image::Rgb))
type Pixel: Pixel;
/// Container for [`Self::Pixel`] - must have the same [`Pixel::Subpixel`]
type Container: Deref<Target = [Pixel::Subpixel]>;
type OutputPixels: Pixel;
type PixelContainer;
/// Error that the decoder will output (use [`NokhwaError`] if you're not sure)
type Error: Error;
type Error;
/// Decode function.
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
/// Decode to user-provided Buffer
///
/// Incase that the buffer is not large enough this should error.
fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
fn decode_buffer(&mut self, buffer: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
/// Decoder Predicted Size
fn predicted_size_of_frame(&mut self, ) -> Option<usize>;
@@ -31,46 +29,46 @@ pub trait Decoder {
///
/// This is useful for times that a simple function is all that is required.
pub trait StaticDecoder: Decoder {
fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
fn decode_static_to_buffer(buffer: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
}
/// Decoder that does not change its internal state.
pub trait IdemptDecoder: Decoder {
/// Decoder that does not change its internal state.
fn decode_nm(&self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
fn decode_nm(&self, buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
/// Decoder that does not change its internal state, decoding to a user provided buffer.
fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
fn decode_nm_to_buffer(&self, buffer: &mut [<<Self as Decoder>::OutputPixels as Pixel>::Subpixel]) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncDecoder: Decoder {
/// Asynchronous decoder
async fn decode_async(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
async fn decode_async(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
/// Asynchronous decoder to user buffer.
async fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
async fn decode_buffer(&mut self, buffer: &mut [Self::OutputPixels::Subpixel]) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncStaticDecoder: Decoder {
/// Asynchronous decoder
async fn decode_static_async(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
async fn decode_static_async(buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
/// Asynchronous decoder to user buffer.
async fn decode_static_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
async fn decode_static_buffer(buffer: &mut [Self::OutputPixels::Subpixel]) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncIdemptDecoder: Decoder {
/// Asynchronous decoder
async fn decode_nm_async(&self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
async fn decode_nm_async(&self, buffer: Buffer) -> Result<ImageBuffer<Self::OutputPixels, Self::PixelContainer>, Self::Error>;
/// Asynchronous decoder to user buffer.
async fn decode_nm_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
async fn decode_nm_buffer(&self, buffer: &mut [Self::OutputPixels::Subpixel]) -> Result<(), Self::Error>;
}
+86 -167
View File
@@ -1,136 +1,19 @@
use std::collections::{BTreeMap, BTreeSet};
use crate::types::{FrameRate, Range};
use std::{
cmp::Ordering,
collections::VecDeque
};
use crate::{
frame_format::FrameFormat,
types::{ CameraFormat, Resolution},
types::{CameraFormat, Resolution, FrameRate, Range},
traits::Distance
};
use paste::paste;
macro_rules! range_set_fields {
($(($range_type:ty, $name:ident),)*) => {
$(
paste! {
pub fn [< with_maximum_ $name >](mut self, $name: $range_type) -> Self {
match &mut self.$name {
Some(r) => {
r.set_maximum(Some($name))
}
None => {
self.$name: Option<Range<$range_type>> = Some(Range {
maximum: Some($name),
minimum: None,
preferred: $range_type::default()
});
}
}
self
}
pub fn [< reset_maximum_ $name >](mut self) -> Self {
if let Some(r) = self.$name {
self.$name.set_maximum(None)
}
self
}
pub fn [< set_maximum_ $name >](&mut self, $name: Option<$range_type>) {
match &mut self.$name {
Some(r) => {
r.set_maximum($name)
}
None => {
self.$name: Option<Range<$range_type>> = Some(Range {
maximum: $name,
minimum: None,
preferred: $range_type::default()
});
}
}
}
pub fn [< with_preferred_ $name >](mut self, $name: $range_type) -> Self {
match self.$name {
Some(r) => {
r.set_preferred(Some($name))
}
None => {
self.$name: Option<Range<$range_type>> = Some(Range {
maximum: None,
minimum: None,
preferred: $range_type::default()
});
}
}
self
}
pub fn [< set_preferred_ $name >](&mut self, $name: $range_type) {
match &mut self.$name {
Some(r) => {
r.set_preferred($name)
}
None => {
self.$name: Option<Range<$range_type>> = Some(Range {
maximum: None,
minimum: None,
preferred: $range_type
});
}
}
}
pub fn [< with_minimum_ $name >](mut self, $name: $range_type) -> Self {
match self.$name {
Some(r) => {
r.set_minimum(Some($name))
}
None => {
self.$name: Option<Range<$range_type>> = Some(Range {
maximum: None,
minimum: Some($name),
preferred: $range_type::default()
});
}
}
self
}
pub fn [< reset_minimum_ $name >](mut self) -> Self {
if let Some(r) = self.$name {
self.$name.set_minimum(None)
}
self
}
pub fn [< set_minimum_ $name >](&mut self, $name: Option<$range_type>) {
match &mut self.$name {
Some(r) => {
r.set_minimum($name)
}
None => {
self.$name: Option<Range<$range_type>> = Some(Range {
maximum: None,
minimum: $name,
preferred: $range_type::default()
});
}
}
}
pub fn [< with_ $name _range >](mut self, $name: Option<Range<$range_type>>) -> Self {
self.$name = $name
Self
}
pub fn [< set_ $name _range >](&mut self, $name: Option<Range<$range_type>>) {
self.$name = $name
}
}
)*
};
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
enum ClosestType {
Resolution,
FrameRate,
Both,
None,
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
@@ -173,8 +56,8 @@ impl FormatRequest {
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)
if let Some(idx) = ffs.iter().position(|ff| ff == &frame_format) {
ffs.remove(idx);
}
}
@@ -205,6 +88,26 @@ impl FormatRequest {
self
}
pub fn set_resolution_range(mut self, resolution_range: Range<Resolution>) -> Self {
self.resolution = Some(resolution_range);
self
}
pub fn reset_resolution_range(mut self) -> Self {
self.resolution = None;
self
}
pub fn set_frame_rate_range(mut self, frame_rate_range: Range<FrameRate>) -> Self {
self.frame_rate = Some(frame_rate_range);
self
}
pub fn reset_frame_rate_range(mut self) -> Self {
self.frame_rate = None;
self
}
pub fn satisfied_by_format(&self, format: &CameraFormat) -> bool {
// check resolution
let resolution_satisfied = match self.resolution {
@@ -227,72 +130,88 @@ impl FormatRequest {
resolution_satisfied && frame_rate_satisfied && frame_format_satisfied
}
pub fn resolve(&self, list_of_formats: &[CameraFormat]) -> CameraFormat {
let mut remaining_formats = list_of_formats.iter().filter(|x| self.satisfied_by_format(*x)).collect::<Vec<CameraFormat>>();
pub fn resolve(&self, list_of_formats: &[CameraFormat]) -> Option<CameraFormat> {
// filter out bad results
let mut remaining_formats = list_of_formats.iter().filter(|x| self.satisfied_by_format(*x)).copied().collect::<Vec<CameraFormat>>();
match self.req_type {
Some(request) => {
match request {
CustomFormatRequestType::HighestFrameRate => {
remaining_formats.sort_by(|a, b| {
a.frame_rate().cmp(&b.frame_rate())
a.frame_rate().partial_cmp(&b.frame_rate()).unwrap_or(Ordering::Equal)
});
remaining_formats[0]
Some(remaining_formats[0])
}
CustomFormatRequestType::HighestResolution => {
remaining_formats.sort_by(|a, b| {
a.resolution().cmp(&b.resolution())
a.frame_rate().partial_cmp(&b.frame_rate()).unwrap_or(Ordering::Equal)
});
remaining_formats[0]
Some(remaining_formats[0])
}
CustomFormatRequestType::Closest => {
enum ClosestType {
Resolution,
FrameRate,
Both,
None,
}
let mut closest_type = ClosestType::Resolution;
if let None = self.resolution {
closest_type = ClosestType::FrameRate
}
if let None = self.frame_rate {
if closest_type == ClosestType::FrameRate {
closest_type = ClosestType::None;
}
closest_type = ClosestType::Resolution
} else {
if ClosestType::Resolution {
closest_type = ClosestType::Both
}
}
let mut closest_type = match (&self.frame_rate, &self.resolution) {
(Some(_), Some(_)) => ClosestType::Both,
(Some(_), None) => ClosestType::FrameRate,
(None, Some(_)) => ClosestType::Resolution,
(None, None) => ClosestType::None,
};
match closest_type {
ClosestType::Resolution => {
let resolution_point = self.resolution.unwrap().preferred();
let resolution_point = match self.resolution.map(|x| x.preferred()).flatten() {
Some(r) => r,
None => return None,
};
let mut distances = remaining_formats.into_iter().map(|fmt| (fmt.resolution().distance_from(&resolution_point), fmt)).collect::<Vec<_>>();
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| Ordering::Equal));
VecDeque::from(distances).pop_front().map(|x| x.1)
}
ClosestType::FrameRate => {
let frame_rate_point = self.frame_rate.unwrap().preferred();
let frame_rate_point = match self.frame_rate.map(|x| x.preferred()).flatten() {
Some(f) => f,
None => return None,
};
let mut distances = remaining_formats.into_iter().map(|fmt| (fmt.frame_rate().distance_from(&frame_rate_point), fmt)).collect::<Vec<_>>();
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| Ordering::Equal));
VecDeque::from(distances).pop_front().map(|x| x.1)
}
ClosestType::Both => {
let resolution_point = self.resolution.unwrap().preferred();
let frame_rate_point = self.frame_rate.unwrap().preferred();
let resolution_point = match self.resolution.map(|x| x.preferred()).flatten() {
Some(r) => r,
None => return None,
};
let frame_rate_point = match self.frame_rate.map(|x| x.preferred()).flatten() {
Some(f) => f,
None => return None,
};
// lets calcuate distance in 3 dimensions (add both resolution and frame_rate together)
let mut distances = remaining_formats.into_iter()
.map(|fmt| {
(fmt.frame_rate().distance_from(&frame_rate_point) + fmt.resolution().distance_from(&resolution_point) as f32, fmt)
})
.collect::<Vec<_>>();
distances.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or_else(|| Ordering::Equal));
VecDeque::from(distances).pop_front().map(|x| x.1)
}
ClosestType::None => {
remaining_formats[0]
Some(remaining_formats[0])
}
}
}
}
}
None => {
remaining_formats[0]
Some(remaining_formats[0])
}
}
}
}
range_set_fields!((Resolution, resolution), (FrameRate, frame_rate),);
+13 -19
View File
@@ -14,13 +14,9 @@
* limitations under the License.
*/
use crate::{buffer::Buffer, types::ApiBackend};
use image::{ImageBuffer, Pixel};
use std::{
error::Error,
fmt::{Display, Formatter},
ops::Deref,
};
use std::fmt::{Display, Formatter};
use crate::types::ApiBackend;
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC`.
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
@@ -60,7 +56,7 @@ pub enum FrameFormat {
// Custom
Custom(u128),
PlatformSpecificCustomFormat(PlatformFrameFormat),
PlatformSpecificCustomFormat(PlatformSpecific),
}
impl FrameFormat {
@@ -134,9 +130,7 @@ impl FrameFormat {
FrameFormat::RgbA8,
];
pub const GRAYSCALE: &'static [FrameFormat] = {
FrameFormat::Luma8
}
pub const GRAYSCALE: &'static [FrameFormat] = &[FrameFormat::Luma8, FrameFormat::Luma16];
}
impl Display for FrameFormat {
@@ -147,12 +141,12 @@ impl Display for FrameFormat {
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct PlatformFrameFormat {
pub struct PlatformSpecific {
backend: ApiBackend,
format: u128,
}
impl PlatformFrameFormat {
impl PlatformSpecific {
pub fn new(backend: ApiBackend, format: u128) -> Self {
Self { backend, format }
}
@@ -170,25 +164,25 @@ impl PlatformFrameFormat {
}
}
impl From<(ApiBackend, u128)> for PlatformFrameFormat {
impl From<(ApiBackend, u128)> for PlatformSpecific {
fn from(value: (ApiBackend, u128)) -> Self {
PlatformFrameFormat::new(value.0, value.1)
PlatformSpecific::new(value.0, value.1)
}
}
impl From<PlatformFrameFormat> for (ApiBackend, u128) {
fn from(value: PlatformFrameFormat) -> Self {
impl From<PlatformSpecific> for (ApiBackend, u128) {
fn from(value: PlatformSpecific) -> Self {
value.as_tuple()
}
}
impl PartialEq<(ApiBackend, u128)> for PlatformFrameFormat {
impl PartialEq<(ApiBackend, u128)> for PlatformSpecific {
fn eq(&self, other: &(ApiBackend, u128)) -> bool {
&self.as_tuple() == other
}
}
impl Display for PlatformFrameFormat {
impl Display for PlatformSpecific {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{self:?}")
}
+15 -18
View File
@@ -17,14 +17,14 @@
use crate::{
buffer::Buffer,
error::NokhwaError,
format_request::FormatFilter,
frame_format::SourceFrameFormat,
types::{
ApiBackend, CameraControl, CameraFormat, CameraInfo, ControlValueSetter,
KnownCameraControl, Resolution,
},
};
use std::{borrow::Cow, collections::HashMap};
use crate::frame_format::FrameFormat;
use crate::types::FrameRate;
pub trait Backend {
const BACKEND: ApiBackend;
@@ -40,10 +40,7 @@ pub trait Backend {
pub trait CaptureTrait {
/// Initialize the camera, preparing it for use, with a random format (usually the first one).
fn init(&mut self) -> Result<(), NokhwaError>;
/// Initialize the camera, preparing it for use, with a format that fits the supplied [`FormatFilter`].
fn init_with_format(&mut self, format: FormatFilter) -> Result<CameraFormat, NokhwaError>;
/// Returns the current backend used.
fn backend(&self) -> ApiBackend;
@@ -71,8 +68,8 @@ pub trait CaptureTrait {
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation ([`UnsupportedOperationError`](NokhwaError::UnsupportedOperationError)).
fn compatible_list_by_resolution(
&mut self,
fourcc: SourceFrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError>;
fourcc: FrameFormat,
) -> Result<HashMap<Resolution, Vec<FrameRate>>, NokhwaError>;
/// Gets the compatible [`CameraFormat`] of the camera
/// # Errors
@@ -93,7 +90,7 @@ pub trait CaptureTrait {
/// A Vector of compatible [`FrameFormat`]s. Will only return 2 elements at most.
/// # Errors
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation ([`UnsupportedOperationError`](NokhwaError::UnsupportedOperationError)).
fn compatible_fourcc(&mut self) -> Result<Vec<SourceFrameFormat>, NokhwaError>;
fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError>;
/// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]). This will force refresh to the current latest if it has changed.
fn resolution(&self) -> Option<Resolution>;
@@ -118,7 +115,7 @@ pub trait CaptureTrait {
fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError>;
/// Gets the current camera's frame format (See: [`FrameFormat`], [`CameraFormat`]). This will force refresh to the current latest if it has changed.
fn frame_format(&self) -> SourceFrameFormat;
fn frame_format(&self) -> FrameFormat;
/// Will set the current [`FrameFormat`]
/// This will reset the current stream if used while stream is opened.
@@ -126,7 +123,7 @@ pub trait CaptureTrait {
/// This will also update the cache.
/// # Errors
/// If you started the stream and the camera rejects the new frame format, this will return an error.
fn set_frame_format(&mut self, fourcc: SourceFrameFormat)
fn set_frame_format(&mut self, fourcc: FrameFormat)
-> Result<(), NokhwaError>;
/// Gets the value of [`KnownCameraControl`].
@@ -253,10 +250,6 @@ pub trait AsyncCaptureTrait: CaptureTrait {
/// Initialize the camera, preparing it for use, with a random format (usually the first one).
async fn init_async(&mut self) -> Result<(), NokhwaError>;
/// Initialize the camera, preparing it for use, with a format that fits the supplied [`FormatFilter`].
async fn init_with_format_async(&mut self, format: FormatFilter)
-> Result<CameraFormat, NokhwaError>;
/// Forcefully refreshes the stored camera format, bringing it into sync with "reality" (current camera state)
/// # Errors
/// If the camera can not get its most recent [`CameraFormat`]. this will error.
@@ -275,7 +268,7 @@ pub trait AsyncCaptureTrait: CaptureTrait {
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation ([`UnsupportedOperationError`](NokhwaError::UnsupportedOperationError)).
async fn compatible_list_by_resolution_async(
&mut self,
fourcc: SourceFrameFormat,
fourcc: FrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError>;
/// Gets the compatible [`CameraFormat`] of the camera
@@ -286,7 +279,7 @@ pub trait AsyncCaptureTrait: CaptureTrait {
/// A Vector of compatible [`FrameFormat`]s. Will only return 2 elements at most.
/// # Errors
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation ([`UnsupportedOperationError`](NokhwaError::UnsupportedOperationError)).
async fn compatible_fourcc_async(&mut self) -> Result<Vec<SourceFrameFormat>, NokhwaError>;
async fn compatible_fourcc_async(&mut self) -> Result<Vec<FrameFormat>, NokhwaError>;
/// Will set the current [`Resolution`]
/// This will reset the current stream if used while stream is opened.
@@ -312,7 +305,7 @@ pub trait AsyncCaptureTrait: CaptureTrait {
/// If you started the stream and the camera rejects the new frame format, this will return an error.
async fn set_frame_format_async(
&mut self,
fourcc: SourceFrameFormat,
fourcc: FrameFormat,
) -> Result<(), NokhwaError>;
/// Sets the control to `control` in the camera.
@@ -389,3 +382,7 @@ pub trait AsyncOneShot: AsyncCaptureTrait {
}
pub trait VirtualBackendTrait {}
pub trait Distance<T> where T: PartialEq {
fn distance_from(&self, other: &Self) -> T;
}
+85 -34
View File
@@ -4,17 +4,23 @@ use crate::{
};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::{
fmt::{
Debug,
Display,
Formatter
},
borrow::Borrow,
cmp::Ordering,
fmt::{Display, Formatter},
hash::{Hash, Hasher}
};
use crate::traits::Distance;
/// Creates a range of values.
///
/// Inclusive by default.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
minimum: Option<T>,
lower_inclusive: bool,
@@ -27,6 +33,7 @@ impl<T> Range<T>
where
T: Copy + Clone + Debug + PartialOrd + PartialEq,
{
/// Create an upper and lower inclusive [`Range`]
pub fn new(preferred: Option<T>, min: Option<T>, max: Option<T>) -> Self {
Self {
minimum: min,
@@ -113,7 +120,7 @@ where
}
pub fn reset_preferred(&mut self) {
self.preferred = None
self.preferred = None;
}
pub fn minimum(&self) -> Option<T> {
self.minimum
@@ -311,9 +318,21 @@ impl Ord for Resolution {
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
impl Distance<u32> for Resolution {
fn distance_from(&self, other: &Self) -> u32 {
let x1 = self.x();
let x2 = other.x();
let y1 = self.y();
let y2 = other.y();
(x2 - x1).pow(2) + (y2 - y1).pow(2)
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
/// The frame rate of a camera.
/// The frame rate of a camera. DO NOT CONSTRUCT THIS ENUM DIRECTLY. YOU WILL VIOLATE INVARIANTS. Use [`FrameRate::new_integer`], [`FrameRate::new_fraction`], or [`FrameRate::new_float`] instead.
pub enum FrameRate {
/// The driver reports the frame rate as a clean integer (e.g. 30 FPS).
Integer(u32),
@@ -327,25 +346,39 @@ pub enum FrameRate {
}
impl FrameRate {
pub fn new_integer(fps: u32) -> Self {
FrameRate::Integer(fps)
}
pub fn new_float(fps: f32) -> Self {
FrameRate::Float(fps)
}
pub fn new_fraction(numerator: u16, denominator: u16) -> Self {
FrameRate::Fraction {
numerator,
denominator,
pub fn new_integer(fps: u32) -> Result<Self, NokhwaError> {
if fps == 0 {
return Err(NokhwaError::StructureError { structure: "FrameRate".to_string(), error: "Framerate cannot be 0".to_string() })
}
Ok(FrameRate::Integer(fps))
}
pub fn new_float(fps: f32) -> Result<Self, NokhwaError> {
if fps.is_nan() || fps.is_infinite() || fps.is_sign_negative() || (fps > f32::EPSILON) {
return Err(NokhwaError::StructureError { structure: "FrameRate".to_string(), error: "Invalid F32 FrameRate".to_string() })
}
Ok(FrameRate::Float(fps))
}
pub fn new_fraction(numerator: u16, denominator: u16) -> Result<Self, NokhwaError> {
if numerator == 0 || denominator == 0 {
return Err(NokhwaError::StructureError { structure: "FrameRate".to_string(), error: "Invalid Fraction (denominator or numerator is 0)".to_string() })
}
Ok(
FrameRate::Fraction {
numerator,
denominator,
}
)
}
pub fn as_float(&self) -> f32 {
match self {
FrameRate::Integer(fps) => *fps as f32,
FrameRate::Float(fps) => fps,
FrameRate::Float(fps) => *fps,
FrameRate::Fraction { numerator, denominator } => (*numerator as f32) / (*denominator as f32)
}
}
@@ -354,7 +387,7 @@ impl FrameRate {
match self {
FrameRate::Integer(fps) => *fps,
FrameRate::Float(fps) => *fps as u32,
FrameRate::Fraction { numerator, denominator } => numerator / denominator,
FrameRate::Fraction { numerator, denominator } => (numerator / denominator) as u32,
}
}
}
@@ -373,11 +406,20 @@ impl PartialOrd for FrameRate {
}
}
impl Ord for FrameRate {
fn cmp(&self, other: &Self) -> Ordering {
let this_float = self.as_float();
let other = other.as_float();
this_float.total_cmp(&other)
impl Hash for FrameRate {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
FrameRate::Integer(i) => {
state.write_u32(*i)
}
FrameRate::Float(f) => {
state.write(f.to_string().as_bytes())
}
FrameRate::Fraction { denominator, numerator } => {
state.write_u16(*denominator);
state.write_u16(*numerator);
}
}
}
}
@@ -394,6 +436,15 @@ impl Display for FrameRate {
}
}
impl Distance<f32> for FrameRate {
fn distance_from(&self, other: &Self) -> f32 {
let self_as_float = self.as_float();
let other_as_float = other.as_float();
self_as_float.powi(2) + other_as_float.powi(2)
}
}
impl From<u32> for FrameRate {
fn from(value: u32) -> Self {
FrameRate::Integer(value)
@@ -416,8 +467,8 @@ impl From<(u16, u16)> for FrameRate {
}
/// This is a convenience struct that holds all information about the format of a webcam stream.
/// It consists of a [`Resolution`], [`FrameFormat`], and a frame rate(u8).
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
/// It consists of a [`Resolution`], [`FrameFormat`], and a [`FrameRate`].
#[derive(Copy, Clone, Debug, Hash, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct CameraFormat {
resolution: Resolution,
@@ -1593,13 +1644,13 @@ pub fn buf_yuyv422_to_rgb(data: &[u8], dest: &mut [u8], rgba: bool) -> Result<()
let y1 = chunk[2] as f32;
let v = chunk[3] as f32;
let r0 = y0 + 1.370705 * (v - 128.);
let g0 = y0 - 0.698001 * (v - 128.) - 0.337633 * (u - 128.);
let b0 = y0 + 1.732446 * (u - 128.);
let r0 = y0 + 1.370_705 * (v - 128.);
let g0 = y0 - 0.698_001 * (v - 128.) - 0.337_633 * (u - 128.);
let b0 = y0 + 1.732_446 * (u - 128.);
let r1 = y1 + 1.370705 * (v - 128.);
let g1 = y1 - 0.698001 * (v - 128.) - 0.337633 * (u - 128.);
let b1 = y1 + 1.732446 * (u - 128.);
let r1 = y1 + 1.370_705 * (v - 128.);
let g1 = y1 - 0.698_001 * (v - 128.) - 0.337_633 * (u - 128.);
let b1 = y1 + 1.732_446 * (u - 128.);
if rgba {
buf.extend_from_slice(&[