finish impl stream for UVC, change to auto default camera format, adjust trait API

This commit is contained in:
l1npengtul
2021-05-28 19:37:16 +09:00
parent 2163b0ceff
commit 85f94eb470
4 changed files with 206 additions and 155 deletions
+139 -72
View File
@@ -6,12 +6,11 @@ use std::{
cell::{Cell, RefCell},
collections::HashMap,
mem::MaybeUninit,
ops::DerefMut,
sync::{atomic::AtomicUsize, Arc},
};
use uvc::{
ActiveStream, Context, Device, DeviceHandle, DeviceList, Error, FrameFormat as UVCFrameFormat,
StreamFormat, StreamHandle,
ActiveStream, Context, Device, DeviceHandle, FrameFormat as UVCFrameFormat, StreamFormat,
StreamHandle,
};
#[cfg(feature = "input_uvc")]
@@ -40,23 +39,24 @@ impl From<CameraFormat> for StreamFormat {
/// 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).
/// - 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()).
/// - [`get_frame_raw()`](CaptureBackendTrait::get_frame_raw()) returns the same raw data as [`get_frame()`](CaptureBackendTrait::get_frame()), a.k.a. no custom decoding required, all data is automatically RGB
/// This backend, once stream is open, will constantly collect frames. When you call [`get_frame()`](CaptureBackendTrait::get_frame()) or one of its variants, it will only give you the latest frame.
/// # Safety
/// This backend requires use of `unsafe` due to the self-referencing structs involved.
#[allow(clippy::too_many_arguments)]
/// If [`open_stream()`](CaptureBackendTrait::open_stream()) and [`get_frame()`](CaptureBackendTrait::get_frame()) are called in the wrong order this may crash the entire program.
#[self_referencing(chain_hack)]
pub struct UVCCaptureDevice<'a> {
camera_format: Option<CameraFormat>,
camera_format: CameraFormat,
camera_info: CameraInfo,
frame_receiver: Box<Receiver<Vec<u8>>>,
frame_sender: Box<Sender<Vec<u8>>>,
context: Box<Context<'a>>,
stream_handle_init: Cell<bool>,
active_stream_init: Cell<bool>,
context: Box<Context<'a>>,
#[borrows(context)]
#[not_covariant]
device: Box<Device<'this>>,
@@ -73,11 +73,12 @@ pub struct UVCCaptureDevice<'a> {
impl<'a> UVCCaptureDevice<'a> {
/// Creates a UVC Camera device with optional [`CameraFormat`].
/// If `camera_format` is `None`, it will be spawned with with 640x480@15 FPS, MJPEG [`CameraFormat`] default.
/// # 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> {
pub fn create(index: usize, cam_fmt: Option<CameraFormat>) -> Result<Self, NokhwaError> {
let context = match Context::new() {
Ok(ctx) => Box::new(ctx),
Err(why) => return Err(NokhwaError::CouldntOpenDevice(why.to_string())),
@@ -147,6 +148,11 @@ impl<'a> UVCCaptureDevice<'a> {
)
};
let camera_format = match cam_fmt {
Some(cfmt) => cfmt,
None => CameraFormat::default(),
};
Ok(UVCCaptureDeviceBuilder {
camera_format,
camera_info,
@@ -197,16 +203,8 @@ impl<'a> CaptureBackendTrait for UVCCaptureDevice<'a> {
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_camera_format(&self) -> CameraFormat {
*self.borrow_camera_format()
}
fn get_compatible_list_by_resolution(
@@ -221,36 +219,51 @@ impl<'a> CaptureBackendTrait for UVCCaptureDevice<'a> {
}
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 = { fields.stream_handle_init.get() };
if is_streamh_some {
// TODO
}
let prev_fmt = *self.borrow_camera_format();
Ok(())
self.with_camera_format_mut(|cfmt| {
*cfmt = new_fmt;
});
let is_streamh_some = self.borrow_stream_handle_init().get();
if is_streamh_some {
return match self.open_stream() {
Ok(_) => Ok(()),
Err(why) => {
// revert
self.with_camera_format_mut(|cfmt| {
*cfmt = prev_fmt;
});
Err(NokhwaError::CouldntSetProperty {
property: "CameraFormat".to_string(),
value: new_fmt.to_string(),
error: why.to_string(),
})
}
};
}
Ok(())
}
fn get_resolution(&self) -> Option<Resolution> {
self.with_camera_format(|fmt| fmt.as_ref().map(CameraFormat::resoltuion))
fn get_resolution(&self) -> Resolution {
self.borrow_camera_format().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 get_framerate(&self) -> u32 {
self.borrow_camera_format().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 get_frameformat(&self) -> FrameFormat {
self.borrow_camera_format().format()
}
fn set_frameformat(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
@@ -259,42 +272,20 @@ impl<'a> CaptureBackendTrait for UVCCaptureDevice<'a> {
fn open_stream(&mut self) -> Result<(), NokhwaError> {
let ret: Result<(), NokhwaError> = 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(),
))
}
};
let stream_format: StreamFormat = CameraFormat::into(*fields.camera_format);
// first, drop the existing stream by setting it to None
{
match fields.active_stream.try_borrow_mut() {
Ok(raw_astream) => {
if fields.active_stream_init.get() {
std::mem::drop(raw_astream.assume_init());
std::mem::drop(raw_astream);
*raw_astream = MaybeUninit::uninit();
fields.active_stream_init.set(false);
}
}
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
if fields.active_stream_init.get() {
let innard_value = fields.active_stream.replace(MaybeUninit::uninit());
unsafe { std::mem::drop(innard_value.assume_init()) };
fields.active_stream_init.set(false);
}
match fields.stream_handle.try_borrow_mut() {
Ok(mut raw_streamh) => {
if fields.stream_handle_init.get() {
std::mem::drop(raw_streamh.assume_init());
std::mem::drop(raw_streamh);
*raw_streamh = MaybeUninit::uninit();
fields.stream_handle_init.set(false);
}
}
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
if fields.stream_handle_init.get() {
let innard_value = fields.stream_handle.replace(MaybeUninit::uninit());
unsafe { std::mem::drop(innard_value.assume_init()) };
fields.stream_handle_init.set(false);
}
}
// second, set the stream handle according to the streamformat
@@ -322,27 +313,103 @@ impl<'a> CaptureBackendTrait for UVCCaptureDevice<'a> {
// finally, get the active stream
let counter = Arc::new(AtomicUsize::new(0));
let frame_sender: Sender<Vec<u8>> = *(self.with_frame_sender(|send| send)).clone();
let mut streamh = unsafe {};
// let active_stream = streamh.start_stream(|frame, _cnt| {}, counter);
let streamh = unsafe {
let raw_ptr =
(*fields.stream_handle.borrow_mut()).as_ptr() as *mut MaybeUninit<StreamHandle>;
let assume_inited: *mut MaybeUninit<StreamHandle<'static>> =
raw_ptr.cast::<MaybeUninit<uvc::StreamHandle>>();
&mut *assume_inited
};
let streamh_init = unsafe {
match streamh.as_mut_ptr().as_mut() {
Some(sth) => sth,
None => {
return Err(NokhwaError::CouldntOpenStream(
"Failed to get mutable raw pointer to stream handle!".to_string(),
))
}
}
};
let active_stream = match streamh_init.start_stream(
move |frame, _count| {
let vec_frame: Vec<u8> = frame.to_rgb().unwrap().to_bytes().to_vec();
if frame_sender.send(vec_frame).is_err() {
// do nothing
}
},
counter,
) {
Ok(active) => active,
Err(why) => return Err(NokhwaError::CouldntOpenStream(why.to_string())),
};
*fields.active_stream.borrow_mut() = MaybeUninit::new(active_stream);
Ok(())
});
if ret_2.is_err() {
return ret_2;
}
Ok(())
}
fn is_stream_open(&self) -> bool {
todo!()
self.with_active_stream_init(Cell::get)
}
fn get_frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
todo!()
let data = match self.get_frame_raw() {
Ok(d) => d,
Err(why) => return Err(why),
};
let resolution: Resolution = self.borrow_camera_format().resoltuion();
let imagebuf: ImageBuffer<Rgb<u8>, Vec<u8>> =
match ImageBuffer::from_vec(resolution.width(), resolution.height(), data) {
Some(img) => img,
None => {
return Err(NokhwaError::CouldntCaptureFrame(
"ImageBuffer too small! This is probably a bug, please report it!"
.to_string(),
))
}
};
Ok(imagebuf)
}
fn get_frame_raw(&mut self) -> Result<Vec<u8>, NokhwaError> {
todo!()
// assertions
if !self.borrow_active_stream_init().get() {
return Err(NokhwaError::CouldntCaptureFrame(
"Please call `open_stream()` first!".to_string(),
));
}
let f_recv = self.borrow_frame_receiver();
let messages_iter = f_recv.drain();
match messages_iter.last() {
Some(msg) => Ok(msg),
None => Err(NokhwaError::CouldntCaptureFrame("Too fast!".to_string())),
}
}
fn stop_stream(&mut self) -> Result<(), NokhwaError> {
todo!()
self.with(|fields| {
if fields.active_stream_init.get() {
let innard_value = fields.active_stream.replace(MaybeUninit::uninit());
unsafe { std::mem::drop(innard_value.assume_init()) };
fields.active_stream_init.set(false);
}
if fields.stream_handle_init.get() {
let innard_value = fields.stream_handle.replace(MaybeUninit::uninit());
unsafe { std::mem::drop(innard_value.assume_init()) };
fields.stream_handle_init.set(false);
}
});
Ok(())
}
}
+28 -62
View File
@@ -30,10 +30,9 @@ impl From<CameraFormat> for Format {
/// 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).
/// - 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_format: CameraFormat,
camera_info: CameraInfo,
device: Device,
stream_handle: Option<MmapStream<'a>>,
@@ -41,9 +40,11 @@ pub struct V4LCaptureDevice<'a> {
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.
///
/// If `camera_format` is `None`, it will be spawned with with 640x480@15 FPS, MJPEG [`CameraFormat`] default.
/// # Errors
/// This function will error if the camera is currently busy or if V4L2 can't read device information.
pub fn new(index: usize, camera_format: Option<CameraFormat>) -> Result<Self, NokhwaError> {
pub fn new(index: usize, cam_fmt: Option<CameraFormat>) -> Result<Self, NokhwaError> {
let device = match Device::new(index) {
Ok(dev) => dev,
Err(why) => {
@@ -64,6 +65,11 @@ impl<'a> V4LCaptureDevice<'a> {
}
};
let camera_format = match cam_fmt {
Some(cfmt) => cfmt,
None => CameraFormat::default(),
};
Ok(V4LCaptureDevice {
camera_format,
camera_info,
@@ -92,20 +98,7 @@ impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> {
self.camera_info.clone()
}
#[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 get_camera_format(&self) -> Option<CameraFormat> {
fn get_camera_format(&self) -> CameraFormat {
self.camera_format
}
@@ -242,60 +235,41 @@ impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> {
}
};
}
self.camera_format = Some(new_fmt);
self.camera_format = new_fmt;
Ok(())
}
fn get_resolution(&self) -> Option<Resolution> {
self.camera_format.map(|fmt| fmt.resoltuion())
fn get_resolution(&self) -> Resolution {
self.camera_format.resolution()
}
#[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(())
}
let mut new_fmt = self.camera_format;
new_fmt.set_resolution(new_res);
self.set_camera_format(new_fmt)
}
fn get_framerate(&self) -> Option<u32> {
self.camera_format.map(|fmt| fmt.framerate())
fn get_framerate(&self) -> u32 {
self.camera_format.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(())
}
let mut new_fmt = self.camera_format;
new_fmt.set_framerate(new_fps);
self.set_camera_format(new_fmt)
}
fn get_frameformat(&self) -> Option<FrameFormat> {
self.camera_format.map(|fmt| fmt.format())
fn get_frameformat(&self) -> FrameFormat {
self.camera_format.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(())
}
let mut new_fmt = self.camera_format;
new_fmt.set_format(fourcc);
self.set_camera_format(new_fmt)
}
fn open_stream(&mut self) -> Result<(), NokhwaError> {
@@ -313,15 +287,7 @@ impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> {
fn get_frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
let raw_frame = self.get_frame_raw()?;
let cam_fmt = match self.camera_format {
Some(fmt) => fmt,
None => {
return Err(NokhwaError::CouldntCaptureFrame(
"CameraFormat isn't initialized! This is probably a bug, please report it"
.to_string(),
));
}
};
let cam_fmt = self.camera_format;
let conv = match cam_fmt.format() {
FrameFormat::MJPEG => mjpeg_to_rgb888(&raw_frame)?,
FrameFormat::YUYV => yuyv422_to_rgb888(&raw_frame)?,
+14 -17
View File
@@ -9,50 +9,47 @@ use crate::{
/// This trait is for any backend that allows you to grab and take frames from a camera.
/// Many of the backends are **blocking**, if the camera is occupied the program will halt while it waits for it to become availible.
///
/// **Note**:
/// - Backends, if not provided with a camera format, will be spawned with 640x480@15 FPS, MJPEG [`CameraFormat`].
/// - Behaviour can differ from backend to backend. While the [`Capture`] struct abstracts most of this away, if you plan to use the raw backend structs please read the `Quirks` section of each backend.
pub trait CaptureBackendTrait {
/// 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>;
/// Gets the current [`CameraFormat`].
fn get_camera_format(&self) -> CameraFormat;
/// A hashmap of [`Resolution`]s mapped to framerates
/// # Errors
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation (see: [`NokhwaError::UnsupportedOperation`]).
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation ([`NokhwaError::UnsupportedOperation`]).
fn get_compatible_list_by_resolution(
&self,
fourcc: FrameFormat,
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError>;
/// Gets the supported camera formats.
/// # Errors
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a NO-OP [`NokhwaError::UnsupportedOperation`]
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a Unsupported Operation ([`NokhwaError::UnsupportedOperation`]).
fn get_resolution_list(&self, fourcc: FrameFormat) -> Result<Vec<Resolution>, NokhwaError>;
/// 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>;
/// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]).
fn get_resolution(&self) -> 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>;
/// Gets the current camera framerate (See: [`CameraFormat`]).
fn get_framerate(&self) -> 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>;
/// Gets the current camera's frame format (See: [`FrameFormat`], [`CameraFormat`]).
fn get_frameformat(&self) -> FrameFormat;
/// Will set the current [`FrameFormat`]
/// This will reset the current stream if used while stream is opened.
/// # Errors
+25 -4
View File
@@ -1,9 +1,10 @@
use crate::NokhwaError;
use mozjpeg::Decompress;
use std::fmt::Formatter;
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>
/// YUYV is a mathematical color space. You can read more [here.](https://en.wikipedia.org/wiki/YCbCr) <br>
/// MJPEG is a motion-jpeg compressed frame, it allows for high frame rates.
#[derive(Copy, Clone, Debug, PartialEq, Hash)]
pub enum FrameFormat {
@@ -84,7 +85,7 @@ impl Ord for Resolution {
}
}
/// This is a conveinence struct that holds all information about the format of a webcam stream.
/// This is a convenience struct that holds all information about the format of a webcam stream.
/// It consists of a [`Resolution`], [`FrameFormat`], and a framerate(u8).
#[derive(Copy, Clone, Debug, Hash, PartialEq)]
pub struct CameraFormat {
@@ -116,7 +117,7 @@ impl CameraFormat {
}
/// Get the resolution of the current [`CameraFormat`]
pub fn resoltuion(&self) -> Resolution {
pub fn resolution(&self) -> Resolution {
self.resolution
}
@@ -166,6 +167,16 @@ impl Default for CameraFormat {
}
}
impl Display for CameraFormat {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}@{}FPS, {} Format",
self.resolution, self.framerate, self.format
)
}
}
/// 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.
@@ -241,6 +252,16 @@ impl Ord for CameraInfo {
}
}
impl Display for CameraInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Name: {}, Description: {}, Extra: {}, Index: {}",
self.human_name, self.description, self.misc, self.index
)
}
}
/// The list of known capture backends to the library. <br>
/// - 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.
@@ -267,7 +288,7 @@ impl Display for CaptureAPIBackend {
/// Converts a MJPEG stream of [u8] into a Vec<u8> of RGB888. (R,G,B,R,G,B,...)
/// # Errors
/// If `mozjpeg` fails to read scanlines or setup the decompresser, this will error.
/// If `mozjpeg` fails to read scanlines or setup the decompressor, this will error.
/// # Safety
/// This function uses `unsafe`. The caller must ensure that:
/// - The input data is of the right size, does not exceed bounds, and/or the final size matches with the initial size.