mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
async trait definition. seperate backend and capture trait for code reuse for Camera.
This commit is contained in:
+4
-3
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"]
|
||||
|
||||
+113
-17
@@ -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<CameraFormat>;
|
||||
|
||||
/// 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<Vec<SourceFrameFormat>, 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<Resolution>;
|
||||
|
||||
/// 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<u32>;
|
||||
|
||||
/// 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<SourceFrameFormat>)
|
||||
-> Result<(), NokhwaError>;
|
||||
|
||||
/// Gets the value of [`KnownCameraControl`].
|
||||
/// # Errors
|
||||
@@ -137,7 +141,7 @@ pub trait CaptureBackendTrait {
|
||||
fn camera_controls(&self) -> Result<Vec<CameraControl>, 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<Buffer, NokhwaError>;
|
||||
|
||||
/// 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<Cow<[u8]>, NokhwaError>;
|
||||
|
||||
// #[cfg(feature = "wgpu-types")]
|
||||
@@ -234,15 +238,107 @@ pub trait CaptureBackendTrait {
|
||||
fn stop_stream(&mut self) -> Result<(), NokhwaError>;
|
||||
}
|
||||
|
||||
impl<T> From<T> for Box<dyn CaptureBackendTrait>
|
||||
impl<T> From<T> for Box<dyn CaptureTrait>
|
||||
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<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.
|
||||
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<SourceFrameFormat>,
|
||||
) -> 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<Buffer, NokhwaError>;
|
||||
|
||||
/// 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<Cow<[u8]>, NokhwaError>;
|
||||
|
||||
/// Will drop the stream.
|
||||
/// # Errors
|
||||
/// Please check the `Quirks` section of each backend.
|
||||
async fn stop_stream(&mut self) -> Result<(), NokhwaError>;
|
||||
}
|
||||
|
||||
impl<T> From<T> for Box<dyn AsyncCaptureTrait>
|
||||
where
|
||||
T: AsyncCaptureTrait + 'static,
|
||||
{
|
||||
fn from(backend: T) -> Self {
|
||||
Box::new(backend)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VirtualBackendTrait {}
|
||||
|
||||
@@ -425,7 +425,7 @@ impl Display for CameraInfo {
|
||||
|
||||
/// The list of known camera controls to the library. <br>
|
||||
/// These can control the picture brightness, etc. <br>
|
||||
/// 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 {
|
||||
|
||||
@@ -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!()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
+442
-339
@@ -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<dyn CaptureBackendTrait>,
|
||||
device: Box<dyn CaptureTrait>,
|
||||
}
|
||||
|
||||
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<Self, NokhwaError> {
|
||||
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<Self, NokhwaError> {
|
||||
// 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<Self, NokhwaError> {
|
||||
// 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<Self, NokhwaError> {
|
||||
// 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<dyn CaptureTrait>) -> 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<CameraFormat, NokhwaError> {
|
||||
// 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<CameraFormat, NokhwaError> {
|
||||
// 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<HashMap<Resolution, Vec<u32>>, 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<Vec<FrameFormat>, 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<Vec<CameraFormat>, 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<Vec<KnownCameraControl>, 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<Vec<CameraControl>, 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::<Vec<CameraControl>>();
|
||||
//
|
||||
// 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<HashMap<String, CameraControl>, 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::<Vec<(String, CameraControl)>>();
|
||||
// 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<HashMap<KnownCameraControl, CameraControl>, 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::<Vec<(KnownCameraControl, CameraControl)>>();
|
||||
// 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<CameraControl, NokhwaError> {
|
||||
// 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<Buffer, NokhwaError> {
|
||||
// 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<Cow<[u8]>, 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<F: FormatDecoder>(
|
||||
// &mut self,
|
||||
// buffer: &mut [u8],
|
||||
// ) -> Result<(), NokhwaError> {
|
||||
// self.device.frame()?.decode_image_to_buffer::<F>(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<WgpuTexture, NokhwaError> {
|
||||
// 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<Self, NokhwaError> {
|
||||
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<CameraFormat, NokhwaError> {
|
||||
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<Self, NokhwaError> {
|
||||
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<dyn CaptureBackendTrait>,
|
||||
) -> 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<CameraFormat> {
|
||||
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<CameraFormat, NokhwaError> {
|
||||
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<CameraFormat, NokhwaError> {
|
||||
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<HashMap<Resolution, Vec<u32>>, 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<Vec<FrameFormat>, NokhwaError> {
|
||||
self.device.compatible_fourcc()
|
||||
fn compatible_fourcc(&mut self) -> Result<Vec<SourceFrameFormat>, 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<Vec<CameraFormat>, NokhwaError> {
|
||||
self.device.compatible_camera_formats()
|
||||
fn resolution(&self) -> Option<Resolution> {
|
||||
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<u32> {
|
||||
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<SourceFrameFormat>,
|
||||
) -> 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<CameraControl, NokhwaError> {
|
||||
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<Vec<KnownCameraControl>, NokhwaError> {
|
||||
Ok(self
|
||||
.device
|
||||
.camera_controls()?
|
||||
.iter()
|
||||
.map(CameraControl::control)
|
||||
.collect())
|
||||
fn camera_controls(&self) -> Result<Vec<CameraControl>, 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<Vec<CameraControl>, 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::<Vec<CameraControl>>();
|
||||
|
||||
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<HashMap<String, CameraControl>, 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::<Vec<(String, CameraControl)>>();
|
||||
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<HashMap<KnownCameraControl, CameraControl>, 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::<Vec<(KnownCameraControl, CameraControl)>>();
|
||||
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<CameraControl, NokhwaError> {
|
||||
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<Buffer, NokhwaError> {
|
||||
self.device.frame()
|
||||
fn frame(&mut self) -> Result<Buffer, NokhwaError> {
|
||||
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<Cow<[u8]>, NokhwaError> {
|
||||
match self.device.frame_raw() {
|
||||
Ok(f) => Ok(f),
|
||||
Err(why) => Err(why),
|
||||
}
|
||||
fn frame_raw(&mut self) -> Result<Cow<[u8]>, 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<F: FormatDecoder>(
|
||||
&mut self,
|
||||
buffer: &mut [u8],
|
||||
) -> Result<(), NokhwaError> {
|
||||
self.device.frame()?.decode_image_to_buffer::<F>(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<WgpuTexture, NokhwaError> {
|
||||
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<Box<dyn CaptureBackendTrait>, NokhwaError> {
|
||||
) -> Result<Box<dyn CaptureTrait>, NokhwaError> {
|
||||
let camera_backend = cap_impl_matches! {
|
||||
backend, index, format,
|
||||
("input-v4l", Video4Linux, init_v4l),
|
||||
|
||||
+4
-1
@@ -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")]
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user