diff --git a/nokhwa-core/src/format_filter.rs b/nokhwa-core/src/format_filter.rs index 4a83aab..e5b0231 100644 --- a/nokhwa-core/src/format_filter.rs +++ b/nokhwa-core/src/format_filter.rs @@ -1,13 +1,14 @@ use crate::frame_format::FrameFormat; -use crate::types::{CameraFormat, Resolution}; -use std::collections::HashMap; - +use crate::types::{ApiBackend, CameraFormat, Resolution}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; /// 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 (the `Option`). /// - `HighestFrameRate(u32)`: Pick the highest frame rate for the given [`Resolution`] (the `Option`). +/// - `Exact`: Pick the exact [`CameraFormat`] provided. +/// - `Closest`: Pick the closest [`CameraFormat`] provided in order of [`FrameFormat`], [`Resolution`], and FPS. /// - `None`: Pick a random [`CameraFormat`] #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] @@ -16,10 +17,165 @@ pub enum RequestedFormatType { AbsoluteHighestFrameRate, HighestResolution(Resolution), HighestFrameRate(u32), + Exact(CameraFormat), + Closest(CameraFormat), None, } - +#[derive(Clone, Debug)] pub struct FormatFilter { - filter_pref: + filter_pref: RequestedFormatType, + fcc_primary: BTreeSet, + fcc_platform: BTreeMap>, +} + +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.push(frame_format), + None => self + .fcc_platform + .insert(platform, BTreeSet::from([frame_format])), + }; + } + + pub fn add_allowed_platform_specific_many( + &mut self, + platform_specifics: impl IntoPlatformSpecificMany, + ) { + for (platform, frame_format) in platform_specifics.into_psm().into_iter() { + match self.fcc_platform.get_mut(&platform) { + Some(fccs) => fccs.push(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 { + match self.fcc_platform.get_mut(&platform) { + Some(fccs) => fccs.push(frame_format), + None => self + .fcc_platform + .insert(platform, BTreeSet::from([frame_format])), + }; + self + } + + pub fn with_allowed_platform_specific_many( + mut self, + platform_specifics: impl IntoPlatformSpecificMany, + ) -> 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, + 30, + )), + fcc_primary: BTreeSet::from([FrameFormat::Yuv422]), + fcc_platform: Default::default(), + } + } +} + +pub trait IntoPlatformSpecificMany { + fn into_psm(self) -> Vec<(ApiBackend, u128)>; +} + +impl IntoPlatformSpecificMany for T +where + T: AsRef<(ApiBackend, u128)>, +{ + fn into_psm(self) -> Vec<(ApiBackend, u128)> { + vec![*self.as_ref()] + } +} +impl IntoPlatformSpecificMany for T +where + T: AsRef<[(ApiBackend, u128)]>, +{ + fn into_psm(self) -> Vec<(ApiBackend, u128)> { + self.as_ref().iter().collect() + } +} + +impl IntoPlatformSpecificMany for BTreeMap +where + T: AsRef<[u128]>, +{ + fn into_psm(self) -> Vec<(ApiBackend, u128)> { + self.into_iter() + .flat_map(|(backend, fourcc_lst)| fourcc_lst.as_ref().iter().map(|fcc| (backend, *fcc))) + .collect() + } +} + +impl IntoPlatformSpecificMany for HashMap +where + T: AsRef<[u128]>, +{ + fn into_psm(self) -> Vec<(ApiBackend, u128)> { + self.into_iter() + .flat_map(|(backend, fourcc_lst)| fourcc_lst.as_ref().iter().map(|fcc| (backend, *fcc))) + .collect() + } +} + +impl IntoPlatformSpecificMany for &T +where + T: IntoPlatformSpecificMany + Clone, +{ + fn into_psm(self) -> Vec<(ApiBackend, u128)> { + self.clone().into_psm() + } +} + +impl IntoPlatformSpecificMany for &mut T +where + T: IntoPlatformSpecificMany + Clone, +{ + fn into_psm(self) -> Vec<(ApiBackend, u128)> { + self.clone().into_psm() + } } diff --git a/nokhwa-core/src/frame_format.rs b/nokhwa-core/src/frame_format.rs index 66baca4..955e54f 100644 --- a/nokhwa-core/src/frame_format.rs +++ b/nokhwa-core/src/frame_format.rs @@ -102,3 +102,56 @@ impl Display for FrameFormat { write!(f, "{self:?}") } } + +/* + * Copyright 2022 l1npengtul / The Nokhwa Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +use crate::buffer::Buffer; +use crate::types::ApiBackend; +use image::{ImageBuffer, Luma, LumaA, Primitive, Rgb, Rgba}; +use std::ops::Deref; + +pub trait FormatDecoders: Send + Sync { + const NAME: &'static str; + + const PRIMARY: &'static [FrameFormat]; + + const PLATFORM_ACCEPTABLE: &'static [(ApiBackend, &'static [u128])]; + + type Primitive: Primitive; + + type Container: Deref; +} + +pub trait RgbDecoder: FormatDecoders { + fn decode_rgb(&self, buffer: &Buffer) -> ImageBuffer, Self::Container>; +} + +pub trait RgbADecoder: FormatDecoders { + fn decode_rgba(&self, buffer: &Buffer) -> ImageBuffer, Self::Container>; +} + +pub trait LumaDecoder: FormatDecoders { + fn decode_luma(&self, buffer: &Buffer) -> ImageBuffer, Self::Container>; +} + +pub trait LumaADecoder: FormatDecoders { + fn decode_luma_a( + &self, + buffer: &Buffer, + ) -> ImageBuffer, Self::Container>; +} + +// TODO: Wgpu Decoder diff --git a/nokhwa-core/src/pixel_format.rs b/nokhwa-core/src/pixel_format.rs deleted file mode 100644 index b4373e4..0000000 --- a/nokhwa-core/src/pixel_format.rs +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2022 l1npengtul / The Nokhwa Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -use crate::buffer::Buffer; -use crate::frame_format::FrameFormat; -use image::{ImageBuffer, Luma, LumaA, Primitive, Rgb, Rgba}; -use std::ops::Deref; - -pub trait FormatDecoders: Send + Sync { - const NAME: &'static str; - - const PRIMARY: FrameFormat; - - const ACCEPTABLE: &'static [FrameFormat]; - - const PLATFORM_ACCEPTABLE: &'static [(&'static str, &'static [u128])]; - - type Primitive: Primitive; - - type Container: Deref; -} - -pub trait RgbDecoder: FormatDecoders { - fn decode_rgb(&self, buffer: &Buffer) -> ImageBuffer, Self::Container>; -} - -pub trait RgbADecoder: FormatDecoders { - fn decode_rgba(&self, buffer: &Buffer) -> ImageBuffer, Self::Container>; -} - -pub trait LumaDecoder: FormatDecoders { - fn decode_luma(&self, buffer: &Buffer) -> ImageBuffer, Self::Container>; -} - -pub trait LumaADecoder: FormatDecoders { - fn decode_luma_a( - &self, - buffer: &Buffer, - ) -> ImageBuffer, Self::Container>; -} - -// TODO: Wgpu Decoder