diff --git a/Cargo.toml b/Cargo.toml index 69eb48c..5d40415 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,10 +19,10 @@ exclude = ["examples/jscam"] crate-type = ["cdylib", "rlib"] [features] -default = ["flume", "decoding"] +default = ["decoding"] serialize = ["serde", "nokhwa-core/serialize"] decoding = ["nokhwa-core/mjpeg"] -input-avfoundation = ["nokhwa-bindings-macos"] +input-avfoundation = ["nokhwa-bindings-macos", "flume"] input-msmf = ["nokhwa-bindings-windows"] input-v4l = ["nokhwa-bindings-linux"] input-native = ["input-avfoundation", "input-v4l", "input-msmf"] @@ -33,6 +33,7 @@ input-jscam = ["web-sys", "js-sys", "wasm-bindgen-futures", "wasm-bindgen", "was output-wgpu = ["wgpu", "nokhwa-core/wgpu-types"] #output-wasm = ["input-jscam"] output-threaded = [] +output-async = ["nokhwa-core/async"] small-wasm = [] docs-only = ["input-native", "input-opencv", "input-jscam","output-wgpu", "output-threaded", "serialize"] docs-nolink = ["nokhwa-core/docs-features"] @@ -72,7 +73,7 @@ version = "0.15" optional = true [dependencies.opencv] -version = "0.76" +version = "0.77" default-features = false features = ["videoio"] optional = true diff --git a/nokhwa-bindings-linux/src/lib.rs b/nokhwa-bindings-linux/src/lib.rs index 213fcdb..326a2fb 100644 --- a/nokhwa-bindings-linux/src/lib.rs +++ b/nokhwa-bindings-linux/src/lib.rs @@ -19,7 +19,7 @@ mod internal { use nokhwa_core::{ buffer::Buffer, error::NokhwaError, - traits::CaptureBackendTrait, + traits::CaptureTrait, types::{ ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription, ControlValueSetter, FrameFormat, KnownCameraControl, @@ -118,9 +118,9 @@ mod internal { } /// The backend struct that interfaces with V4L2. - /// To see what this does, please see [`CaptureBackendTrait`]. + /// To see what this does, please see [`CaptureTrait`]. /// # Quirks - /// - Calling [`set_resolution()`](CaptureBackendTrait::set_resolution), [`set_frame_rate()`](CaptureBackendTrait::set_frame_rate), or [`set_frame_format()`](CaptureBackendTrait::set_frame_format) each internally calls [`set_camera_format()`](CaptureBackendTrait::set_camera_format). + /// - Calling [`set_resolution()`](CaptureTrait::set_resolution), [`set_frame_rate()`](CaptureTrait::set_frame_rate), or [`set_frame_format()`](CaptureTrait::set_frame_format) each internally calls [`set_camera_format()`](CaptureTrait::set_camera_format). pub struct V4LCaptureDevice<'a> { camera_format: CameraFormat, camera_info: CameraInfo, @@ -391,7 +391,7 @@ mod internal { } } - impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> { + impl<'a> CaptureTrait for V4LCaptureDevice<'a> { fn backend(&self) -> ApiBackend { ApiBackend::Video4Linux } @@ -810,7 +810,7 @@ mod internal { mod internal { use nokhwa_core::buffer::Buffer; use nokhwa_core::error::NokhwaError; - use nokhwa_core::traits::CaptureBackendTrait; + use nokhwa_core::traits::CaptureTrait; use nokhwa_core::types::{ ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, Resolution, @@ -834,9 +834,9 @@ mod internal { } /// The backend struct that interfaces with V4L2. - /// To see what this does, please see [`CaptureBackendTrait`]. + /// To see what this does, please see [`CaptureTrait`]. /// # Quirks - /// - Calling [`set_resolution()`](CaptureBackendTrait::set_resolution), [`set_frame_rate()`](CaptureBackendTrait::set_frame_rate), or [`set_frame_format()`](CaptureBackendTrait::set_frame_format) each internally calls [`set_camera_format()`](CaptureBackendTrait::set_camera_format). + /// - Calling [`set_resolution()`](CaptureTrait::set_resolution), [`set_frame_rate()`](CaptureTrait::set_frame_rate), or [`set_frame_format()`](CaptureTrait::set_frame_format) each internally calls [`set_camera_format()`](CaptureTrait::set_camera_format). pub struct V4LCaptureDevice<'a> { __holder: PhantomData<&'a str>, } @@ -880,7 +880,7 @@ mod internal { } #[allow(unused_variables)] - impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> { + impl<'a> CaptureTrait for V4LCaptureDevice<'a> { fn backend(&self) -> ApiBackend { ApiBackend::Video4Linux } diff --git a/nokhwa-core/Cargo.toml b/nokhwa-core/Cargo.toml index 9cec9f9..43b2c51 100644 --- a/nokhwa-core/Cargo.toml +++ b/nokhwa-core/Cargo.toml @@ -17,6 +17,7 @@ wgpu-types = ["wgpu"] mjpeg = ["mozjpeg"] opencv-mat = ["opencv"] docs-features = ["serialize", "wgpu-types", "mjpeg"] +async = ["async-trait"] test-fail-warnings = [] @@ -38,7 +39,7 @@ version = "0.15" optional = true [dependencies.opencv] -version = "0.76" +version = "0.77" default-features = false optional = true @@ -46,5 +47,9 @@ optional = true version = "0.9" optional = true +[dependencies.async-trait] +version = "0.1" +optional = true + [package.metadata.docs.rs] features = ["docs-features"] diff --git a/nokhwa-core/src/traits.rs b/nokhwa-core/src/traits.rs index 595ee5a..335ff15 100644 --- a/nokhwa-core/src/traits.rs +++ b/nokhwa-core/src/traits.rs @@ -14,12 +14,11 @@ * limitations under the License. */ -use crate::frame_format::SourceFrameFormat; use crate::{ buffer::Buffer, error::NokhwaError, format_filter::FormatFilter, - frame_format::FrameFormat, + frame_format::{FrameFormat, SourceFrameFormat}, types::{ ApiBackend, CameraControl, CameraFormat, CameraInfo, ControlValueSetter, KnownCameraControl, Resolution, @@ -27,14 +26,18 @@ use crate::{ }; use std::{borrow::Cow, collections::HashMap}; +pub trait Backend { + const BACKEND: ApiBackend; +} + /// This trait is for any backend that allows you to grab and take frames from a camera. /// Many of the backends are **blocking**, if the camera is occupied the library will block while it waits for it to become available. /// /// **Note**: /// - Backends, if not provided with a camera format, will be spawned with 640x480@15 FPS, MJPEG [`CameraFormat`]. /// - Behaviour can differ from backend to backend. While the Camera struct abstracts most of this away, if you plan to use the raw backend structs please read the `Quirks` section of each backend. -/// - If you call [`stop_stream()`](CaptureBackendTrait::stop_stream()), you will usually need to call [`open_stream()`](CaptureBackendTrait::open_stream()) to get more frames from the camera. -pub trait CaptureBackendTrait { +/// - If you call [`stop_stream()`](CaptureTrait::stop_stream()), you will usually need to call [`open_stream()`](CaptureTrait::open_stream()) to get more frames from the camera. +pub trait CaptureTrait { /// Initialize the camera, preparing it for use, with a random format (usually the first one). fn init(&mut self) -> Result<(), NokhwaError>; @@ -53,7 +56,7 @@ pub trait CaptureBackendTrait { fn refresh_camera_format(&mut self) -> Result<(), NokhwaError>; /// Gets the current [`CameraFormat`]. This will force refresh to the current latest if it has changed. - fn camera_format(&self) -> CameraFormat; + fn camera_format(&self) -> Option; /// Will set the current [`CameraFormat`] /// This will reset the current stream if used while stream is opened. @@ -93,7 +96,7 @@ pub trait CaptureBackendTrait { fn compatible_fourcc(&mut self) -> Result, NokhwaError>; /// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]). This will force refresh to the current latest if it has changed. - fn resolution(&self) -> Resolution; + fn resolution(&self) -> Option; /// Will set the current [`Resolution`] /// This will reset the current stream if used while stream is opened. @@ -104,7 +107,7 @@ pub trait CaptureBackendTrait { fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError>; /// Gets the current camera framerate (See: [`CameraFormat`]). This will force refresh to the current latest if it has changed. - fn frame_rate(&self) -> u32; + fn frame_rate(&self) -> Option; /// Will set the current framerate /// This will reset the current stream if used while stream is opened. @@ -115,7 +118,7 @@ pub trait CaptureBackendTrait { 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) -> FrameFormat; + fn frame_format(&self) -> SourceFrameFormat; /// Will set the current [`FrameFormat`] /// This will reset the current stream if used while stream is opened. @@ -123,7 +126,8 @@ pub trait CaptureBackendTrait { /// 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: FrameFormat) -> Result<(), NokhwaError>; + fn set_frame_format(&mut self, fourcc: impl Into) + -> Result<(), NokhwaError>; /// Gets the value of [`KnownCameraControl`]. /// # Errors @@ -137,7 +141,7 @@ pub trait CaptureBackendTrait { fn camera_controls(&self) -> Result, NokhwaError>; /// Sets the control to `control` in the camera. - /// Usually, the pipeline is calling [`camera_control()`](CaptureBackendTrait::camera_control), getting a camera control that way + /// 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. /// # Errors /// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control, @@ -148,7 +152,7 @@ pub trait CaptureBackendTrait { value: ControlValueSetter, ) -> Result<(), NokhwaError>; - /// Will open the camera stream with set parameters. This will be called internally if you try and call [`frame()`](CaptureBackendTrait::frame()) before you call [`open_stream()`](CaptureBackendTrait::open_stream()). + /// Will open the camera stream with set parameters. This will be called internally if you try and call [`frame()`](CaptureTrait::frame()) before you call [`open_stream()`](CaptureTrait::open_stream()). /// # Errors /// If the specific backend fails to open the camera (e.g. already taken, busy, doesn't exist anymore) this will error. fn open_stream(&mut self) -> Result<(), NokhwaError>; @@ -156,16 +160,16 @@ pub trait CaptureBackendTrait { /// Checks if stream if open. If it is, it will return true. fn is_stream_open(&self) -> bool; - /// Will get a frame from the camera as a [`Buffer`]. Depending on the backend, if you have not called [`open_stream()`](CaptureBackendTrait::open_stream()) before you called this, + /// Will get a frame from the camera as a [`Buffer`]. Depending on the backend, if you have not called [`open_stream()`](CaptureTrait::open_stream()) before you called this, /// it will either return an error. /// # Errors - /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), the decoding fails (e.g. MJPEG -> u8), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, + /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), the decoding fails (e.g. MJPEG -> u8), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, /// this will error. fn frame(&mut self) -> Result; /// Will get a frame from the camera **without** any processing applied, meaning you will usually get a frame you need to decode yourself. /// # Errors - /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, this will error. + /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, this will error. fn frame_raw(&mut self) -> Result, NokhwaError>; // #[cfg(feature = "wgpu-types")] @@ -234,15 +238,107 @@ pub trait CaptureBackendTrait { fn stop_stream(&mut self) -> Result<(), NokhwaError>; } -impl From for Box +impl From for Box where - T: CaptureBackendTrait + 'static, + T: CaptureTrait + 'static, { fn from(backend: T) -> Self { Box::new(backend) } } -pub trait AsyncCaptureBackendTrait: CaptureBackendTrait {} +#[cfg(feature = "async")] +#[cfg_attr(feature = "async", async_trait::async_trait)] +pub trait AsyncCaptureTrait: CaptureTrait { + /// Initialize the camera, preparing it for use, with a random format (usually the first one). + async fn init(&mut self) -> Result<(), NokhwaError>; + + /// Initialize the camera, preparing it for use, with a format that fits the supplied [`FormatFilter`]. + async fn init_with_format(&mut self, format: FormatFilter) + -> Result; + + /// 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. + async fn refresh_camera_format(&mut self) -> Result<(), NokhwaError>; + + /// Will set the current [`CameraFormat`] + /// This will reset the current stream if used while stream is opened. + /// + /// This will also update the cache. + /// # Errors + /// If you started the stream and the camera rejects the new camera format, this will return an error. + async fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError>; + + /// Will set the current [`Resolution`] + /// This will reset the current stream if used while stream is opened. + /// + /// This will also update the cache. + /// # Errors + /// If you started the stream and the camera rejects the new resolution, this will return an error. + async fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError>; + + /// Will set the current framerate + /// This will reset the current stream if used while stream is opened. + /// + /// This will also update the cache. + /// # Errors + /// If you started the stream and the camera rejects the new framerate, this will return an error. + async fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError>; + + /// Will set the current [`FrameFormat`] + /// This will reset the current stream if used while stream is opened. + /// + /// 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. + async fn set_frame_format( + &mut self, + fourcc: impl Into, + ) -> Result<(), 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. + /// # Errors + /// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control, + /// this will error. + async fn set_camera_control( + &mut self, + id: KnownCameraControl, + value: ControlValueSetter, + ) -> Result<(), NokhwaError>; + + /// Will open the camera stream with set parameters. This will be called internally if you try and call [`frame()`](CaptureTrait::frame()) before you call [`open_stream()`](CaptureTrait::open_stream()). + /// # Errors + /// If the specific backend fails to open the camera (e.g. already taken, busy, doesn't exist anymore) this will error. + async fn open_stream(&mut self) -> Result<(), NokhwaError>; + + /// Will get a frame from the camera as a [`Buffer`]. Depending on the backend, if you have not called [`open_stream()`](CaptureTrait::open_stream()) before you called this, + /// it will either return an error. + /// # Errors + /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), the decoding fails (e.g. MJPEG -> u8), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, + /// this will error. + async fn frame(&mut self) -> Result; + + /// Will get a frame from the camera **without** any processing applied, meaning you will usually get a frame you need to decode yourself. + /// # Errors + /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, this will error. + async fn frame_raw(&mut self) -> Result, NokhwaError>; + + /// Will drop the stream. + /// # Errors + /// Please check the `Quirks` section of each backend. + async fn stop_stream(&mut self) -> Result<(), NokhwaError>; +} + +impl From for Box +where + T: AsyncCaptureTrait + 'static, +{ + fn from(backend: T) -> Self { + Box::new(backend) + } +} pub trait VirtualBackendTrait {} diff --git a/nokhwa-core/src/types.rs b/nokhwa-core/src/types.rs index d00c16f..ce26b49 100644 --- a/nokhwa-core/src/types.rs +++ b/nokhwa-core/src/types.rs @@ -425,7 +425,7 @@ impl Display for CameraInfo { /// The list of known camera controls to the library.
/// These can control the picture brightness, etc.
-/// Note that not all backends/devices support all these. Run [`supported_camera_controls()`](crate::traits::CaptureBackendTrait::camera_controls) to see which ones can be set. +/// Note that not all backends/devices support all these. Run [`supported_camera_controls()`](crate::traits::CaptureTrait::camera_controls) to see which ones can be set. #[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)] #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] pub enum KnownCameraControl { diff --git a/src/async_camera.rs b/src/async_camera.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/backends/capture/avfoundation.rs b/src/backends/capture/avfoundation.rs index fe83d81..cfae42d 100644 --- a/src/backends/capture/avfoundation.rs +++ b/src/backends/capture/avfoundation.rs @@ -24,7 +24,7 @@ use nokhwa_core::{ buffer::Buffer, error::NokhwaError, pixel_format::RgbFormat, - traits::CaptureBackendTrait, + traits::CaptureTrait, types::{ ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, RequestedFormatType, Resolution, @@ -36,7 +36,7 @@ use std::{ffi::CString, sync::Arc}; use std::{borrow::Cow, collections::HashMap}; /// The backend struct that interfaces with V4L2. -/// To see what this does, please see [`CaptureBackendTrait`]. +/// To see what this does, please see [`CaptureTrait`]. /// # Quirks /// - While working with `iOS` is allowed, it is not officially supported and may not work. /// - You **must** call [`nokhwa_initialize`](crate::nokhwa_initialize) **before** doing anything with `AVFoundation`. @@ -121,7 +121,7 @@ impl AVFoundationCaptureDevice { } #[cfg(target_os = "macos")] -impl CaptureBackendTrait for AVFoundationCaptureDevice { +impl CaptureTrait for AVFoundationCaptureDevice { fn backend(&self) -> ApiBackend { ApiBackend::AVFoundation } @@ -352,7 +352,7 @@ impl Drop for AVFoundationCaptureDevice { } /// The backend struct that interfaces with V4L2. -/// To see what this does, please see [`CaptureBackendTrait`]. +/// To see what this does, please see [`CaptureTrait`]. /// # Quirks /// - While working with `iOS` is allowed, it is not officially supported and may not work. /// - You **must** call [`nokhwa_initialize`](crate::nokhwa_initialize) **before** doing anything with `AVFoundation`. @@ -395,7 +395,7 @@ impl AVFoundationCaptureDevice { #[cfg(not(target_os = "macos"))] #[allow(unreachable_code)] -impl CaptureBackendTrait for AVFoundationCaptureDevice { +impl CaptureTrait for AVFoundationCaptureDevice { fn backend(&self) -> ApiBackend { todo!() } diff --git a/src/backends/capture/msmf_backend.rs b/src/backends/capture/msmf_backend.rs index 0a8597b..2b3ea17 100644 --- a/src/backends/capture/msmf_backend.rs +++ b/src/backends/capture/msmf_backend.rs @@ -18,7 +18,7 @@ use nokhwa_core::{ buffer::Buffer, error::NokhwaError, pixel_format::RgbFormat, - traits::CaptureBackendTrait, + traits::CaptureTrait, types::{ all_known_camera_controls, ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, @@ -28,7 +28,7 @@ use nokhwa_core::{ use std::{borrow::Cow, collections::HashMap}; /// The backend that deals with Media Foundation on Windows. -/// To see what this does, please see [`CaptureBackendTrait`]. +/// To see what this does, please see [`CaptureTrait`]. /// /// Note: This requires Windows 7 or newer to work. /// # Quirks @@ -108,7 +108,7 @@ impl MediaFoundationCaptureDevice { } } -impl CaptureBackendTrait for MediaFoundationCaptureDevice { +impl CaptureTrait for MediaFoundationCaptureDevice { fn backend(&self) -> ApiBackend { ApiBackend::MediaFoundation } diff --git a/src/backends/capture/opencv_backend.rs b/src/backends/capture/opencv_backend.rs index 6cca332..9c418c1 100644 --- a/src/backends/capture/opencv_backend.rs +++ b/src/backends/capture/opencv_backend.rs @@ -18,7 +18,7 @@ use nokhwa_core::types::RequestedFormatType; use nokhwa_core::{ buffer::Buffer, error::NokhwaError, - traits::CaptureBackendTrait, + traits::CaptureTrait, types::{ ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueDescription, ControlValueSetter, FrameFormat, KnownCameraControl, RequestedFormat, Resolution, @@ -61,7 +61,7 @@ pub fn known_camera_control_to_video_capture_property( /// The backend struct that interfaces with `OpenCV`. Note that an `opencv` matching the version that this was either compiled on must be present on the user's machine. (usually 4.5.2 or greater) /// For more information, please see [`opencv-rust`](https://github.com/twistedfall/opencv-rust) and [`OpenCV VideoCapture Docs`](https://docs.opencv.org/4.5.2/d8/dfe/classcv_1_1VideoCapture.html). /// -/// To see what this does, please see [`CaptureBackendTrait`] +/// To see what this does, please see [`CaptureTrait`] /// # Quirks /// - **Some features don't work properly on this backend (yet)! Setting [`Resolution`], FPS, [`FrameFormat`] does not work and will default to 640x480 30FPS. This is being worked on.** /// - This is a **cross-platform** backend. This means that it will work on most platforms given that `OpenCV` is present. @@ -69,7 +69,7 @@ pub fn known_camera_control_to_video_capture_property( /// - The backend's backend will default to system level APIs on Linux(V4L2), Mac(AVFoundation), and Windows(Media Foundation). Otherwise, it will decide for itself. /// - If the [`OpenCvCaptureDevice`] is initialized as a `IPCamera`, the [`CameraFormat`]'s `index` value will be [`u32::MAX`](std::u32::MAX) (4294967295). /// - `OpenCV` does not support camera querying. Camera Name and Camera supported resolution/fps/fourcc is a [`UnsupportedOperationError`](NokhwaError::UnsupportedOperationError). -/// Note: [`resolution()`](crate::camera_traits::CaptureBackendTrait::resolution()), [`frame_format()`](crate::camera_traits::CaptureBackendTrait::frame_format()), and [`frame_rate()`](crate::camera_traits::CaptureBackendTrait::frame_rate()) is not affected. +/// Note: [`resolution()`](crate::camera_traits::CaptureTrait::resolution()), [`frame_format()`](crate::camera_traits::CaptureTrait::frame_format()), and [`frame_rate()`](crate::camera_traits::CaptureTrait::frame_rate()) is not affected. /// - [`CameraInfo`]'s human name will be "`OpenCV` Capture Device {location}" /// - [`CameraInfo`]'s description will contain the Camera's Index or IP. /// - The API Preference order is the native OS API (linux => `v4l2`, mac => `AVFoundation`, windows => `MSMF`) than [`CAP_AUTO`](https://docs.opencv.org/4.5.2/d4/d15/group__videoio__flags__base.html#gga023786be1ee68a9105bf2e48c700294da77ab1fe260fd182f8ec7655fab27a31d) @@ -283,7 +283,7 @@ impl OpenCvCaptureDevice { } } -impl CaptureBackendTrait for OpenCvCaptureDevice { +impl CaptureTrait for OpenCvCaptureDevice { fn backend(&self) -> ApiBackend { ApiBackend::OpenCv } diff --git a/src/camera.rs b/src/camera.rs index 5f35492..fe29ed5 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -14,15 +14,16 @@ * limitations under the License. */ -use nokhwa_core::types::RequestedFormatType; +use nokhwa_core::format_filter::FormatFilter; +use nokhwa_core::frame_format::SourceFrameFormat; use nokhwa_core::{ buffer::Buffer, error::NokhwaError, pixel_format::FormatDecoder, - traits::CaptureBackendTrait, + traits::CaptureTrait, types::{ ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter, - FrameFormat, KnownCameraControl, RequestedFormat, Resolution, + FrameFormat, KnownCameraControl, RequestedFormatType, Resolution, }, }; use std::{borrow::Cow, collections::HashMap}; @@ -33,393 +34,495 @@ use wgpu::{Device as WgpuDevice, Queue as WgpuQueue, Texture as WgpuTexture}; pub struct Camera { idx: CameraIndex, api: ApiBackend, - device: Box, + device: Box, } -impl Camera { - /// Create a new camera from an `index` and `format` - /// # Errors - /// This will error if you either have a bad platform configuration (e.g. `input-v4l` but not on linux) or the backend cannot create the camera (e.g. permission denied). - pub fn new(index: CameraIndex, format: RequestedFormat) -> Result { - Camera::with_backend(index, format, ApiBackend::Auto) +impl Camera {} + +// impl Camera { +// /// Create a new camera from an `index` and `format` +// /// # Errors +// /// This will error if you either have a bad platform configuration (e.g. `input-v4l` but not on linux) or the backend cannot create the camera (e.g. permission denied). +// pub fn new(index: CameraIndex, format: RequestedFormat) -> Result { +// Camera::with_backend(index, format, ApiBackend::Auto) +// } +// +// /// Create a new camera from an `index`, `format`, and `backend`. `format` can be `None`. +// /// # Errors +// /// This will error if you either have a bad platform configuration (e.g. `input-v4l` but not on linux) or the backend cannot create the camera (e.g. permission denied). +// pub fn with_backend( +// index: CameraIndex, +// format: RequestedFormat, +// backend: ApiBackend, +// ) -> Result { +// let camera_backend = init_camera(&index, format, backend)?; +// +// Ok(Camera { +// idx: index, +// api: backend, +// device: camera_backend, +// }) +// } +// +// /// Create a new `Camera` from raw values. +// /// # Errors +// /// This will error if you either have a bad platform configuration (e.g. `input-v4l` but not on linux) or the backend cannot create the camera (e.g. permission denied). +// #[deprecated(since = "0.10.0", note = "please use `new` instead.")] +// pub fn new_with( +// index: CameraIndex, +// width: u32, +// height: u32, +// fps: u32, +// fourcc: FrameFormat, +// backend: ApiBackend, +// ) -> Result { +// let camera_format = CameraFormat::new_from(width, height, fourcc, fps); +// Camera::with_backend( +// index, +// RequestedFormat::with_formats(RequestedFormatType::Exact(camera_format), &[fourcc]), +// backend, +// ) +// } +// +// /// Allows creation of a [`Camera`] with a custom backend. This is useful if you are creating e.g. a custom module. +// /// +// /// You **must** have set a format beforehand. +// pub fn with_custom(idx: CameraIndex, api: ApiBackend, device: Box) -> Self { +// Self { idx, api, device } +// } +// +// /// Gets the current Camera's index. +// #[must_use] +// pub fn index(&self) -> &CameraIndex { +// &self.idx +// } +// +// /// Sets the current Camera's index. Note that this re-initializes the camera. +// /// # Errors +// /// The Backend may fail to initialize. +// pub fn set_index(&mut self, new_idx: &CameraIndex) -> Result<(), NokhwaError> { +// { +// self.device.stop_stream()?; +// } +// let new_camera_format = self.device.camera_format(); +// let temp = vec![new_camera_format.format()]; +// let new_camera = init_camera( +// new_idx, +// RequestedFormat::with_formats(RequestedFormatType::Exact(new_camera_format), &temp), +// self.api, +// )?; +// self.device = new_camera; +// Ok(()) +// } +// +// /// Gets the current Camera's backend +// #[must_use] +// pub fn backend(&self) -> ApiBackend { +// self.api +// } +// +// /// Sets the current Camera's backend. Note that this re-initializes the camera. +// /// # Errors +// /// The new backend may not exist or may fail to initialize the new camera. +// pub fn set_backend(&mut self, new_backend: ApiBackend) -> Result<(), NokhwaError> { +// { +// self.device.stop_stream()?; +// } +// let new_camera_format = self.device.camera_format(); +// let temp = vec![new_camera_format.format()]; +// let new_camera = init_camera( +// &self.idx, +// RequestedFormat::with_formats(RequestedFormatType::Exact(new_camera_format), &temp), +// new_backend, +// )?; +// self.device = new_camera; +// Ok(()) +// } +// +// /// Gets the camera information such as Name and Index as a [`CameraInfo`]. +// #[must_use] +// pub fn info(&self) -> &CameraInfo { +// self.device.camera_info() +// } +// +// /// Gets the current [`CameraFormat`]. +// #[must_use] +// pub fn camera_format(&self) -> CameraFormat { +// self.device.camera_format() +// } +// +// /// 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. +// pub fn refresh_camera_format(&mut self) -> Result { +// self.device.refresh_camera_format()?; +// Ok(self.device.camera_format()) +// } +// +// /// Will set the current [`CameraFormat`], using a [`RequestedFormat.`] +// /// This will reset the current stream if used while stream is opened. +// /// +// /// This will also update the cache. +// /// +// /// This will return the new [`CameraFormat`] +// /// # Errors +// /// If nothing fits the requested criteria, this will return an error. +// pub fn set_camera_request( +// &mut self, +// request: RequestedFormat, +// ) -> Result { +// let new_format = request +// .fulfill(self.device.compatible_camera_formats()?.as_slice()) +// .ok_or(NokhwaError::GetPropertyError { +// property: "Compatible Camera Format by request".to_string(), +// error: "Failed to fufill".to_string(), +// })?; +// self.device.set_camera_format(new_format)?; +// Ok(new_format) +// } +// +// #[deprecated(since = "0.10.0", note = "please use `set_camera_request` instead.")] +// /// Will set the current [`CameraFormat`] +// /// This will reset the current stream if used while stream is opened. +// /// +// /// This will also update the cache. +// /// # Errors +// /// If you started the stream and the camera rejects the new camera format, this will return an error. +// pub fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> { +// self.device.set_camera_format(new_fmt) +// } +// +// /// A hashmap of [`Resolution`]s mapped to framerates +// /// # Errors +// /// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError). +// pub fn compatible_list_by_resolution( +// &mut self, +// fourcc: FrameFormat, +// ) -> Result>, NokhwaError> { +// self.device.compatible_list_by_resolution(fourcc) +// } +// +// /// A Vector of compatible [`FrameFormat`]s. +// /// # Errors +// /// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError). +// pub fn compatible_fourcc(&mut self) -> Result, NokhwaError> { +// self.device.compatible_fourcc() +// } +// +// /// A Vector of available [`CameraFormat`]s. +// /// # Errors +// /// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError). +// pub fn compatible_camera_formats(&mut self) -> Result, NokhwaError> { +// self.device.compatible_camera_formats() +// } +// +// /// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]). This will force refresh to the current latest if it has changed. +// #[must_use] +// pub fn resolution(&self) -> Resolution { +// self.device.resolution() +// } +// +// /// Will set the current [`Resolution`] +// /// This will reset the current stream if used while stream is opened. +// /// +// /// This will also update the cache. +// /// # Errors +// /// If you started the stream and the camera rejects the new resolution, this will return an error. +// pub fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> { +// self.device.set_resolution(new_res) +// } +// +// /// Gets the current camera framerate (See: [`CameraFormat`]). +// #[must_use] +// pub fn frame_rate(&self) -> u32 { +// self.device.frame_rate() +// } +// +// /// Will set the current framerate +// /// This will reset the current stream if used while stream is opened. +// /// +// /// This will also update the cache. +// /// # Errors +// /// If you started the stream and the camera rejects the new framerate, this will return an error. +// pub fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError> { +// self.device.set_frame_rate(new_fps) +// } +// +// /// Gets the current camera's frame format (See: [`FrameFormat`], [`CameraFormat`]). This will force refresh to the current latest if it has changed. +// #[must_use] +// pub fn frame_format(&self) -> FrameFormat { +// self.device.frame_format() +// } +// +// /// Will set the current [`FrameFormat`] +// /// This will reset the current stream if used while stream is opened. +// /// +// /// 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. +// pub fn set_frame_format(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> { +// self.device.set_frame_format(fourcc) +// } +// +// /// Gets the current supported list of [`KnownCameraControl`](crate::utils::KnownCameraControl) +// /// # Errors +// /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". +// pub fn supported_camera_controls(&self) -> Result, NokhwaError> { +// Ok(self +// .device +// .camera_controls()? +// .iter() +// .map(CameraControl::control) +// .collect()) +// } +// +// /// Gets the current supported list of [`CameraControl`]s keyed by its name as a `String`. +// /// # Errors +// /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". +// pub fn camera_controls(&self) -> Result, NokhwaError> { +// let known_controls = self.supported_camera_controls()?; +// let maybe_camera_controls = known_controls +// .iter() +// .map(|x| self.camera_control(*x)) +// .filter(Result::is_ok) +// .map(Result::unwrap) +// .collect::>(); +// +// Ok(maybe_camera_controls) +// } +// +// /// Gets the current supported list of [`CameraControl`]s keyed by its name as a `String`. +// /// # Errors +// /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". +// pub fn camera_controls_string(&self) -> Result, NokhwaError> { +// let known_controls = self.supported_camera_controls()?; +// let maybe_camera_controls = known_controls +// .iter() +// .map(|x| (x.to_string(), self.camera_control(*x))) +// .filter(|(_, x)| x.is_ok()) +// .map(|(c, x)| (c, Result::unwrap(x))) +// .collect::>(); +// let mut control_map = HashMap::with_capacity(maybe_camera_controls.len()); +// +// for (kc, cc) in maybe_camera_controls { +// control_map.insert(kc, cc); +// } +// +// Ok(control_map) +// } +// +// /// Gets the current supported list of [`CameraControl`]s keyed by its name as a `String`. +// /// # Errors +// /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". +// pub fn camera_controls_known_camera_controls( +// &self, +// ) -> Result, NokhwaError> { +// let known_controls = self.supported_camera_controls()?; +// let maybe_camera_controls = known_controls +// .iter() +// .map(|x| (*x, self.camera_control(*x))) +// .filter(|(_, x)| x.is_ok()) +// .map(|(c, x)| (c, Result::unwrap(x))) +// .collect::>(); +// let mut control_map = HashMap::with_capacity(maybe_camera_controls.len()); +// +// for (kc, cc) in maybe_camera_controls { +// control_map.insert(kc, cc); +// } +// +// Ok(control_map) +// } +// +// /// 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. +// pub fn camera_control( +// &self, +// control: KnownCameraControl, +// ) -> Result { +// self.device.camera_control(control) +// } +// +// /// Sets the control to `control` in the camera. +// /// Usually, the pipeline is calling [`camera_control()`](crate::camera_traits::CaptureTrait::camera_control), getting a camera control that way +// /// then calling [`value()`](crate::utils::CameraControl::value()) to get a [`ControlValueSetter`](crate::utils::ControlValueSetter) and setting the value that way. +// /// # Errors +// /// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control, +// /// this will error. +// pub fn set_camera_control( +// &mut self, +// id: KnownCameraControl, +// value: ControlValueSetter, +// ) -> Result<(), NokhwaError> { +// self.device.set_camera_control(id, value) +// } +// +// /// Will open the camera stream with set parameters. This will be called internally if you try and call [`frame()`](CaptureTrait::frame()) before you call [`open_stream()`](CaptureTrait::open_stream()). +// /// # Errors +// /// If the specific backend fails to open the camera (e.g. already taken, busy, doesn't exist anymore) this will error. +// pub fn open_stream(&mut self) -> Result<(), NokhwaError> { +// self.device.open_stream() +// } +// +// /// Checks if stream if open. If it is, it will return true. +// #[must_use] +// pub fn is_stream_open(&self) -> bool { +// self.device.is_stream_open() +// } +// +// /// Will get a frame from the camera as a Raw RGB image buffer. Depending on the backend, if you have not called [`open_stream()`](CaptureTrait::open_stream()) before you called this, +// /// it will either return an error. +// /// # Errors +// /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), the decoding fails (e.g. MJPEG -> u8), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, +// /// this will error. +// pub fn frame(&mut self) -> Result { +// self.device.frame() +// } +// +// /// Will get a frame from the camera **without** any processing applied, meaning you will usually get a frame you need to decode yourself. +// /// # Errors +// /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, this will error. +// pub fn frame_raw(&mut self) -> Result, NokhwaError> { +// match self.device.frame_raw() { +// Ok(f) => Ok(f), +// Err(why) => Err(why), +// } +// } +// +// /// Directly writes the current frame into said `buffer`. +// /// # Errors +// /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureTrait::open_stream()) has not been called yet, this will error. +// pub fn write_frame_to_buffer( +// &mut self, +// buffer: &mut [u8], +// ) -> Result<(), NokhwaError> { +// self.device.frame()?.decode_image_to_buffer::(buffer) +// } +// +// #[cfg(feature = "output-wgpu")] +// #[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-wgpu")))] +// /// Directly copies a frame to a Wgpu texture. This will automatically convert the frame into a RGBA frame. +// /// # Errors +// /// If the frame cannot be captured or the resolution is 0 on any axis, this will error. +// pub fn frame_texture<'a, F: FormatDecoder>( +// &mut self, +// device: &WgpuDevice, +// queue: &WgpuQueue, +// label: Option<&'a str>, +// ) -> Result { +// self.device.frame_texture(device, queue, label) +// } +// +// /// Will drop the stream. +// /// # Errors +// /// Please check the `Quirks` section of each backend. +// pub fn stop_stream(&mut self) -> Result<(), NokhwaError> { +// self.device.stop_stream() +// } +// } + +impl CaptureTrait for Camera { + fn init(&mut self) -> Result<(), NokhwaError> { + todo!() } - /// Create a new camera from an `index`, `format`, and `backend`. `format` can be `None`. - /// # Errors - /// This will error if you either have a bad platform configuration (e.g. `input-v4l` but not on linux) or the backend cannot create the camera (e.g. permission denied). - pub fn with_backend( - index: CameraIndex, - format: RequestedFormat, - backend: ApiBackend, - ) -> Result { - let camera_backend = init_camera(&index, format, backend)?; - - Ok(Camera { - idx: index, - api: backend, - device: camera_backend, - }) + fn init_with_format(&mut self, format: FormatFilter) -> Result { + todo!() } - /// Create a new `Camera` from raw values. - /// # Errors - /// This will error if you either have a bad platform configuration (e.g. `input-v4l` but not on linux) or the backend cannot create the camera (e.g. permission denied). - #[deprecated(since = "0.10.0", note = "please use `new` instead.")] - pub fn new_with( - index: CameraIndex, - width: u32, - height: u32, - fps: u32, - fourcc: FrameFormat, - backend: ApiBackend, - ) -> Result { - let camera_format = CameraFormat::new_from(width, height, fourcc, fps); - Camera::with_backend( - index, - RequestedFormat::with_formats(RequestedFormatType::Exact(camera_format), &[fourcc]), - backend, - ) + fn backend(&self) -> ApiBackend { + todo!() } - /// Allows creation of a [`Camera`] with a custom backend. This is useful if you are creating e.g. a custom module. - /// - /// You **must** have set a format beforehand. - pub fn with_custom( - idx: CameraIndex, - api: ApiBackend, - device: Box, - ) -> Self { - Self { idx, api, device } + fn camera_info(&self) -> &CameraInfo { + todo!() } - /// Gets the current Camera's index. - #[must_use] - pub fn index(&self) -> &CameraIndex { - &self.idx + fn refresh_camera_format(&mut self) -> Result<(), NokhwaError> { + todo!() } - /// Sets the current Camera's index. Note that this re-initializes the camera. - /// # Errors - /// The Backend may fail to initialize. - pub fn set_index(&mut self, new_idx: &CameraIndex) -> Result<(), NokhwaError> { - { - self.device.stop_stream()?; - } - let new_camera_format = self.device.camera_format(); - let temp = vec![new_camera_format.format()]; - let new_camera = init_camera( - new_idx, - RequestedFormat::with_formats(RequestedFormatType::Exact(new_camera_format), &temp), - self.api, - )?; - self.device = new_camera; - Ok(()) + fn camera_format(&self) -> Option { + todo!() } - /// Gets the current Camera's backend - #[must_use] - pub fn backend(&self) -> ApiBackend { - self.api + fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> { + todo!() } - /// Sets the current Camera's backend. Note that this re-initializes the camera. - /// # Errors - /// The new backend may not exist or may fail to initialize the new camera. - pub fn set_backend(&mut self, new_backend: ApiBackend) -> Result<(), NokhwaError> { - { - self.device.stop_stream()?; - } - let new_camera_format = self.device.camera_format(); - let temp = vec![new_camera_format.format()]; - let new_camera = init_camera( - &self.idx, - RequestedFormat::with_formats(RequestedFormatType::Exact(new_camera_format), &temp), - new_backend, - )?; - self.device = new_camera; - Ok(()) - } - - /// Gets the camera information such as Name and Index as a [`CameraInfo`]. - #[must_use] - pub fn info(&self) -> &CameraInfo { - self.device.camera_info() - } - - /// Gets the current [`CameraFormat`]. - #[must_use] - pub fn camera_format(&self) -> CameraFormat { - self.device.camera_format() - } - - /// 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. - pub fn refresh_camera_format(&mut self) -> Result { - self.device.refresh_camera_format()?; - Ok(self.device.camera_format()) - } - - /// Will set the current [`CameraFormat`], using a [`RequestedFormat.`] - /// This will reset the current stream if used while stream is opened. - /// - /// This will also update the cache. - /// - /// This will return the new [`CameraFormat`] - /// # Errors - /// If nothing fits the requested criteria, this will return an error. - pub fn set_camera_request( + fn compatible_list_by_resolution( &mut self, - request: RequestedFormat, - ) -> Result { - let new_format = request - .fulfill(self.device.compatible_camera_formats()?.as_slice()) - .ok_or(NokhwaError::GetPropertyError { - property: "Compatible Camera Format by request".to_string(), - error: "Failed to fufill".to_string(), - })?; - self.device.set_camera_format(new_format)?; - Ok(new_format) - } - - #[deprecated(since = "0.10.0", note = "please use `set_camera_request` instead.")] - /// Will set the current [`CameraFormat`] - /// This will reset the current stream if used while stream is opened. - /// - /// This will also update the cache. - /// # Errors - /// If you started the stream and the camera rejects the new camera format, this will return an error. - pub fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> { - self.device.set_camera_format(new_fmt) - } - - /// A hashmap of [`Resolution`]s mapped to framerates - /// # Errors - /// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError). - pub fn compatible_list_by_resolution( - &mut self, - fourcc: FrameFormat, + fourcc: SourceFrameFormat, ) -> Result>, NokhwaError> { - self.device.compatible_list_by_resolution(fourcc) + todo!() } - /// A Vector of compatible [`FrameFormat`]s. - /// # Errors - /// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError). - pub fn compatible_fourcc(&mut self) -> Result, NokhwaError> { - self.device.compatible_fourcc() + fn compatible_fourcc(&mut self) -> Result, NokhwaError> { + todo!() } - /// A Vector of available [`CameraFormat`]s. - /// # Errors - /// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError). - pub fn compatible_camera_formats(&mut self) -> Result, NokhwaError> { - self.device.compatible_camera_formats() + fn resolution(&self) -> Option { + todo!() } - /// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]). This will force refresh to the current latest if it has changed. - #[must_use] - pub fn resolution(&self) -> Resolution { - self.device.resolution() + fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> { + todo!() } - /// Will set the current [`Resolution`] - /// This will reset the current stream if used while stream is opened. - /// - /// This will also update the cache. - /// # Errors - /// If you started the stream and the camera rejects the new resolution, this will return an error. - pub fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> { - self.device.set_resolution(new_res) + fn frame_rate(&self) -> Option { + todo!() } - /// Gets the current camera framerate (See: [`CameraFormat`]). - #[must_use] - pub fn frame_rate(&self) -> u32 { - self.device.frame_rate() + fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError> { + todo!() } - /// Will set the current framerate - /// This will reset the current stream if used while stream is opened. - /// - /// This will also update the cache. - /// # Errors - /// If you started the stream and the camera rejects the new framerate, this will return an error. - pub fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError> { - self.device.set_frame_rate(new_fps) + fn frame_format(&self) -> SourceFrameFormat { + todo!() } - /// Gets the current camera's frame format (See: [`FrameFormat`], [`CameraFormat`]). This will force refresh to the current latest if it has changed. - #[must_use] - pub fn frame_format(&self) -> FrameFormat { - self.device.frame_format() + fn set_frame_format( + &mut self, + fourcc: impl Into, + ) -> Result<(), NokhwaError> { + todo!() } - /// Will set the current [`FrameFormat`] - /// This will reset the current stream if used while stream is opened. - /// - /// 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. - pub fn set_frame_format(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> { - self.device.set_frame_format(fourcc) + fn camera_control(&self, control: KnownCameraControl) -> Result { + todo!() } - /// Gets the current supported list of [`KnownCameraControl`](crate::utils::KnownCameraControl) - /// # Errors - /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". - pub fn supported_camera_controls(&self) -> Result, NokhwaError> { - Ok(self - .device - .camera_controls()? - .iter() - .map(CameraControl::control) - .collect()) + fn camera_controls(&self) -> Result, NokhwaError> { + todo!() } - /// Gets the current supported list of [`CameraControl`]s keyed by its name as a `String`. - /// # Errors - /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". - pub fn camera_controls(&self) -> Result, NokhwaError> { - let known_controls = self.supported_camera_controls()?; - let maybe_camera_controls = known_controls - .iter() - .map(|x| self.camera_control(*x)) - .filter(Result::is_ok) - .map(Result::unwrap) - .collect::>(); - - Ok(maybe_camera_controls) - } - - /// Gets the current supported list of [`CameraControl`]s keyed by its name as a `String`. - /// # Errors - /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". - pub fn camera_controls_string(&self) -> Result, NokhwaError> { - let known_controls = self.supported_camera_controls()?; - let maybe_camera_controls = known_controls - .iter() - .map(|x| (x.to_string(), self.camera_control(*x))) - .filter(|(_, x)| x.is_ok()) - .map(|(c, x)| (c, Result::unwrap(x))) - .collect::>(); - let mut control_map = HashMap::with_capacity(maybe_camera_controls.len()); - - for (kc, cc) in maybe_camera_controls { - control_map.insert(kc, cc); - } - - Ok(control_map) - } - - /// Gets the current supported list of [`CameraControl`]s keyed by its name as a `String`. - /// # Errors - /// If the list cannot be collected, this will error. This can be treated as a "nothing supported". - pub fn camera_controls_known_camera_controls( - &self, - ) -> Result, NokhwaError> { - let known_controls = self.supported_camera_controls()?; - let maybe_camera_controls = known_controls - .iter() - .map(|x| (*x, self.camera_control(*x))) - .filter(|(_, x)| x.is_ok()) - .map(|(c, x)| (c, Result::unwrap(x))) - .collect::>(); - let mut control_map = HashMap::with_capacity(maybe_camera_controls.len()); - - for (kc, cc) in maybe_camera_controls { - control_map.insert(kc, cc); - } - - Ok(control_map) - } - - /// 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. - pub fn camera_control( - &self, - control: KnownCameraControl, - ) -> Result { - self.device.camera_control(control) - } - - /// Sets the control to `control` in the camera. - /// Usually, the pipeline is calling [`camera_control()`](crate::camera_traits::CaptureBackendTrait::camera_control), getting a camera control that way - /// then calling [`value()`](crate::utils::CameraControl::value()) to get a [`ControlValueSetter`](crate::utils::ControlValueSetter) and setting the value that way. - /// # Errors - /// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control, - /// this will error. - pub fn set_camera_control( + fn set_camera_control( &mut self, id: KnownCameraControl, value: ControlValueSetter, ) -> Result<(), NokhwaError> { - self.device.set_camera_control(id, value) + todo!() } - /// Will open the camera stream with set parameters. This will be called internally if you try and call [`frame()`](CaptureBackendTrait::frame()) before you call [`open_stream()`](CaptureBackendTrait::open_stream()). - /// # Errors - /// If the specific backend fails to open the camera (e.g. already taken, busy, doesn't exist anymore) this will error. - pub fn open_stream(&mut self) -> Result<(), NokhwaError> { - self.device.open_stream() + fn open_stream(&mut self) -> Result<(), NokhwaError> { + todo!() } - /// Checks if stream if open. If it is, it will return true. - #[must_use] - pub fn is_stream_open(&self) -> bool { - self.device.is_stream_open() + fn is_stream_open(&self) -> bool { + todo!() } - /// Will get a frame from the camera as a Raw RGB image buffer. Depending on the backend, if you have not called [`open_stream()`](CaptureBackendTrait::open_stream()) before you called this, - /// it will either return an error. - /// # Errors - /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), the decoding fails (e.g. MJPEG -> u8), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, - /// this will error. - pub fn frame(&mut self) -> Result { - self.device.frame() + fn frame(&mut self) -> Result { + todo!() } - /// Will get a frame from the camera **without** any processing applied, meaning you will usually get a frame you need to decode yourself. - /// # Errors - /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, this will error. - pub fn frame_raw(&mut self) -> Result, NokhwaError> { - match self.device.frame_raw() { - Ok(f) => Ok(f), - Err(why) => Err(why), - } + fn frame_raw(&mut self) -> Result, NokhwaError> { + todo!() } - /// Directly writes the current frame into said `buffer`. - /// # Errors - /// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, this will error. - pub fn write_frame_to_buffer( - &mut self, - buffer: &mut [u8], - ) -> Result<(), NokhwaError> { - self.device.frame()?.decode_image_to_buffer::(buffer) - } - - #[cfg(feature = "output-wgpu")] - #[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-wgpu")))] - /// Directly copies a frame to a Wgpu texture. This will automatically convert the frame into a RGBA frame. - /// # Errors - /// If the frame cannot be captured or the resolution is 0 on any axis, this will error. - pub fn frame_texture<'a, F: FormatDecoder>( - &mut self, - device: &WgpuDevice, - queue: &WgpuQueue, - label: Option<&'a str>, - ) -> Result { - self.device.frame_texture(device, queue, label) - } - - /// Will drop the stream. - /// # Errors - /// Please check the `Quirks` section of each backend. - pub fn stop_stream(&mut self) -> Result<(), NokhwaError> { - self.device.stop_stream() + fn stop_stream(&mut self) -> Result<(), NokhwaError> { + todo!() } } @@ -567,7 +670,7 @@ fn init_camera( index: &CameraIndex, format: RequestedFormat, backend: ApiBackend, -) -> Result, NokhwaError> { +) -> Result, NokhwaError> { let camera_backend = cap_impl_matches! { backend, index, format, ("input-v4l", Video4Linux, init_v4l), diff --git a/src/lib.rs b/src/lib.rs index 2bf60b4..2cd0e30 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,7 @@ //! # nokhwa //! A Simple-to-use, cross-platform Rust Webcam Capture Library //! -//! The raw backends can be found in [`backends`](crate::backends) +//! The raw backends can be found in [`backends`](backends) //! //! The [`Camera`] struct is what you will likely use. //! @@ -40,6 +40,9 @@ mod init; pub mod js_camera; pub use nokhwa_core::pixel_format::FormatDecoder; +#[cfg(feature = "output-async")] +#[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-async")))] +pub mod async_camera; mod query; /// A camera that runs in a different thread and can call your code based on callbacks. #[cfg(feature = "output-threaded")] diff --git a/src/threaded.rs b/src/threaded.rs index 70fde8d..725d0a4 100644 --- a/src/threaded.rs +++ b/src/threaded.rs @@ -418,7 +418,7 @@ impl CallbackCamera { } /// Sets the control to `control` in the camera. - /// Usually, the pipeline is calling [`camera_control()`](crate::camera_traits::CaptureBackendTrait::camera_control), getting a camera control that way + /// Usually, the pipeline is calling [`camera_control()`](crate::camera_traits::CaptureTrait::camera_control), getting a camera control that way /// then calling [`value()`](crate::utils::CameraControl::value()) to get a [`ControlValueSetter`](crate::utils::ControlValueSetter) and setting the value that way. /// # Errors /// If the `control` is not supported, the value is invalid (less than min, greater than max, not in step), or there was an error setting the control,