mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 10:37:26 +00:00
finish decoder and frame format searcher implementation
This commit is contained in:
Generated
+741
-1004
File diff suppressed because it is too large
Load Diff
+10
-9
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
@@ -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
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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),);
|
||||
|
||||
@@ -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:?}")
|
||||
}
|
||||
|
||||
+14
-17
@@ -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;
|
||||
@@ -41,9 +41,6 @@ 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;
|
||||
}
|
||||
|
||||
+78
-27
@@ -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_integer(fps: u32) -> Result<Self, NokhwaError> {
|
||||
if fps == 0 {
|
||||
return Err(NokhwaError::StructureError { structure: "FrameRate".to_string(), error: "Framerate cannot be 0".to_string() })
|
||||
}
|
||||
|
||||
pub fn new_float(fps: f32) -> Self {
|
||||
FrameRate::Float(fps)
|
||||
Ok(FrameRate::Integer(fps))
|
||||
}
|
||||
|
||||
pub fn new_fraction(numerator: u16, denominator: u16) -> Self {
|
||||
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(&[
|
||||
|
||||
Reference in New Issue
Block a user