mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
start impl v4l2 capture backend
This commit is contained in:
@@ -16,6 +16,8 @@ input_opencv = ["opencv", "opencv/clang-runtime"]
|
||||
input_msmf = ["windows"]
|
||||
input_v4l = ["v4l"]
|
||||
input_gstreamer = ["gstreamer"]
|
||||
input_ffmpeg = []
|
||||
docs-only = ["input_uvc", "input_opencv", "input_msmf", "input_v4l", "input_gstreamer", "input_ffmpeg"]
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.24"
|
||||
@@ -44,3 +46,7 @@ optional = true
|
||||
|
||||
[dev-dependencies.windows]
|
||||
version = "0.10.0"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
no-default-features = true
|
||||
features = ["docs-only"]
|
||||
+204
-11
@@ -1,30 +1,62 @@
|
||||
use crate::{error::NokhwaError, utils::{CameraFormat, CameraInfo}};
|
||||
use crate::{
|
||||
error::NokhwaError,
|
||||
utils::{CameraFormat, CameraInfo},
|
||||
CaptureBackendTrait, FrameFormat, Resolution,
|
||||
};
|
||||
use v4l::prelude::*;
|
||||
use v4l::{
|
||||
buffer::Type,
|
||||
io::traits::CaptureStream,
|
||||
video::{capture::Parameters, Capture},
|
||||
Format, FourCC,
|
||||
};
|
||||
|
||||
pub struct V4LCaptureDevice {
|
||||
#[cfg(feature = "input_v4l")]
|
||||
impl From<CameraFormat> for Format {
|
||||
fn from(cam_fmt: CameraFormat) -> Self {
|
||||
let pxfmt = match cam_fmt.format() {
|
||||
FrameFormat::MJPEG => FourCC::new(b"MJPG"),
|
||||
FrameFormat::YUYV => FourCC::new(b"YUYV"),
|
||||
};
|
||||
|
||||
Format::new(cam_fmt.width(), cam_fmt.height(), pxfmt)
|
||||
}
|
||||
}
|
||||
|
||||
/// The backend struct that interfaces with V4L2.
|
||||
/// To see what this does, please see [`CaptureBackendTrait`]
|
||||
/// # Quirks
|
||||
/// Calling [`set_resolution()`](CaptureBackendTrait::set_resolution), [`set_framerate()`](CaptureBackendTrait::set_framerate), or [`set_frameformat()`](CaptureBackendTrait::set_frameformat)
|
||||
/// each internally calls [`set_camera_format()`](CaptureBackendTrait::set_camera_format).
|
||||
pub struct V4LCaptureDevice<'a> {
|
||||
camera_format: Option<CameraFormat>,
|
||||
camera_info: CameraInfo,
|
||||
device: Device,
|
||||
stream_handle: Option<MmapStream<'a>>,
|
||||
}
|
||||
|
||||
impl V4LCaptureDevice {
|
||||
/// Creates a new capture device using the V4L2 backend
|
||||
impl<'a> V4LCaptureDevice<'a> {
|
||||
/// Creates a new capture device using the V4L2 backend. Indexes are gives to devices by the OS, and usually numbered by order of discovery.
|
||||
/// # Errors
|
||||
/// This function will error if the camera is currently busy or if V4L2 can't read device information.
|
||||
/// This function will error if the camera is currently busy or if V4L2 can't read device information.
|
||||
pub fn new(index: usize) -> Result<Self, NokhwaError> {
|
||||
let device = match Device::new(index) {
|
||||
Ok(dev) => dev,
|
||||
Err(why) => {
|
||||
return Err(NokhwaError::CouldntOpenDevice(format!("V4L2 Error: {}", why.to_string())))
|
||||
return Err(NokhwaError::CouldntOpenDevice(format!(
|
||||
"V4L2 Error: {}",
|
||||
why.to_string()
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let camera_info = match device.query_caps() {
|
||||
Ok(caps) => {
|
||||
CameraInfo::new(caps.card, "".to_string(), caps.driver, index)
|
||||
}
|
||||
Ok(caps) => CameraInfo::new(caps.card, "".to_string(), caps.driver, index),
|
||||
Err(why) => {
|
||||
return Err(NokhwaError::CouldntQueryDevice{ property: "Capabilities".to_string(), error: why.to_string() })
|
||||
return Err(NokhwaError::CouldntQueryDevice {
|
||||
property: "Capabilities".to_string(),
|
||||
error: why.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,7 +64,168 @@ impl V4LCaptureDevice {
|
||||
camera_format: None,
|
||||
camera_info,
|
||||
device,
|
||||
stream_handle: None,
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> {
|
||||
fn get_info(&self) -> CameraInfo {
|
||||
self.camera_info.clone()
|
||||
}
|
||||
|
||||
fn get_camera_format(&self) -> Option<CameraFormat> {
|
||||
self.camera_format
|
||||
}
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
fn init_camera_format_default(&mut self, overwrite: bool) -> Result<(), NokhwaError> {
|
||||
match self.camera_format {
|
||||
Some(_) => {
|
||||
if overwrite {
|
||||
return self.set_camera_format(CameraFormat::default());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
None => self.set_camera_format(CameraFormat::default()),
|
||||
}
|
||||
}
|
||||
|
||||
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
||||
let prev_format = match self.device.format() {
|
||||
Ok(fmt) => fmt,
|
||||
Err(why) => {
|
||||
return Err(NokhwaError::CouldntQueryDevice {
|
||||
property: "Resolution, FrameFormat".to_string(),
|
||||
error: why.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
let prev_fps = match self.device.params() {
|
||||
Ok(fps) => fps,
|
||||
Err(why) => {
|
||||
return Err(NokhwaError::CouldntQueryDevice {
|
||||
property: "Framerate".to_string(),
|
||||
error: why.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let format: Format = new_fmt.into();
|
||||
let framerate = Parameters::with_fps(new_fmt.framerate());
|
||||
|
||||
if let Err(why) = self.device.set_format(&format) {
|
||||
return Err(NokhwaError::CouldntSetProperty {
|
||||
property: "Resolution, FrameFormat".to_string(),
|
||||
value: format.to_string(),
|
||||
error: why.to_string(),
|
||||
});
|
||||
}
|
||||
if let Err(why) = self.device.set_params(&framerate) {
|
||||
return Err(NokhwaError::CouldntSetProperty {
|
||||
property: "Framerate".to_string(),
|
||||
value: framerate.to_string(),
|
||||
error: why.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
if self.stream_handle.is_some() {
|
||||
self.stream_handle = Some({
|
||||
match MmapStream::new(&self.device, Type::VideoCapture) {
|
||||
Ok(stream) => stream,
|
||||
Err(why) => {
|
||||
// undo
|
||||
if let Err(why) = self.device.set_format(&prev_format) {
|
||||
return Err(NokhwaError::CouldntSetProperty {
|
||||
property: "Attempt undo due to stream acquisition failure. Resolution, FrameFormat".to_string(),
|
||||
value: prev_format.to_string(),
|
||||
error: why.to_string(),
|
||||
});
|
||||
}
|
||||
if let Err(why) = self.device.set_params(&prev_fps) {
|
||||
return Err(NokhwaError::CouldntSetProperty {
|
||||
property:
|
||||
"Attempt undo due to stream acquisition failure. Framerate"
|
||||
.to_string(),
|
||||
value: prev_fps.to_string(),
|
||||
error: why.to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
return Err(NokhwaError::CouldntOpenStream(why.to_string()));
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
self.camera_format = Some(new_fmt);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_resolution(&self) -> Option<Resolution> {
|
||||
self.camera_format.map(|fmt| fmt.resoltuion())
|
||||
}
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
|
||||
if let Some(fmt) = self.camera_format {
|
||||
let mut new_fmt = fmt;
|
||||
new_fmt.set_resolution(new_res);
|
||||
self.set_camera_format(new_fmt)
|
||||
} else {
|
||||
self.camera_format = Some(CameraFormat::new(new_res, FrameFormat::MJPEG, 0));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_framerate(&self) -> Option<u32> {
|
||||
self.camera_format.map(|fmt| fmt.framerate())
|
||||
}
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
fn set_framerate(&mut self, new_fps: u32) -> Result<(), NokhwaError> {
|
||||
if let Some(fmt) = self.camera_format {
|
||||
let mut new_fmt = fmt;
|
||||
new_fmt.set_framerate(new_fps);
|
||||
self.set_camera_format(new_fmt)
|
||||
} else {
|
||||
self.camera_format = Some(CameraFormat::new(
|
||||
Resolution::new(0, 0),
|
||||
FrameFormat::MJPEG,
|
||||
new_fps,
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_frameformat(&self) -> Option<FrameFormat> {
|
||||
self.camera_format.map(|fmt| fmt.format())
|
||||
}
|
||||
|
||||
#[allow(clippy::option_if_let_else)]
|
||||
fn set_frameformat(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
|
||||
if let Some(fmt) = self.camera_format {
|
||||
let mut new_fmt = fmt;
|
||||
new_fmt.set_format(fourcc);
|
||||
self.set_camera_format(new_fmt)
|
||||
} else {
|
||||
self.camera_format = Some(CameraFormat::new(Resolution::new(0, 0), fourcc, 0));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_stream_open(&self) -> bool {
|
||||
self.stream_handle.is_some()
|
||||
}
|
||||
|
||||
fn get_frame(&self) -> Result<image::ImageBuffer<image::Rgb<u8>, Vec<u8>>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frame_raw(&self) -> Vec<u8> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
pub struct Capture {
|
||||
|
||||
}
|
||||
pub struct Capture {}
|
||||
|
||||
+67
-4
@@ -1,12 +1,75 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use image::{ImageBuffer, Rgb};
|
||||
|
||||
use crate::{error::NokhwaError, utils::{CameraFormat, CameraInfo}};
|
||||
use crate::{
|
||||
error::NokhwaError,
|
||||
utils::{CameraFormat, CameraInfo, FrameFormat, Resolution},
|
||||
};
|
||||
|
||||
/// This trait is for any backend that allows you to grab and take frames from a camera.
|
||||
pub trait CaptureBackendTrait {
|
||||
fn info(&self) -> CameraInfo;
|
||||
fn set_camera_format(&self, new_fmt: CameraFormat) -> Result<(), NokhwaError>;
|
||||
fn open_stream(&self) -> Result<(), NokhwaError>;
|
||||
/// Gets the camera information such as Name and Index as a [`CameraInfo`].
|
||||
fn get_info(&self) -> CameraInfo;
|
||||
/// Assigns a sensible default to the backend's `CameraFormat`. Usually 640x480 @ 15 FPS + MJPEG.
|
||||
/// If there is already a value assigned to the `CameraFormat`, it will only be overwritten if `overwrite` is set to `true`.
|
||||
/// If false, this function will do nothing (NO-OP).
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
/// # Errors
|
||||
/// If you started the stream and the camera rejects the new camera format, this will return an error.
|
||||
fn init_camera_format_default(&mut self, overwrite: bool) -> Result<(), NokhwaError>;
|
||||
/// Gets the current [`CameraFormat`]. Will return none if no format has been set yet.
|
||||
fn get_camera_format(&self) -> Option<CameraFormat>;
|
||||
/// Will set the current [`CameraFormat`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
/// # Errors
|
||||
/// If you started the stream and the camera rejects the new camera format, this will return an error.
|
||||
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError>;
|
||||
/// Gets the current camera resolution (See: [`Resolution`]). Will return none if no resolution has been set yet.
|
||||
fn get_resolution(&self) -> Option<Resolution>;
|
||||
/// Will set the current [`Resolution`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
/// # Errors
|
||||
/// If you started the stream and the camera rejects the new resolution, this will return an error.
|
||||
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError>;
|
||||
/// Gets the current camera framerate. Will return none if no framerate has been set yet.
|
||||
fn get_framerate(&self) -> Option<u32>;
|
||||
/// Will set the current framerate
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
/// # Errors
|
||||
/// If you started the stream and the camera rejects the new framerate, this will return an error.
|
||||
fn set_framerate(&mut self, new_fps: u32) -> Result<(), NokhwaError>;
|
||||
/// Gets the current camera's frame format (See: [`FrameFormat`]). Will return none if no frame format has been set yet.
|
||||
fn get_frameformat(&self) -> Option<FrameFormat>;
|
||||
/// Will set the current [`FrameFormat`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
/// # Errors
|
||||
/// If you started the stream and the camera rejects the new frame foramt, this will return an error.
|
||||
fn set_frameformat(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError>;
|
||||
/// Will open the camera stream with set parameters. This will be called internally if you try and call [`CaptureBackendTrait::get_frame()`] before you call [`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.
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError>;
|
||||
/// 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 Raw RGB image buffer. This will call [`CaptureBackendTrait::open_stream()`] first if you haven't already.
|
||||
/// # Errors
|
||||
/// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore) or the decoding fails (e.g. MJPEG -> u8), this will error.
|
||||
fn get_frame(&self) -> Result<ImageBuffer<Rgb<u8>, 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
|
||||
/// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), this will error.
|
||||
fn get_frame_raw(&self) -> Vec<u8>;
|
||||
}
|
||||
|
||||
/// This is for any backend that allows you to query a camera for its compatible resolutions/fourcc/framerates.
|
||||
pub trait QueryBackendTrait: CaptureBackendTrait {
|
||||
/// A hashmap of Framerates mapped to [`Resolution`]s.
|
||||
fn get_compatible_by_framerate(&self, fourcc: FrameFormat) -> HashMap<u32, Vec<Resolution>>;
|
||||
/// A hashmap of [`Resolution`]s mapped to framerates
|
||||
fn get_compatible_by_resolution(&self, fourcc: FrameFormat) -> HashMap<Resolution, Vec<u32>>;
|
||||
/// Gets the supported camera formats.
|
||||
fn get_compatible_fourcc(&self, resolution: Resolution, framerate: u32) -> Option<FrameFormat>;
|
||||
}
|
||||
|
||||
pub trait VirtualBackendTrait {}
|
||||
|
||||
+10
-4
@@ -1,13 +1,19 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[allow(clippy::clippy::module_name_repetitions)]
|
||||
#[allow(clippy::module_name_repetitions)]
|
||||
#[allow(clippy::pub_enum_variant_names)]
|
||||
#[derive(Error, Debug, Clone)]
|
||||
pub enum NokhwaError {
|
||||
#[error("Could not open device: {0}")]
|
||||
CouldntOpenDevice(String),
|
||||
#[error("Could not query device property {property}: {error}")]
|
||||
CouldntQueryDevice {
|
||||
CouldntQueryDevice { property: String, error: String },
|
||||
#[error("Could not set device property {property} with value {value}: {error}")]
|
||||
CouldntSetProperty {
|
||||
property: String,
|
||||
value: String,
|
||||
error: String,
|
||||
}
|
||||
}
|
||||
},
|
||||
#[error("Could not open device stream: {0}")]
|
||||
CouldntOpenStream(String),
|
||||
}
|
||||
|
||||
+8
-3
@@ -1,10 +1,15 @@
|
||||
#![deny(clippy::pedantic)]
|
||||
#![warn(clippy::all)]
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![allow(clippy::must_use_candidate)]
|
||||
|
||||
mod camera_traits;
|
||||
pub mod backends;
|
||||
mod utils;
|
||||
mod camera;
|
||||
mod camera_traits;
|
||||
mod error;
|
||||
mod query;
|
||||
mod query;
|
||||
mod utils;
|
||||
|
||||
pub use camera_traits::*;
|
||||
pub use error::NokhwaError;
|
||||
pub use utils::*;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
+62
-9
@@ -1,14 +1,19 @@
|
||||
use std::fmt::Display;
|
||||
use std::cmp::Ordering;
|
||||
use std::{cmp::Ordering, fmt::Display};
|
||||
|
||||
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC`
|
||||
|
||||
/// YUYV is a mathmatical color space. You can read more [here.](https://en.wikipedia.org/wiki/YCbCr)
|
||||
|
||||
/// MJPEG is a motion-jpeg compressed frame, it allows for high frame rates.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Hash)]
|
||||
pub enum FrameFormat {
|
||||
MJPEG,
|
||||
YUYV,
|
||||
}
|
||||
|
||||
/// Describes a Resolution.
|
||||
/// Describes a Resolution.
|
||||
/// This struct consists of a Width and a Height value (x,y).
|
||||
/// Note that the [`Ord`] implementation of this struct is flipped from highest to lowest.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct Resolution {
|
||||
pub width_x: u32,
|
||||
@@ -58,8 +63,6 @@ impl PartialOrd for Resolution {
|
||||
}
|
||||
|
||||
impl Ord for Resolution {
|
||||
// Flip around the order to make it seem the way the user would expect.
|
||||
// The user would expect a descending list of resolutions (aka highest -> lowest)
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
match self.x().cmp(&other.x()) {
|
||||
Ordering::Less => Ordering::Less,
|
||||
@@ -69,6 +72,8 @@ impl Ord for Resolution {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is a conveinence struct that holds all information about the format of a webcam stream.
|
||||
/// It consists of a Resolution, `FrameFormat`, and a framerate.
|
||||
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
|
||||
pub struct CameraFormat {
|
||||
resolution: Resolution,
|
||||
@@ -77,6 +82,7 @@ pub struct CameraFormat {
|
||||
}
|
||||
|
||||
impl CameraFormat {
|
||||
/// Construct a new [`CameraFormat`]
|
||||
pub fn new(resolution: Resolution, format: FrameFormat, framerate: u32) -> Self {
|
||||
CameraFormat {
|
||||
resolution,
|
||||
@@ -85,6 +91,7 @@ impl CameraFormat {
|
||||
}
|
||||
}
|
||||
|
||||
/// [`CameraFormat::new()`], but raw.
|
||||
pub fn new_from(res_x: u32, res_y: u32, format: FrameFormat, fps: u32) -> Self {
|
||||
CameraFormat {
|
||||
resolution: Resolution {
|
||||
@@ -96,27 +103,60 @@ impl CameraFormat {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn res(&self) -> Resolution {
|
||||
/// Get the resolution of the current [`CameraFormat`]
|
||||
pub fn resoltuion(&self) -> Resolution {
|
||||
self.resolution
|
||||
}
|
||||
|
||||
/// Get the width of the resolution of the current [`CameraFormat`]
|
||||
pub fn width(&self) -> u32 {
|
||||
self.resolution.width()
|
||||
}
|
||||
|
||||
/// Get the height of the resolution of the current [`CameraFormat`]
|
||||
pub fn height(&self) -> u32 {
|
||||
self.resolution.height()
|
||||
}
|
||||
|
||||
pub fn frame_format(&self) -> FrameFormat {
|
||||
self.format
|
||||
/// Set the [`CameraFormat`]'s resolution.
|
||||
pub fn set_resolution(&mut self, resolution: Resolution) {
|
||||
self.resolution = resolution;
|
||||
}
|
||||
|
||||
/// Get the framerate of the current [`CameraFormat`]
|
||||
pub fn framerate(&self) -> u32 {
|
||||
self.framerate
|
||||
}
|
||||
|
||||
/// Set the [`CameraFormat`]'s framerate.
|
||||
pub fn set_framerate(&mut self, framerate: u32) {
|
||||
self.framerate = framerate;
|
||||
}
|
||||
|
||||
/// Get the [`CameraFormat`]'s format.
|
||||
pub fn format(&self) -> FrameFormat {
|
||||
self.format
|
||||
}
|
||||
|
||||
/// Set the [`CameraFormat`]'s format.
|
||||
pub fn set_format(&mut self, format: FrameFormat) {
|
||||
self.format = format;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CameraFormat {
|
||||
fn default() -> Self {
|
||||
CameraFormat {
|
||||
resolution: Resolution::new(640, 480),
|
||||
format: FrameFormat::MJPEG,
|
||||
framerate: 15,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about a Camera e.g. its name.
|
||||
/// `description` amd `misc` may contain backend-specific information.
|
||||
/// `index` is a camera's index given to it by (usually) the OS usually in the order it is known to the system.
|
||||
#[derive(Clone, Debug, Default, Hash, PartialEq, Eq)]
|
||||
pub struct CameraInfo {
|
||||
human_name: String,
|
||||
@@ -126,13 +166,13 @@ pub struct CameraInfo {
|
||||
}
|
||||
|
||||
impl CameraInfo {
|
||||
/// Create a new [`CameraInfo`].
|
||||
pub fn new(human_name: String, description: String, misc: String, index: usize) -> Self {
|
||||
CameraInfo {
|
||||
human_name,
|
||||
description,
|
||||
misc,
|
||||
index,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +229,19 @@ impl Ord for CameraInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// The list of known capture backends to the library.
|
||||
///
|
||||
/// AUTO is special - it tells the Camera struct to automatically choose a backend most suited for the current platform.
|
||||
///
|
||||
/// V4L2 - `Video4Linux2`, a linux specific backend.
|
||||
///
|
||||
/// UVC - Universal Video Class (please check [libuvc](https://github.com/libuvc/libuvc)). Platform agnostic, although on linux it needs `sudo` permissions or similar to use.
|
||||
///
|
||||
/// MSMF - Microsoft Media Foundation, Winsows only (replacement for `DirectShow`)
|
||||
///
|
||||
/// `OpenCV` - Uses `OpenCV` to capture. Platform agnostic.
|
||||
///
|
||||
/// FFMPEG - Uses FFMPEG (libavdevice) to capture. Platform agnostic.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum CaptureAPIBackend {
|
||||
AUTO,
|
||||
|
||||
Reference in New Issue
Block a user