mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
start implement uvc, remove IDE folder from git, update gitignore, add docs, pub use for mod.rs, trait impl for CameraFormat (UVC specific), add error sections
This commit is contained in:
@@ -1,2 +1,4 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
|
||||
.idea
|
||||
Generated
-3
@@ -1,3 +0,0 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/nokhwa.iml" filepath="$PROJECT_DIR$/.idea/nokhwa.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-54
@@ -1,54 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/bindgen-da18c220213b5026/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/bitflags-5e34d1f84d2a96f1/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/clang-sys-9053640b53b35358/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/crc32fast-0d2dfc2b15768c60/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/crossbeam-utils-b48698c417c7a327/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/libc-c4d5e0ac290484c3/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/log-07564267581ecd40/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/memchr-809547edee52f4bd/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/memoffset-d0b85380e951be2e/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/miniz_oxide-1b7113a72926dcfd/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/nom-55d131cf545dabbb/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-integer-94c2c53e5be3c76c/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-iter-c0e27e0e44ce843a/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-rational-789674f9dc39616a/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-traits-bba6d9da981bf2bd/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/proc-macro2-4aba2102ce30163e/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/rayon-bd03a8d39d1e1581/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/rayon-core-bfc51648641673b7/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/syn-a14c600f8083dc5a/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/v4l2-sys-mit-1401199a612bbed5/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/mozjpeg-sys-c35f54bf209e057e/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/nokhwa-fca4e2084c34cbf5/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/bitflags-88b50a288ea9b589/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/crc32fast-f112d4af2349618a/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/crossbeam-utils-f18a9a09c842a116/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/libc-34b92eaa97780640/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/memoffset-7dcca5ba1dbddb41/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/miniz_oxide-24ce73e20e4a3ff2/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/mozjpeg-sys-1a963405fcd77efc/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-integer-add9cb380db572d4/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-iter-7488762592985ead/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-rational-cc8bf80ac17a0e16/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/num-traits-68267bf3e91cd7cc/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/proc-macro2-ce1a087ba38e801a/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/rayon-82b053c11a069b7f/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/rayon-core-14a7bb24d6f58d5f/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/syn-ce42942113a88686/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/futures-core-398c829ef0b43005/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/proc-macro-error-3767db49a8a5c3f2/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/proc-macro-error-attr-4fdf86427e6e8f90/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/syn-649155a95cf88f66/out" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/target/debug/build/syn-e4c794e1e37211a0/out" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,4 +1,8 @@
|
||||
#[cfg(feature = "input_v4l")]
|
||||
pub mod v4l2;
|
||||
mod v4l2;
|
||||
#[cfg(feature = "input_v4l")]
|
||||
pub use v4l2::V4LCaptureDevice;
|
||||
#[cfg(feature = "input_uvc")]
|
||||
pub mod uvc;
|
||||
mod uvc_backend;
|
||||
#[cfg(feature = "input_uvc")]
|
||||
pub use uvc_backend::UVCCaptureDevice;
|
||||
|
||||
@@ -1,209 +0,0 @@
|
||||
use crate::{CameraFormat, CameraInfo, CaptureBackendTrait, FrameFormat, NokhwaError, Resolution};
|
||||
use flume::{Receiver, Sender};
|
||||
use image::{ImageBuffer, Rgb};
|
||||
use ouroboros::self_referencing;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
};
|
||||
use uvc::{ActiveStream, Context, Device, DeviceHandle, DeviceList, Error, StreamHandle};
|
||||
|
||||
// ignore the IDE, this compiles
|
||||
/// The backend struct that interfaces with libuvc.
|
||||
/// To see what this does, please see [`CaptureBackendTrait`]
|
||||
/// # Quirks
|
||||
/// The indexing for this backend is based off of `libuvc`'s device ordering, not the OS.
|
||||
/// You must call [`UVCCaptureDevice::create()`] instead of [`UVCCaptureDevice::new()`], some methods are auto-generated by the self-referencer and are not meant to be used.
|
||||
/// # Safety
|
||||
/// This backend requires use of `unsafe` due to the self-referencing structs involved.
|
||||
#[self_referencing(chain_hack, no_doc)]
|
||||
pub struct UVCCaptureDevice<'a> {
|
||||
camera_format: Option<CameraFormat>,
|
||||
camera_info: CameraInfo,
|
||||
frame_receiver: Box<Receiver<Vec<u8>>>,
|
||||
frame_sender: Box<Sender<Vec<u8>>>,
|
||||
context: Box<Context<'a>>,
|
||||
#[borrows(context)]
|
||||
#[not_covariant]
|
||||
device: Box<Device<'this>>,
|
||||
#[borrows(device)]
|
||||
#[not_covariant]
|
||||
device_handle: Box<Option<DeviceHandle<'this>>>,
|
||||
#[borrows(device_handle)]
|
||||
#[not_covariant]
|
||||
stream_handle: Box<Option<StreamHandle<'this>>>,
|
||||
#[borrows(stream_handle)]
|
||||
#[not_covariant]
|
||||
active_stream: Box<Option<ActiveStream<'this, Arc<AtomicUsize>>>>,
|
||||
}
|
||||
|
||||
impl<'a> UVCCaptureDevice<'a> {
|
||||
/// Creates a UVC Camera device with optional CameraFormat.
|
||||
pub fn create(index: usize, camera_format: Option<CameraFormat>) -> Result<Self, NokhwaError> {
|
||||
let context = match Context::new() {
|
||||
Ok(ctx) => Box::new(ctx),
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
|
||||
};
|
||||
|
||||
let device_list = match context.devices() {
|
||||
Ok(device_list) => device_list,
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
|
||||
};
|
||||
|
||||
let device = match device_list.into_iter().nth(index) {
|
||||
Some(d) => Box::new(d),
|
||||
None => {
|
||||
return Err(NokhwaError::CouldntOpenDevice(format!(
|
||||
"Device at {} not found",
|
||||
index
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let device_desc = match device.description() {
|
||||
Ok(desc) => desc,
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
|
||||
};
|
||||
|
||||
let device_name = match (device_desc.manufacturer, device_desc.product) {
|
||||
(Some(manu), Some(prod)) => {
|
||||
format!("{} {}", manu, prod)
|
||||
}
|
||||
(_, Some(prod)) => prod,
|
||||
(Some(manu), _) => {
|
||||
format!(
|
||||
"{}:{} {}",
|
||||
device_desc.vendor_id, device_desc.product_id, manu
|
||||
)
|
||||
}
|
||||
(_, _) => {
|
||||
format!("{}:{}", device_desc.vendor_id, device_desc.product_id)
|
||||
}
|
||||
};
|
||||
|
||||
let camera_info = CameraInfo::new(
|
||||
device_name,
|
||||
"".to_string(),
|
||||
format!("{}:{}", device_desc.vendor_id, device_desc.product_id),
|
||||
index,
|
||||
);
|
||||
|
||||
let (frame_sender, frame_receiver) = {
|
||||
let (a, b) = flume::unbounded::<Vec<u8>>();
|
||||
(Box::new(a), Box::new(b))
|
||||
};
|
||||
|
||||
Ok(UVCCaptureDeviceBuilder {
|
||||
camera_format,
|
||||
camera_info,
|
||||
frame_receiver,
|
||||
frame_sender,
|
||||
context,
|
||||
device_builder: |_ctx| device,
|
||||
device_handle_builder: |_device_builder| Box::new(None),
|
||||
stream_handle_builder: |_device_handle_builder| Box::new(None),
|
||||
active_stream_builder: |_stream_handle_builder| Box::new(None),
|
||||
}
|
||||
.build())
|
||||
}
|
||||
|
||||
/// Create a UVC Camera with desired settings.
|
||||
pub fn create_with(
|
||||
index: usize,
|
||||
width: u32,
|
||||
height: u32,
|
||||
fps: u32,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<Self, NokhwaError> {
|
||||
let camera_format = Some(CameraFormat::new_from(width, height, fourcc, fps));
|
||||
UVCCaptureDevice::create(index, camera_format)
|
||||
}
|
||||
}
|
||||
|
||||
// IDE Autocomplete ends here. Do not be afraid it your IDE does not show completion.
|
||||
// Here are some docs to help you out: https://docs.rs/ouroboros/0.9.3/ouroboros/attr.self_referencing.html
|
||||
impl<'a> CaptureBackendTrait for UVCCaptureDevice<'a> {
|
||||
fn get_info(&self) -> CameraInfo {
|
||||
self.borrow_camera_info().clone()
|
||||
}
|
||||
|
||||
fn init_camera_format_default(&mut self, overwrite: bool) -> Result<(), NokhwaError> {
|
||||
let camera_format = CameraFormat::default();
|
||||
|
||||
self.with_camera_format_mut(|fmt| match fmt {
|
||||
Some(existing_fmt) => {
|
||||
if overwrite {
|
||||
fmt = &mut Some(camera_format);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
fmt = &mut Some(camera_format);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn get_camera_format(&self) -> Option<CameraFormat> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_compatible_list_by_resolution(
|
||||
&self,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_resolution_list(&self, fourcc: FrameFormat) -> Result<Vec<Resolution>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_resolution(&self) -> Option<Resolution> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_framerate(&self) -> Option<u32> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_framerate(&mut self, new_fps: u32) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frameformat(&self) -> Option<FrameFormat> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_frameformat(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_stream_open(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frame_raw(&mut self) -> Result<Vec<u8>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stop_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
use crate::{CameraFormat, CameraInfo, CaptureBackendTrait, FrameFormat, NokhwaError, Resolution};
|
||||
use flume::{Receiver, Sender};
|
||||
use image::{ImageBuffer, Rgb};
|
||||
use ouroboros::self_referencing;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::HashMap,
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
};
|
||||
use uvc::{
|
||||
ActiveStream, Context, Device, DeviceHandle, DeviceList, Error, FrameFormat as UVCFrameFormat,
|
||||
StreamFormat, StreamHandle,
|
||||
};
|
||||
|
||||
#[cfg(feature = "input_uvc")]
|
||||
impl From<FrameFormat> for UVCFrameFormat {
|
||||
fn from(ff: FrameFormat) -> Self {
|
||||
match ff {
|
||||
FrameFormat::MJPEG => UVCFrameFormat::MJPEG,
|
||||
FrameFormat::YUYV => UVCFrameFormat::YUYV,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "input_uvc")]
|
||||
impl From<CameraFormat> for StreamFormat {
|
||||
fn from(cf: CameraFormat) -> Self {
|
||||
StreamFormat {
|
||||
width: cf.width(),
|
||||
height: cf.height(),
|
||||
fps: cf.framerate(),
|
||||
format: cf.format().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ignore the IDE, this compiles
|
||||
/// The backend struct that interfaces with libuvc.
|
||||
/// To see what this does, please see [`CaptureBackendTrait`]
|
||||
/// # Quirks
|
||||
/// The indexing for this backend is based off of `libuvc`'s device ordering, not the OS.
|
||||
/// You must call [create()](UVCCaptureDevice::create()) instead `new()`, some methods are auto-generated by the self-referencer and are not meant to be used.
|
||||
/// The [create()](UVCCaptureDevice::create()) method will open the device twice.
|
||||
/// 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).
|
||||
/// # Safety
|
||||
/// This backend requires use of `unsafe` due to the self-referencing structs involved.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[self_referencing(chain_hack)]
|
||||
pub struct UVCCaptureDevice<'a> {
|
||||
camera_format: Option<CameraFormat>,
|
||||
camera_info: CameraInfo,
|
||||
frame_receiver: Box<Receiver<Vec<u8>>>,
|
||||
frame_sender: Box<Sender<Vec<u8>>>,
|
||||
context: Box<Context<'a>>,
|
||||
#[borrows(context)]
|
||||
#[not_covariant]
|
||||
device: Box<Device<'this>>,
|
||||
#[borrows(device)]
|
||||
#[not_covariant]
|
||||
device_handle: Box<DeviceHandle<'this>>,
|
||||
#[borrows(device_handle)]
|
||||
#[not_covariant]
|
||||
stream_handle: Box<RefCell<Option<StreamHandle<'this>>>>,
|
||||
#[borrows(stream_handle)]
|
||||
#[not_covariant]
|
||||
active_stream: Box<RefCell<Option<ActiveStream<'this, Arc<AtomicUsize>>>>>,
|
||||
}
|
||||
|
||||
impl<'a> UVCCaptureDevice<'a> {
|
||||
/// Creates a UVC Camera device with optional [`CameraFormat`].
|
||||
/// # Panics
|
||||
/// This operation may panic! If the UVC Context fails to retrieve the device from the gotten IDs, this operation will panic.
|
||||
/// # Errors
|
||||
/// This may error when the `libuvc` backend fails to retreive the device or its data.
|
||||
pub fn create(index: usize, camera_format: Option<CameraFormat>) -> Result<Self, NokhwaError> {
|
||||
let context = match Context::new() {
|
||||
Ok(ctx) => Box::new(ctx),
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
|
||||
};
|
||||
|
||||
let (camera_info, frame_receiver, frame_sender, vendor_id, product_id, serial) = {
|
||||
let device_list = match context.devices() {
|
||||
Ok(device_list) => device_list,
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
|
||||
};
|
||||
|
||||
let device = match device_list.into_iter().nth(index) {
|
||||
Some(d) => Box::new(d),
|
||||
None => {
|
||||
return Err(NokhwaError::CouldntOpenDevice(format!(
|
||||
"Device at {} not found",
|
||||
index
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let device_desc = match device.description() {
|
||||
Ok(desc) => desc,
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
|
||||
};
|
||||
|
||||
let device_name = match (device_desc.manufacturer, device_desc.product) {
|
||||
(Some(manu), Some(prod)) => {
|
||||
format!("{} {}", manu, prod)
|
||||
}
|
||||
(_, Some(prod)) => prod,
|
||||
(Some(manu), _) => {
|
||||
format!(
|
||||
"{}:{} {}",
|
||||
device_desc.vendor_id, device_desc.product_id, manu
|
||||
)
|
||||
}
|
||||
(_, _) => {
|
||||
format!("{}:{}", device_desc.vendor_id, device_desc.product_id)
|
||||
}
|
||||
};
|
||||
|
||||
let camera_info = CameraInfo::new(
|
||||
device_name,
|
||||
"".to_string(),
|
||||
format!("{}:{}", device_desc.vendor_id, device_desc.product_id),
|
||||
index,
|
||||
);
|
||||
|
||||
let (vendor_id, product_id, serial) = (
|
||||
Some(i32::from(device_desc.product_id)),
|
||||
Some(i32::from(device_desc.vendor_id)),
|
||||
device_desc.serial_number,
|
||||
);
|
||||
|
||||
let (frame_sender, frame_receiver) = {
|
||||
let (a, b) = flume::unbounded::<Vec<u8>>();
|
||||
(Box::new(a), Box::new(b))
|
||||
};
|
||||
(
|
||||
camera_info,
|
||||
frame_receiver,
|
||||
frame_sender,
|
||||
vendor_id,
|
||||
product_id,
|
||||
serial,
|
||||
)
|
||||
};
|
||||
|
||||
Ok(UVCCaptureDeviceBuilder {
|
||||
camera_format,
|
||||
camera_info,
|
||||
frame_receiver,
|
||||
frame_sender,
|
||||
context,
|
||||
device_builder: |context_builder| {
|
||||
Box::new(
|
||||
context_builder
|
||||
.find_device(vendor_id, product_id, serial.as_deref())
|
||||
.unwrap(),
|
||||
)
|
||||
},
|
||||
device_handle_builder: |device_builder| Box::new(device_builder.open().unwrap()),
|
||||
stream_handle_builder: |_device_handle_builder| Box::new(RefCell::new(None)),
|
||||
active_stream_builder: |_stream_handle_builder| Box::new(RefCell::new(None)),
|
||||
}
|
||||
.build())
|
||||
}
|
||||
|
||||
/// Create a UVC Camera with desired settings.
|
||||
/// # Panics
|
||||
/// This operation may panic! If the UVC Context fails to retrieve the device from the gotten IDs, this operation will panic.
|
||||
/// # Errors
|
||||
/// This may error when the `libuvc` backend fails to retreive the device or its data.
|
||||
pub fn create_with(
|
||||
index: usize,
|
||||
width: u32,
|
||||
height: u32,
|
||||
fps: u32,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<Self, NokhwaError> {
|
||||
let camera_format = Some(CameraFormat::new_from(width, height, fourcc, fps));
|
||||
UVCCaptureDevice::create(index, camera_format)
|
||||
}
|
||||
}
|
||||
|
||||
// IDE Autocomplete ends here. Do not be afraid it your IDE does not show completion.
|
||||
// Here are some docs to help you out: https://docs.rs/ouroboros/0.9.3/ouroboros/attr.self_referencing.html
|
||||
impl<'a> CaptureBackendTrait for UVCCaptureDevice<'a> {
|
||||
fn get_info(&self) -> CameraInfo {
|
||||
self.borrow_camera_info().clone()
|
||||
}
|
||||
|
||||
fn init_camera_format_default(&mut self, overwrite: bool) -> Result<(), NokhwaError> {
|
||||
let camera_format = CameraFormat::default();
|
||||
|
||||
self.with_mut(|fields| {});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_camera_format(&self) -> Option<CameraFormat> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_compatible_list_by_resolution(
|
||||
&self,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_resolution_list(&self, fourcc: FrameFormat) -> Result<Vec<Resolution>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
||||
let ret: Result<(), NokhwaError> = self.with_mut(|fields| {
|
||||
*fields.camera_format = Some(new_fmt);
|
||||
let is_streamh_some = {
|
||||
match fields.stream_handle.try_borrow() {
|
||||
Ok(v) => v.is_some(),
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
|
||||
}
|
||||
};
|
||||
if is_streamh_some {
|
||||
// drop the stream handle first
|
||||
{
|
||||
*fields.stream_handle.borrow_mut() = None;
|
||||
}
|
||||
// replace with new
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_resolution(&self) -> Option<Resolution> {
|
||||
self.with_camera_format(|fmt| fmt.as_ref().map(CameraFormat::resoltuion))
|
||||
}
|
||||
|
||||
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_framerate(&self) -> Option<u32> {
|
||||
self.with_camera_format(|fmt| fmt.as_ref().map(CameraFormat::framerate))
|
||||
}
|
||||
|
||||
fn set_framerate(&mut self, new_fps: u32) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frameformat(&self) -> Option<FrameFormat> {
|
||||
self.with_camera_format(|fmt| fmt.as_ref().map(CameraFormat::format))
|
||||
}
|
||||
|
||||
fn set_frameformat(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
let ret = self.with_mut(|fields| {
|
||||
let stream_format: StreamFormat = match fields.camera_format {
|
||||
Some(fmt) => {
|
||||
let cameraformat: CameraFormat = *fmt;
|
||||
cameraformat.into()
|
||||
}
|
||||
None => {
|
||||
return Err(NokhwaError::CouldntOpenStream(
|
||||
"Please initialise the CameraFormat first!".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
// first, drop the existing stream by setting it to None
|
||||
{
|
||||
match fields.stream_handle.try_borrow_mut() {
|
||||
Ok(mut streamh_raw) => *streamh_raw = None,
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
|
||||
}
|
||||
}
|
||||
// second, set the stream handle according to the streamformat
|
||||
match fields
|
||||
.device_handle
|
||||
.get_stream_handle_with_format(stream_format)
|
||||
{
|
||||
Ok(streamh) => match fields.stream_handle.try_borrow_mut() {
|
||||
Ok(mut streamh_raw) => *streamh_raw = Some(streamh),
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
|
||||
},
|
||||
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_stream_open(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_frame_raw(&mut self) -> Result<Vec<u8>, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stop_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,8 @@ impl<'a> V4LCaptureDevice<'a> {
|
||||
}
|
||||
|
||||
/// Create a new V4L Camera with desired settings.
|
||||
/// # Errors
|
||||
/// This function will error if the camera is currently busy or if V4L2 can't read device information.
|
||||
pub fn new_with(
|
||||
index: usize,
|
||||
width: u32,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![allow(clippy::must_use_candidate)]
|
||||
|
||||
/// Raw access to each of Nokhwa's backends.
|
||||
pub mod backends;
|
||||
mod camera;
|
||||
mod camera_traits;
|
||||
|
||||
+2
-4
@@ -1,8 +1,6 @@
|
||||
use std::{cmp::Ordering, convert::TryFrom, fmt::{Display, write}, slice::from_raw_parts};
|
||||
|
||||
use mozjpeg::Decompress;
|
||||
|
||||
use crate::NokhwaError;
|
||||
use mozjpeg::Decompress;
|
||||
use std::{cmp::Ordering, convert::TryFrom, fmt::Display, slice::from_raw_parts};
|
||||
|
||||
/// Describes a frame format (i.e. how the bytes themselves are encoded). Often called `FourCC` <br>
|
||||
/// YUYV is a mathmatical color space. You can read more [here.](https://en.wikipedia.org/wiki/YCbCr) <br>
|
||||
|
||||
Reference in New Issue
Block a user