mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
fix some bugs, complete capture example
This commit is contained in:
@@ -20,17 +20,7 @@ Most likely, you will only use functionality provided by the `Camera` struct. If
|
||||
|
||||
```rust
|
||||
// set up the Camera
|
||||
let mut camera = Camera::new(
|
||||
0, // index
|
||||
Some(CameraFormat::new_from(640, 480, FrameFormat::MJPEG, 30)), // format
|
||||
)
|
||||
.unwrap();
|
||||
// open stream
|
||||
camera.open_stream().unwrap();
|
||||
loop {
|
||||
let frame = camera.frame().unwrap();
|
||||
println!("{}, {}", frame.width(), frame.height());
|
||||
}
|
||||
|
||||
```
|
||||
A command line app made with `nokhwa` can be found in the `examples` folder.
|
||||
|
||||
@@ -42,20 +32,19 @@ The table below lists current Nokhwa API support.
|
||||
- The `Query-Device` column signifies reading device capabilities
|
||||
- The `Platform` column signifies what Platform this is availible on.
|
||||
|
||||
| Backend | Input | Query | Query-Device | Platform |
|
||||
|----------------------------------------|--------------------|-------------------|--------------------|---------------------|
|
||||
| Video4Linux(`input-v4l`) | ✅ | ✅ | ✅ | Linux |
|
||||
| MSMF(`input-msmf`) | ✅ | ✅ | ✅ | Windows |
|
||||
| AVFoundation(`input-avfoundation`)^^ | ✅ | ✅ | ✅ | Mac |
|
||||
| libuvc(`input-uvc`) (**DEPRECATED**)^^^| ❌ | ✅ | ❌ | Linux, Windows, Mac |
|
||||
| Backend | Input | Query | Query-Device | Platform |
|
||||
-----------------------------------------|----------------------------------------|--------------------|-------------------|--------------------|---------------------|
|
||||
| Video4Linux(`input-v4l`) | ✅ | ✅ | ✅ | Linux |
|
||||
| MSMF(`input-msmf`) | ✅ | ✅ | ✅ | Windows |
|
||||
| AVFoundation(`input-avfoundation`)^^ | ✅ | ✅ | ✅ | Mac |
|
||||
| libuvc(`input-uvc`) (**DEPRECATED**)^^^ | ❌ | ✅ | ❌ | Linux, Windows, Mac |
|
||||
| OpenCV(`input-opencv`)^ | ✅ | ❌ | ❌ | Linux, Windows, Mac |
|
||||
| IPCamera(`input-ipcam`/OpenCV)^ | ✅ | ❌ | ❌ | Linux, Windows, Mac |
|
||||
| GStreamer(`input-gst`)(**DEPRECATED**) | ✅ | ✅ | ✅ | Linux, Windows, Mac |
|
||||
| JS/WASM(`input-wasm`) | ✅ | ✅ | ✅ | Browser(Web) |
|
||||
| GStreamer(`input-gst`)(**DEPRECATED**) | ✅ | ✅ | ✅ | Linux, Windows, Mac |
|
||||
| JS/WASM(`input-wasm`) | ✅ | ✅ | ✅ | Browser(Web) |
|
||||
|
||||
✅: Working, 🔮 : Experimental, ❌ : Not Supported, 🚧: Planned/WIP
|
||||
|
||||
^ = No CameraFormat setting support.
|
||||
^ = May be bugged. Also supports IP Cameras.
|
||||
|
||||
^^ = No FPS setting support.
|
||||
|
||||
|
||||
+13
-12
@@ -1,23 +1,24 @@
|
||||
[package]
|
||||
name = "capture"
|
||||
version = "0.1.0"
|
||||
authors = ["l1npengtul <l1npengtul@protonmail.com>"]
|
||||
name = "nokhwactl"
|
||||
version = "0.10.0"
|
||||
authors = ["l1npengtul <l1npengtul@protonmail.com>", "The Nokhwa Contributors"]
|
||||
edition = "2018"
|
||||
|
||||
about = "An example CLI program to show off Nokhwa's capabilities."
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
default = ["nokhwa/default"]
|
||||
input-msmf = ["nokhwa/input-msmf"]
|
||||
input-v4l = ["nokhwa/input-v4l"]
|
||||
input-opencv = ["nokhwa/input-opencv"]
|
||||
input-avfoundation = ["nokhwa/input-avfoundation"]
|
||||
native = ["nokhwa/input-native"]
|
||||
|
||||
[dependencies]
|
||||
clap = "4.0.19"
|
||||
glium = "0.32.1"
|
||||
glutin = "0.30.0"
|
||||
flume = "0.10.9"
|
||||
ggez = "0.8.1"
|
||||
flume = "0.10.14"
|
||||
once_cell = "1.16.0"
|
||||
image = "0.24.4"
|
||||
|
||||
[dependencies.clap]
|
||||
version = "4.0.20"
|
||||
features = ["derive"]
|
||||
|
||||
# Use these as you need
|
||||
[dependencies.nokhwa]
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copywight © :3 2021 w1npengtuw, the x3 Nyokhwa Contwibutews. Wicensed undew the x3 MPL-2.0. *looks at you* You shouwd have weceived a copy with this softwawe, but if nyot i-it c-can be found at You c-can obtain onye at https://mozilla.org/MPL/2.0/. *huggles tightly*</string>
|
||||
<string>Copywight © :3 2022 w1npengtuw, the x3 Nyokhwa Contwibutews. Wicensed undew the x3 APL-2.0. *looks at you* You shouwd have weceived a copy with this softwawe, but if nyot i-it c-can be found at You c-can obtain onye at https://www.apache.org/licenses/LICENSE-2.0.html. *huggles tightly*</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>we *notices buldge* wiww s-s-steaw aww youw webcam and pewsonyaw infowmation undew the x3 guise of b-being a "nyokhwa exampwe c-captuwe app" and a "devewopew toow" <3 :3 *nyuzzwes yuwu*</string>
|
||||
<key>NSMainNibFile</key>
|
||||
|
||||
@@ -16,4 +16,339 @@
|
||||
|
||||
// Some assembly required. For developers 7 and up.
|
||||
|
||||
fn main() {}
|
||||
use clap::{Parser, Subcommand};
|
||||
use flume::{Receiver, Sender};
|
||||
use ggez::{
|
||||
event::{run, EventHandler},
|
||||
graphics::{Canvas, Image},
|
||||
Context, ContextBuilder, GameError,
|
||||
};
|
||||
use nokhwa::{
|
||||
native_api_backend,
|
||||
pixel_format::RgbFormat,
|
||||
query,
|
||||
utils::{
|
||||
frame_formats, CameraFormat, CameraIndex, FrameFormat, RequestedFormat,
|
||||
RequestedFormatType, Resolution,
|
||||
},
|
||||
Buffer, CallbackCamera, Camera,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
struct CaptureState {
|
||||
sender: Arc<Sender<Buffer>>,
|
||||
receiver: Arc<Receiver<Buffer>>,
|
||||
buffer: Vec<u8>,
|
||||
camera: CallbackCamera,
|
||||
}
|
||||
|
||||
impl EventHandler<GameError> for CaptureState {
|
||||
fn update(&mut self, _ctx: &mut Context) -> Result<(), GameError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw(&mut self, ctx: &mut Context) -> Result<(), GameError> {
|
||||
self.receiver
|
||||
.recv()
|
||||
.map_err(|why| GameError::RenderError(why.to_string()))?
|
||||
.decode_image_to_buffer(&mut self.buffer)?;
|
||||
let image = Image::from_bytes(ctx, &self.buffer)?;
|
||||
let canvas = Canvas::from_image(ctx, image, None);
|
||||
canvas.finish(ctx)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
command: Option<Commands>,
|
||||
}
|
||||
|
||||
enum IndexKind {
|
||||
String(String),
|
||||
Index(u32),
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
ListDevices,
|
||||
ListProperties {
|
||||
device: Option<IndexKind>,
|
||||
kind: PropertyKind,
|
||||
},
|
||||
Stream {
|
||||
device: Option<IndexKind>,
|
||||
display: bool,
|
||||
requested: Option<RequestedCliFormat>,
|
||||
},
|
||||
Single {
|
||||
device: Option<IndexKind>,
|
||||
save: Option<String>,
|
||||
requested: Option<RequestedCliFormat>,
|
||||
},
|
||||
}
|
||||
|
||||
struct RequestedCliFormat {
|
||||
format_type: String,
|
||||
format_option: Option<String>,
|
||||
}
|
||||
|
||||
enum PropertyKind {
|
||||
All,
|
||||
Controls,
|
||||
CompatibleFormats,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
nokhwa::nokhwa_initialize(|_| {
|
||||
println!("Nokhwa Initalized.");
|
||||
nokhwa_main()
|
||||
})
|
||||
}
|
||||
|
||||
fn nokhwa_main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
let cmd = match &cli.command {
|
||||
Some(cmd) => cmd,
|
||||
None => {
|
||||
println!("Unknown command \"\". Do --help for info.")
|
||||
}
|
||||
};
|
||||
|
||||
match cmd {
|
||||
Commands::ListDevices => {
|
||||
let backend = native_api_backend().unwrap();
|
||||
let devices = query(backend).unwrap();
|
||||
println!("There are {} available cameras.", devices.len());
|
||||
for device in devices {
|
||||
println!("{device}");
|
||||
}
|
||||
}
|
||||
Commands::ListProperties { device, kind } => {
|
||||
let index = match device.unwrap_or(IndexKind::Index(0)) {
|
||||
IndexKind::String(s) => CameraIndex::String(s),
|
||||
IndexKind::Index(i) => CameraIndex::Index(i),
|
||||
};
|
||||
let mut camera = Camera::new(
|
||||
index,
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::None),
|
||||
)
|
||||
.unwrap();
|
||||
match kind {
|
||||
PropertyKind::All => {
|
||||
camera_print_controls(&camera);
|
||||
camera_compatible_formats(&mut camera);
|
||||
}
|
||||
PropertyKind::Controls => {
|
||||
camera_print_controls(&camera);
|
||||
}
|
||||
PropertyKind::CompatibleFormats => {
|
||||
camera_compatible_formats(&mut camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
Commands::Stream {
|
||||
device,
|
||||
display,
|
||||
requested,
|
||||
} => {
|
||||
let requested = match requested {
|
||||
Some(req) => match req.format_type.as_str() {
|
||||
"HighestResolutionAbs" => {
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestResolutionAbs)
|
||||
}
|
||||
"HighestFrameRateAbs" => {
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestFrameRateAbs)
|
||||
}
|
||||
"HighestResolution" => {
|
||||
let values = req.format_option.unwrap().split(",").collect::<Vec<&str>>();
|
||||
let x = values[0].parse::<u32>().unwrap();
|
||||
let y = values[1].parse::<u32>().unwrap();
|
||||
let resolution = Resolution::new(x, y);
|
||||
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestResolution(
|
||||
resolution,
|
||||
))
|
||||
}
|
||||
"HighestFrameRate" => {
|
||||
let fps = req.format_option.unwrap().parse::<u32>().unwrap();
|
||||
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestFrameRate(
|
||||
fps,
|
||||
))
|
||||
}
|
||||
"Exact" => {
|
||||
let values = req.format_option.unwrap().split(",").collect::<Vec<&str>>();
|
||||
let x = values[0].parse::<u32>().unwrap();
|
||||
let y = values[1].parse::<u32>().unwrap();
|
||||
let fps = values[2].parse::<u32>().unwrap();
|
||||
let fourcc = values[3].parse::<FrameFormat>().unwrap();
|
||||
|
||||
let resolution = Resolution::new(x, y);
|
||||
let camera_format = CameraFormat::new(resolution, fourcc, fps);
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::Exact(camera_format))
|
||||
}
|
||||
"Closest" => {
|
||||
let values = req.format_option.unwrap().split(",").collect::<Vec<&str>>();
|
||||
let x = values[0].parse::<u32>().unwrap();
|
||||
let y = values[1].parse::<u32>().unwrap();
|
||||
let fps = values[2].parse::<u32>().unwrap();
|
||||
let fourcc = values[3].parse::<FrameFormat>().unwrap();
|
||||
|
||||
let resolution = Resolution::new(x, y);
|
||||
let camera_format = CameraFormat::new(resolution, fourcc, fps);
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::Closest(
|
||||
camera_format,
|
||||
))
|
||||
}
|
||||
"None" => RequestedFormat::new::<RgbFormat>(RequestedFormatType::None),
|
||||
_ => {
|
||||
println!("Expected HighestResolutionAbs, HighestFrameRateAbs, HighestResolution, HighestFrameRate, Exact, Closest, or None");
|
||||
return;
|
||||
}
|
||||
},
|
||||
None => RequestedFormat::new::<RgbFormat>(RequestedFormatType::None),
|
||||
};
|
||||
|
||||
let index = match device.unwrap_or(IndexKind::Index(0)) {
|
||||
IndexKind::String(s) => CameraIndex::String(s),
|
||||
IndexKind::Index(i) => CameraIndex::Index(i),
|
||||
};
|
||||
|
||||
if display {
|
||||
let (sender, receiver) = flume::unbounded();
|
||||
let (sender, receiver) = (Arc::new(sender), Arc::new(receiver));
|
||||
let sender_clone = sender.clone();
|
||||
|
||||
let mut camera = CallbackCamera::new(index, requested, move |buf| {
|
||||
sender_clone.send(buf).expect("Error sending frame!!!!");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let camera_info = camera.info().unwrap().clone();
|
||||
|
||||
camera.open_stream().unwrap();
|
||||
|
||||
let state = CaptureState {
|
||||
sender,
|
||||
receiver,
|
||||
buffer: Vec::with_capacity(3840 * 2160 * 3),
|
||||
camera,
|
||||
};
|
||||
|
||||
let cb = ContextBuilder::new(&camera_info.human_name(), "Nokhwa");
|
||||
let (ctx, el) = cb.build().unwrap();
|
||||
run(ctx, el, state)
|
||||
} else {
|
||||
let mut cb = CallbackCamera::new(index, requested, |buf| {
|
||||
println!("Captured frame of size {}", buf.buffer().len());
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cb.open_stream().unwrap();
|
||||
}
|
||||
}
|
||||
Commands::Single {
|
||||
device,
|
||||
save,
|
||||
requested,
|
||||
} => {
|
||||
let index = match device.unwrap_or(IndexKind::Index(0)) {
|
||||
IndexKind::String(s) => CameraIndex::String(s),
|
||||
IndexKind::Index(i) => CameraIndex::Index(i),
|
||||
};
|
||||
let requested = match requested {
|
||||
Some(req) => match req.format_type.as_str() {
|
||||
"HighestResolutionAbs" => {
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestResolutionAbs)
|
||||
}
|
||||
"HighestFrameRateAbs" => {
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestFrameRateAbs)
|
||||
}
|
||||
"HighestResolution" => {
|
||||
let values = req.format_option.unwrap().split(",").collect::<Vec<&str>>();
|
||||
let x = values[0].parse::<u32>().unwrap();
|
||||
let y = values[1].parse::<u32>().unwrap();
|
||||
let resolution = Resolution::new(x, y);
|
||||
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestResolution(
|
||||
resolution,
|
||||
))
|
||||
}
|
||||
"HighestFrameRate" => {
|
||||
let fps = req.format_option.unwrap().parse::<u32>().unwrap();
|
||||
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::HighestFrameRate(
|
||||
fps,
|
||||
))
|
||||
}
|
||||
"Exact" => {
|
||||
let values = req.format_option.unwrap().split(",").collect::<Vec<&str>>();
|
||||
let x = values[0].parse::<u32>().unwrap();
|
||||
let y = values[1].parse::<u32>().unwrap();
|
||||
let fps = values[2].parse::<u32>().unwrap();
|
||||
let fourcc = values[3].parse::<FrameFormat>().unwrap();
|
||||
|
||||
let resolution = Resolution::new(x, y);
|
||||
let camera_format = CameraFormat::new(resolution, fourcc, fps);
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::Exact(camera_format))
|
||||
}
|
||||
"Closest" => {
|
||||
let values = req.format_option.unwrap().split(",").collect::<Vec<&str>>();
|
||||
let x = values[0].parse::<u32>().unwrap();
|
||||
let y = values[1].parse::<u32>().unwrap();
|
||||
let fps = values[2].parse::<u32>().unwrap();
|
||||
let fourcc = values[3].parse::<FrameFormat>().unwrap();
|
||||
|
||||
let resolution = Resolution::new(x, y);
|
||||
let camera_format = CameraFormat::new(resolution, fourcc, fps);
|
||||
RequestedFormat::new::<RgbFormat>(RequestedFormatType::Closest(
|
||||
camera_format,
|
||||
))
|
||||
}
|
||||
"None" => RequestedFormat::new::<RgbFormat>(RequestedFormatType::None),
|
||||
_ => {
|
||||
println!("Expected HighestResolutionAbs, HighestFrameRateAbs, HighestResolution, HighestFrameRate, Exact, Closest, or None");
|
||||
return;
|
||||
}
|
||||
},
|
||||
None => RequestedFormat::new::<RgbFormat>(RequestedFormatType::None),
|
||||
};
|
||||
|
||||
let mut camera = Camera::new(index, requested).unwrap();
|
||||
|
||||
let frame = camera.frame().unwrap();
|
||||
println!("Captured Single Frame of {}", frame.buffer().len());
|
||||
let decoded = frame.decode_image::<RgbFormat>().unwrap();
|
||||
println!("Decoded Frame of {}", decoded.len());
|
||||
|
||||
if let Some(path) = save {
|
||||
println!("Saving to {path}");
|
||||
decoded.save(path).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn camera_print_controls(cam: &Camera) {
|
||||
let ctrls = cam.camera_controls().unwrap();
|
||||
let index = cam.index();
|
||||
println!("Controls for camera {index}");
|
||||
for ctrl in ctrls {
|
||||
println!("{ctrl}")
|
||||
}
|
||||
}
|
||||
|
||||
fn camera_compatible_formats(cam: &mut Camera) {
|
||||
for ffmt in frame_formats() {
|
||||
if let Ok(compatible) = cam.compatible_list_by_resolution(*ffmt) {
|
||||
for (resolution, fps) in compatible {
|
||||
println!("{ffmt}:");
|
||||
println!(" {resolution}: {fps:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+38
-22
@@ -1,11 +1,11 @@
|
||||
use crate::error::NokhwaError;
|
||||
use crate::pixel_format::FormatDecoder;
|
||||
use crate::{error::NokhwaError, pixel_format::FormatDecoder};
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
borrow::Borrow,
|
||||
cmp::Ordering,
|
||||
fmt::{Display, Formatter},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
/// Tells the init function what camera format to pick.
|
||||
@@ -21,8 +21,8 @@ use std::{
|
||||
pub enum RequestedFormatType {
|
||||
HighestResolutionAbs,
|
||||
HighestFrameRateAbs,
|
||||
HighestResolution(u32),
|
||||
HighestFrameRate(Resolution),
|
||||
HighestResolution(Resolution),
|
||||
HighestFrameRate(u32),
|
||||
Exact(CameraFormat),
|
||||
Closest(CameraFormat),
|
||||
None,
|
||||
@@ -112,23 +112,7 @@ impl RequestedFormat<'_> {
|
||||
format_framerates.sort_by_key(CameraFormat::resolution);
|
||||
format_framerates.last().copied()
|
||||
}
|
||||
RequestedFormatType::HighestResolution(fps) => {
|
||||
let mut formats = all_formats
|
||||
.iter()
|
||||
.filter(|x| x.frame_rate == fps)
|
||||
.copied()
|
||||
.collect::<Vec<CameraFormat>>();
|
||||
formats.sort_by(|a, b| a.resolution.cmp(&b.resolution));
|
||||
let highest_res = match formats.last() {
|
||||
Some(cf) => cf.resolution,
|
||||
None => return None,
|
||||
};
|
||||
formats
|
||||
.into_iter()
|
||||
.filter(|x| x.resolution() == highest_res)
|
||||
.last()
|
||||
}
|
||||
RequestedFormatType::HighestFrameRate(res) => {
|
||||
RequestedFormatType::HighestResolution(res) => {
|
||||
let mut formats = all_formats
|
||||
.iter()
|
||||
.filter(|x| x.resolution == res)
|
||||
@@ -144,6 +128,22 @@ impl RequestedFormat<'_> {
|
||||
.filter(|x| x.frame_rate == highest_fps)
|
||||
.last()
|
||||
}
|
||||
RequestedFormatType::HighestFrameRate(fps) => {
|
||||
let mut formats = all_formats
|
||||
.iter()
|
||||
.filter(|x| x.frame_rate == fps)
|
||||
.copied()
|
||||
.collect::<Vec<CameraFormat>>();
|
||||
formats.sort_by(|a, b| a.resolution.cmp(&b.resolution));
|
||||
let highest_res = match formats.last() {
|
||||
Some(cf) => cf.resolution,
|
||||
None => return None,
|
||||
};
|
||||
formats
|
||||
.into_iter()
|
||||
.filter(|x| x.resolution() == highest_res)
|
||||
.last()
|
||||
}
|
||||
RequestedFormatType::Exact(fmt) => {
|
||||
if self.wanted_decoder.contains(&fmt.format()) {
|
||||
Some(fmt)
|
||||
@@ -305,7 +305,7 @@ impl Display for FrameFormat {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
FrameFormat::MJPEG => {
|
||||
write!(f, "MJPG")
|
||||
write!(f, "MJPEG")
|
||||
}
|
||||
FrameFormat::YUYV => {
|
||||
write!(f, "YUYV")
|
||||
@@ -322,7 +322,23 @@ impl Display for FrameFormat {
|
||||
}
|
||||
}
|
||||
}
|
||||
impl FromStr for FrameFormat {
|
||||
type Err = NokhwaError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.as_ref() {
|
||||
"MJPEG" => Ok(FrameFormat::MJPEG),
|
||||
"YUYV" => Ok(FrameFormat::YUYV),
|
||||
"GRAY" => Ok(FrameFormat::GRAY),
|
||||
"RAWRGB" => Ok(FrameFormat::RAWRGB),
|
||||
"NV12" => Ok(FrameFormat::NV12),
|
||||
_ => Err(NokhwaError::StructureError {
|
||||
structure: "FrameFormat".to_string(),
|
||||
error: format!("No match for {s}"),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[must_use]
|
||||
pub const fn frame_formats() -> &'static [FrameFormat] {
|
||||
&[
|
||||
|
||||
+16
-5
@@ -19,6 +19,16 @@ use nokhwa_core::{
|
||||
types::{ApiBackend, CameraInfo},
|
||||
};
|
||||
|
||||
/// Gets the native [`ApiBackend`]
|
||||
pub fn native_api_backend() -> Option<ApiBackend> {
|
||||
match std::env::consts::OS {
|
||||
"linux" => Some(ApiBackend::Video4Linux),
|
||||
"macos" | "ios" => Some(ApiBackend::AVFoundation),
|
||||
"windows" => Some(ApiBackend::MediaFoundation),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Update as this goes
|
||||
/// Query the system for a list of available devices. Please refer to the API Backends that support `Query`) <br>
|
||||
/// Usually the order goes Native -> UVC -> Gstreamer.
|
||||
@@ -42,7 +52,7 @@ pub fn query(api: ApiBackend) -> Result<Vec<CameraInfo>, NokhwaError> {
|
||||
} else if cfg!(feature = "input-opencv") {
|
||||
query(ApiBackend::OpenCv)
|
||||
} else {
|
||||
dbg!("Error: No suitable Backends availible. Perhaps you meant to enable one of the backends such as `input-v4l`? (Please read the docs.)");
|
||||
dbg!("Error: No suitable Backends available. Perhaps you meant to enable one of the backends such as `input-v4l`? (Please read the docs.)");
|
||||
Err(NokhwaError::UnsupportedOperationError(ApiBackend::Auto))
|
||||
}
|
||||
}
|
||||
@@ -52,7 +62,7 @@ pub fn query(api: ApiBackend) -> Result<Vec<CameraInfo>, NokhwaError> {
|
||||
} else if cfg!(feature = "input-opencv") {
|
||||
query(ApiBackend::OpenCv)
|
||||
} else {
|
||||
dbg!("Error: No suitable Backends availible. Perhaps you meant to enable one of the backends such as `input-msmf`? (Please read the docs.)");
|
||||
dbg!("Error: No suitable Backends available. Perhaps you meant to enable one of the backends such as `input-msmf`? (Please read the docs.)");
|
||||
Err(NokhwaError::UnsupportedOperationError(ApiBackend::Auto))
|
||||
}
|
||||
}
|
||||
@@ -62,7 +72,7 @@ pub fn query(api: ApiBackend) -> Result<Vec<CameraInfo>, NokhwaError> {
|
||||
} else if cfg!(feature = "input-opencv") {
|
||||
query(ApiBackend::OpenCv)
|
||||
} else {
|
||||
dbg!("Error: No suitable Backends availible. Perhaps you meant to enable one of the backends such as `input-avfoundation`? (Please read the docs.)");
|
||||
dbg!("Error: No suitable Backends available. Perhaps you meant to enable one of the backends such as `input-avfoundation`? (Please read the docs.)");
|
||||
Err(NokhwaError::UnsupportedOperationError(ApiBackend::Auto))
|
||||
}
|
||||
}
|
||||
@@ -70,12 +80,12 @@ pub fn query(api: ApiBackend) -> Result<Vec<CameraInfo>, NokhwaError> {
|
||||
if cfg!(feature = "input-avfoundation") {
|
||||
query(ApiBackend::AVFoundation)
|
||||
} else {
|
||||
dbg!("Error: No suitable Backends availible. Perhaps you meant to enable one of the backends such as `input-avfoundation`? (Please read the docs.)");
|
||||
dbg!("Error: No suitable Backends available. Perhaps you meant to enable one of the backends such as `input-avfoundation`? (Please read the docs.)");
|
||||
Err(NokhwaError::UnsupportedOperationError(ApiBackend::Auto))
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
dbg!("Error: No suitable Backends availible. You are on an unsupported platform.");
|
||||
dbg!("Error: No suitable Backends available. You are on an unsupported platform.");
|
||||
Err(NokhwaError::NotImplementedError("Bad Platform".to_string()))
|
||||
}
|
||||
}
|
||||
@@ -100,6 +110,7 @@ pub fn query(api: ApiBackend) -> Result<Vec<CameraInfo>, NokhwaError> {
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
fn query_v4l() -> Result<Vec<CameraInfo>, NokhwaError> {
|
||||
use nokhwa_core::types::CameraIndex;
|
||||
Ok({
|
||||
let camera_info: Vec<CameraInfo> = v4l::context::enum_devices()
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user