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:
l1npengtul
2021-05-26 17:23:58 +09:00
parent b4a4e43f85
commit 0c2432b5cc
11 changed files with 324 additions and 286 deletions
+2
View File
@@ -1,2 +1,4 @@
/target
Cargo.lock
.idea
-3
View File
@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
-8
View File
@@ -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>
-54
View File
@@ -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
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+6 -2
View File
@@ -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;
-209
View File
@@ -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!()
}
}
+311
View File
@@ -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!()
}
}
+2
View File
@@ -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,
+1
View File
@@ -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
View File
@@ -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>