mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
buffer impl, fixes for some tings, etc
This commit is contained in:
+10
-2
@@ -19,13 +19,14 @@ crate-type = ["cdylib", "rlib"]
|
||||
|
||||
[features]
|
||||
default = ["flume", "decoding"]
|
||||
serialize = ["serde"]
|
||||
decoding = ["mozjpeg"]
|
||||
input-v4l = ["v4l", "v4l2-sys-mit"]
|
||||
input-msmf = ["nokhwa-bindings-windows"]
|
||||
input-avfoundation = ["nokhwa-bindings-macos"]
|
||||
# Re-enable it once soundness has been proven + mozjpeg is updated to 0.9.x
|
||||
# input-uvc = ["uvc", "uvc/vendor", "ouroboros", "usb_enumeration", "lazy_static"]
|
||||
input-opencv = ["opencv", "opencv/clang-runtime"]
|
||||
input-opencv = ["opencv", "opencv/rgb", "rgb"]
|
||||
input-ipcam = ["input-opencv"]
|
||||
input-gst = ["gstreamer", "glib", "gstreamer-app", "gstreamer-video", "regex", "parking_lot"]
|
||||
input-jscam = ["web-sys", "js-sys", "wasm-bindgen-futures", "wasm-bindgen", "wasm-rs-async-executor"]
|
||||
@@ -44,6 +45,10 @@ paste = "1.0"
|
||||
anymap = "1.0.0-beta.2"
|
||||
enum_dispatch = "0.3"
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.flume]
|
||||
version = "0.10"
|
||||
optional = true
|
||||
@@ -74,7 +79,10 @@ optional = true
|
||||
|
||||
[dependencies.opencv]
|
||||
version = "0.63"
|
||||
features = ["clang-runtime"]
|
||||
optional = true
|
||||
|
||||
[dependencies.rgb]
|
||||
version = "0.8"
|
||||
optional = true
|
||||
|
||||
[dependencies.nokhwa-bindings-windows]
|
||||
|
||||
@@ -374,6 +374,11 @@ impl GStreamerCaptureDevice {
|
||||
.insert(Resolution::new(width as u32, height as u32), fps_vec);
|
||||
}
|
||||
}
|
||||
unsupported => {
|
||||
return Err(NokhwaError::NotImplementedError(format!(
|
||||
"Not supported frame format {unsupported:?}"
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -581,6 +586,9 @@ fn webcam_pipeline(device: &str, camera_format: CameraFormat) -> String {
|
||||
FrameFormat::YUYV => {
|
||||
format!("autovideosrc location=/dev/video{} ! video/x-raw,format=YUY2,width={},height={},framerate={}/1 ! appsink name=appsink async=false sync=false", device, camera_format.width(), camera_format.height(), camera_format.frame_rate())
|
||||
}
|
||||
_ => {
|
||||
format!("unsupproted! if you see this, switch to something else!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,6 +601,9 @@ fn webcam_pipeline(device: &str, camera_format: CameraFormat) -> String {
|
||||
FrameFormat::YUYV => {
|
||||
format!("v4l2src device=/dev/video{} ! video/x-raw,format=YUY2,width={},height={},framerate={}/1 ! appsink name=appsink async=false sync=false", device, camera_format.width(), camera_format.height(), camera_format.frame_rate())
|
||||
}
|
||||
_ => {
|
||||
format!("unsupproted! if you see this, switch to something else!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,6 +616,9 @@ fn webcam_pipeline(device: &str, camera_format: CameraFormat) -> String {
|
||||
FrameFormat::YUYV => {
|
||||
format!("ksvideosrc device_index={} ! video/x-raw,format=YUY2,width={},height={},framerate={}/1 ! appsink name=appsink async=false sync=false", device, camera_format.width(), camera_format.height(), camera_format.frame_rate())
|
||||
}
|
||||
_ => {
|
||||
format!("unsupproted! if you see this, switch to something else!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -286,7 +286,7 @@ impl<'a> V4LCaptureDevice<'a> {
|
||||
let format = match fourcc {
|
||||
FrameFormat::MJPEG => FourCC::new(b"MJPG"),
|
||||
FrameFormat::YUYV => FourCC::new(b"YUYV"),
|
||||
FrameFormat::GRAY8 => FourCC::new("GRAY"),
|
||||
FrameFormat::GRAY8 => FourCC::new(b"GRAY"),
|
||||
};
|
||||
|
||||
match v4l::video::Capture::enum_framesizes(&self.device, format) {
|
||||
@@ -329,10 +329,19 @@ impl<'a> V4LCaptureDevice<'a> {
|
||||
pub fn force_refresh_camera_format(&mut self) -> Result<(), NokhwaError> {
|
||||
match (self.device.params(), self.device.format()) {
|
||||
(Ok(params), Ok(format)) => {
|
||||
let new_format = CameraFormat::new(params.capabilities.)
|
||||
// FIXME: actually handle the fractions??????
|
||||
self.camera_format = CameraFormat::new(
|
||||
Resolution::new(format.width, format.height),
|
||||
FrameFormat::from(format.fourcc),
|
||||
params.interval.numerator,
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
(_, _) => {
|
||||
return Err(NokhwaError::GetPropertyError { property: "parameters".to_string(), error: why.to_string() })
|
||||
return Err(NokhwaError::GetPropertyError {
|
||||
property: "parameters".to_string(),
|
||||
error: why.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+58
-10
@@ -17,35 +17,83 @@
|
||||
use crate::pixel_format::{PixelFormat, PixelFormats};
|
||||
use crate::{FrameFormat, NokhwaError, Resolution};
|
||||
use image::ImageBuffer;
|
||||
#[cfg(feature = "input-opencv")]
|
||||
use opencv::core::Mat;
|
||||
#[cfg(feature = "input-opencv")]
|
||||
use rgb::{FromSlice, RGB};
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Default, Hash, PartialOrd, PartialEq)]
|
||||
#[cfg_attr("serde", Serialize, Deserialize)]
|
||||
#[cfg_attr(feature = "serde", Serialize, Deserialize)]
|
||||
pub struct Buffer {
|
||||
resolution: Resolution,
|
||||
buffer: Vec<u8>,
|
||||
|
||||
source_frame_format: FrameFormat,
|
||||
}
|
||||
|
||||
impl Buffer {
|
||||
pub fn new(res: Resolution, buf: Vec<u8>) -> Self {
|
||||
pub fn new(res: Resolution, buf: Vec<u8>, source_frame_format: FrameFormat) -> Self {
|
||||
Self {
|
||||
resolution: res,
|
||||
buffer: buf,
|
||||
source_frame_format,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_image_with_custom_format<I>(self) -> Result<ImageBuffer<I::Output, Vec<u8>>, NokhwaError>
|
||||
|
||||
pub fn to_image_with_custom_format<F>(
|
||||
self,
|
||||
) -> Result<ImageBuffer<F::Output, Vec<u8>>, NokhwaError>
|
||||
where
|
||||
I: PixelFormat,
|
||||
F: PixelFormat,
|
||||
{
|
||||
if self.source_frame_format != F::CODE {
|
||||
return Err(NokhwaError::ProcessFrameError {
|
||||
src: self.source_frame_format,
|
||||
destination: F::CODE.to_string(),
|
||||
error: "Assertion failed, wrong source!".to_string(),
|
||||
});
|
||||
}
|
||||
ImageBuffer::from_raw(
|
||||
self.resolution.width_x,
|
||||
self.resolution.height_y,
|
||||
self.buffer,
|
||||
).ok_or(NokhwaError::ProcessFrameError {
|
||||
src: ,
|
||||
destination: "".to_string(),
|
||||
error: "".to_string()
|
||||
)
|
||||
.ok_or(NokhwaError::ProcessFrameError {
|
||||
src: F::CODE,
|
||||
destination: stringify!(I::Output).to_string(),
|
||||
error: "Buffer too small".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "input-opencv")]
|
||||
pub fn to_opencv_mat(self) -> Result<Mat, NokhwaError> {
|
||||
Ok(match self.source_frame_format {
|
||||
FrameFormat::MJPEG | FrameFormat::YUYV => Mat::from_slice_2d(
|
||||
self.buffer
|
||||
.as_rgb()
|
||||
.chunks(self.resolution.height_y as usize)
|
||||
.collect::<&[&[RGB<u8>]]>(),
|
||||
),
|
||||
FrameFormat::GRAY8 => Mat::from_slice_2d(
|
||||
self.buffer
|
||||
.chunks(self.resolution.height_y as usize)
|
||||
.collect::<&[&[u8]]>(),
|
||||
),
|
||||
}
|
||||
.map_err(|why| NokhwaError::ProcessFrameError {
|
||||
src: self.source_frame_format,
|
||||
destination: "OpenCV Mat".to_string(),
|
||||
error: why.to_string(),
|
||||
})?)
|
||||
}
|
||||
pub fn resolution(&self) -> Resolution {
|
||||
self.resolution
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
&self.buffer
|
||||
}
|
||||
pub fn source_frame_format(&self) -> FrameFormat {
|
||||
self.source_frame_format
|
||||
}
|
||||
}
|
||||
|
||||
+23
-10
@@ -14,14 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::buffer::Buffer;
|
||||
use crate::pixel_format::PixelFormat;
|
||||
use crate::{
|
||||
error::NokhwaError,
|
||||
utils::{CameraFormat, CameraInfo, FrameFormat, Resolution},
|
||||
CameraControl, CaptureAPIBackend, KnownCameraControls,
|
||||
};
|
||||
use image::{buffer::ConvertBuffer, ImageBuffer, Rgb, RgbaImage};
|
||||
|
||||
use crate::pixel_format::PixelFormat;
|
||||
use opencv::imgproc::FloodFillFlags;
|
||||
use std::{any::Any, borrow::Cow, collections::HashMap};
|
||||
#[cfg(feature = "output-wgpu")]
|
||||
use wgpu::{
|
||||
@@ -48,7 +49,7 @@ pub trait CaptureBackendTrait {
|
||||
fn camera_info(&self) -> &CameraInfo;
|
||||
|
||||
/// Gets the current [`CameraFormat`].
|
||||
fn camera_format(&self) -> CameraFormat;
|
||||
fn camera_format(&self) -> Result<CameraFormat, NokhwaError>;
|
||||
|
||||
/// Will set the current [`CameraFormat`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
@@ -70,7 +71,7 @@ pub trait CaptureBackendTrait {
|
||||
fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError>;
|
||||
|
||||
/// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]).
|
||||
fn resolution(&self) -> Resolution;
|
||||
fn resolution(&self) -> Result<Resolution, NokhwaError>;
|
||||
|
||||
/// Will set the current [`Resolution`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
@@ -79,7 +80,7 @@ pub trait CaptureBackendTrait {
|
||||
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError>;
|
||||
|
||||
/// Gets the current camera framerate (See: [`CameraFormat`]).
|
||||
fn frame_rate(&self) -> u32;
|
||||
fn frame_rate(&self) -> Result<u32, NokhwaError>;
|
||||
|
||||
/// Will set the current framerate
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
@@ -88,7 +89,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`]).
|
||||
fn frame_format(&self) -> FrameFormat;
|
||||
fn frame_format(&self) -> Result<FrameFormat, NokhwaError>;
|
||||
|
||||
/// Will set the current [`FrameFormat`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
@@ -155,7 +156,16 @@ pub trait CaptureBackendTrait {
|
||||
/// # 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.
|
||||
fn frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError>;
|
||||
fn frame(&mut self) -> Result<Buffer, NokhwaError>;
|
||||
|
||||
/// 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,
|
||||
/// or if the PixelFormat is invalid, this will error.
|
||||
fn frame_typed<F: PixelFormat>(
|
||||
&mut self,
|
||||
) -> Result<ImageBuffer<F::Output, Vec<u8>>, 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
|
||||
@@ -174,11 +184,14 @@ pub trait CaptureBackendTrait {
|
||||
/// Directly writes the current frame(RGB24) into said `buffer`. If `convert_rgba` is true, the buffer written will be written as an RGBA frame instead of a RGB frame. Returns the amount of bytes written on successful capture.
|
||||
/// # 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.
|
||||
fn write_frame_to_buffer(
|
||||
fn write_frame_to_buffer<F>(
|
||||
&mut self,
|
||||
buffer: &mut [u8],
|
||||
convert_rgba: bool,
|
||||
) -> Result<usize, NokhwaError> {
|
||||
write_alpha: bool,
|
||||
) -> Result<usize, NokhwaError>
|
||||
where
|
||||
F: PixelFormat,
|
||||
{
|
||||
let resolution = self.resolution();
|
||||
let frame = self.frame_raw()?;
|
||||
if convert_rgba {
|
||||
|
||||
+2
-32
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
use crate::buffer_output::{BufferOutput, GrayU8, RgbU8};
|
||||
use crate::FrameFormat;
|
||||
use image::{Luma, Pixel, Rgb};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
@@ -22,36 +23,5 @@ use std::hash::Hash;
|
||||
pub trait PixelFormat: Copy + Clone + Debug + Default + Hash + Send + Sync {
|
||||
type Output: Pixel;
|
||||
|
||||
const CODE: &'static str;
|
||||
|
||||
fn code(&self) -> &'static str {
|
||||
CODE
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Hash)]
|
||||
pub struct Mjpeg;
|
||||
|
||||
impl PixelFormat for Mjpeg {
|
||||
type Output = Rgb<u8>;
|
||||
|
||||
const CODE: &'static str = "MJPG";
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Hash)]
|
||||
pub struct Yuyv;
|
||||
|
||||
impl PixelFormat for Yuyv {
|
||||
type Output = Rgb<u8>;
|
||||
|
||||
const CODE: &'static str = "YUYV";
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Hash)]
|
||||
pub struct Gray;
|
||||
|
||||
impl PixelFormat for Gray {
|
||||
type Output = Luma<u8>;
|
||||
|
||||
const CODE: &'static str = "GRAY";
|
||||
const SUPPORTED_CODES: &'static [FrameFormat];
|
||||
}
|
||||
|
||||
+34
-19
@@ -14,15 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::pixel_format::PixelFormat;
|
||||
use crate::NokhwaError;
|
||||
use std::{
|
||||
borrow::{Borrow, Cow},
|
||||
cmp::Ordering,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
#[cfg(feature = "output-wasm")]
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
#[cfg(any(
|
||||
all(
|
||||
feature = "input-avfoundation",
|
||||
@@ -45,11 +38,20 @@ use nokhwa_bindings_windows::{
|
||||
MFCameraFormat, MFControl, MFFrameFormat, MFResolution, MediaFoundationControls,
|
||||
MediaFoundationDeviceDescriptor,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = serde)]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
borrow::{Borrow, Cow},
|
||||
cmp::Ordering,
|
||||
fmt::{Display, Formatter},
|
||||
};
|
||||
#[cfg(feature = "input-uvc")]
|
||||
use uvc::StreamFormat;
|
||||
#[cfg(all(feature = "input-v4l", target_os = "linux"))]
|
||||
use v4l::{control::Description, Format, FourCC};
|
||||
use crate::pixel_format::PixelFormat;
|
||||
#[cfg(feature = "output-wasm")]
|
||||
use wasm_bindgen::prelude::wasm_bindgen;
|
||||
|
||||
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC`.
|
||||
/// - YUYV is a mathematical color space. You can read more [here.](https://en.wikipedia.org/wiki/YCbCr)
|
||||
@@ -57,6 +59,7 @@ use crate::pixel_format::PixelFormat;
|
||||
/// # JS-WASM
|
||||
/// This is exported as `FrameFormat`
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum FrameFormat {
|
||||
MJPEG,
|
||||
YUYV,
|
||||
@@ -64,7 +67,7 @@ pub enum FrameFormat {
|
||||
}
|
||||
|
||||
impl Display for FrameFormat {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FrameFormat::MJPEG => {
|
||||
write!(f, "MJPEG")
|
||||
@@ -79,9 +82,12 @@ impl Display for FrameFormat {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> From<P> for FrameFormat where P: PixelFormat {
|
||||
fn from(px: P) -> Self {
|
||||
match P::
|
||||
impl<P> From<P> for FrameFormat
|
||||
where
|
||||
P: PixelFormat,
|
||||
{
|
||||
fn from(_: P) -> Self {
|
||||
P::CODE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +177,7 @@ impl From<FrameFormat> for AVFourCC {
|
||||
/// # JS-WASM
|
||||
/// This is exported as `JSResolution`
|
||||
#[cfg_attr(feature = "output-wasm", wasm_bindgen(js_name = JSResolution))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
|
||||
pub struct Resolution {
|
||||
pub width_x: u32,
|
||||
@@ -225,7 +232,7 @@ impl Resolution {
|
||||
}
|
||||
|
||||
impl Display for Resolution {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}x{}", self.x(), self.y())
|
||||
}
|
||||
}
|
||||
@@ -296,6 +303,7 @@ impl From<AVVideoResolution> for Resolution {
|
||||
/// This is a convenience struct that holds all information about the format of a webcam stream.
|
||||
/// It consists of a [`Resolution`], [`FrameFormat`], and a frame rate(u8).
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct CameraFormat {
|
||||
resolution: Resolution,
|
||||
format: FrameFormat,
|
||||
@@ -474,6 +482,7 @@ impl From<CameraFormat> for CaptureDeviceFormatDescriptor {
|
||||
/// This is exported as a `JSCameraInfo`.
|
||||
#[cfg_attr(feature = "output-wasm", wasm_bindgen(js_name = JSCameraInfo))]
|
||||
#[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct CameraInfo {
|
||||
human_name: String,
|
||||
description: String,
|
||||
@@ -488,10 +497,13 @@ impl CameraInfo {
|
||||
/// This is exported as a constructor for [`CameraInfo`].
|
||||
#[must_use]
|
||||
#[cfg_attr(feature = "output-wasm", wasm_bindgen(constructor))]
|
||||
// OK, i just checkeed back on this code. WTF was I on when I wrote `&(impl AsRef<str> + ?Sized)` ????
|
||||
// I need to get on the same shit that my previous self was on, because holy shit that stuff is strong as FUCK!
|
||||
// Finally fixed this insanity. Hopefully I didnt torment anyone by actually putting this in a stable release.
|
||||
pub fn new(
|
||||
human_name: &(impl AsRef<str> + ?Sized),
|
||||
description: &(impl AsRef<str> + ?Sized),
|
||||
misc: &(impl AsRef<str> + ?Sized),
|
||||
human_name: impl AsRef<str>,
|
||||
description: impl AsRef<str>,
|
||||
misc: impl AsRef<str>,
|
||||
index: CameraIndex,
|
||||
) -> Self {
|
||||
CameraInfo {
|
||||
@@ -648,6 +660,7 @@ impl From<AVCaptureDeviceDescriptor> for CameraInfo {
|
||||
/// These can control the picture brightness, etc. <br>
|
||||
/// Note that not all backends/devices support all these. Run [`supported_camera_controls()`](crate::CaptureBackendTrait::supported_camera_controls) to see which ones can be set.
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum KnownCameraControls {
|
||||
Brightness,
|
||||
Contrast,
|
||||
@@ -737,7 +750,7 @@ impl From<MFControl> for KnownCameraControls {
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "input-v4l", target_os = "linux"))]
|
||||
impl std::convert::TryFrom<Description> for KnownCameraControls {
|
||||
impl TryFrom<Description> for KnownCameraControls {
|
||||
type Error = NokhwaError;
|
||||
|
||||
fn try_from(value: Description) -> Result<Self, Self::Error> {
|
||||
@@ -786,6 +799,7 @@ impl Display for KnownCameraControlFlag {
|
||||
/// NOTE: Assume the values for `min` and `max` as **non-inclusive**!.
|
||||
/// E.g. if the [`CameraControl`] says `min` is 100, the minimum is actually 101.
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct CameraControl {
|
||||
control: KnownCameraControls,
|
||||
min: i32,
|
||||
@@ -1019,6 +1033,7 @@ impl Ord for CameraControl {
|
||||
/// - `Network` - Uses `OpenCV` to capture from an IP.
|
||||
/// - `Browser` - Uses browser APIs to capture from a webcam.
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum CaptureAPIBackend {
|
||||
Auto,
|
||||
AVFoundation,
|
||||
@@ -1032,7 +1047,7 @@ pub enum CaptureAPIBackend {
|
||||
}
|
||||
|
||||
impl Display for CaptureAPIBackend {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let self_str = format!("{:?}", self);
|
||||
write!(f, "{}", self_str)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user