mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
browser backend todoed, raw frame format, threaded fixes
This commit is contained in:
@@ -56,6 +56,12 @@ impl Buffer {
|
||||
&self.buffer
|
||||
}
|
||||
|
||||
/// Get a owned version of this buffer.
|
||||
#[must_use]
|
||||
pub fn buffer_bytes(&self) -> Bytes {
|
||||
self.buffer.clone()
|
||||
}
|
||||
|
||||
/// Get the [`FrameFormat`] of this buffer.
|
||||
#[must_use]
|
||||
pub fn source_frame_format(&self) -> FrameFormat {
|
||||
|
||||
@@ -64,6 +64,7 @@ impl FormatDecoder for RgbFormat {
|
||||
[pxv, pxv, pxv]
|
||||
})
|
||||
.collect()),
|
||||
FrameFormat::RAWRGB => Ok(data.to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +93,7 @@ impl FormatDecoder for RgbFormat {
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
FrameFormat::RAWRGB => {dest.copy_from_slice(data); Ok(())}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,6 +123,13 @@ impl FormatDecoder for RgbAFormat {
|
||||
[pxv, pxv, pxv, 255]
|
||||
})
|
||||
.collect()),
|
||||
FrameFormat::RAWRGB => Ok(data
|
||||
.chunks_exact(3)
|
||||
.flat_map(|x| {
|
||||
[x[0], x[1], x[2], 255]
|
||||
})
|
||||
.collect()
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +159,20 @@ impl FormatDecoder for RgbAFormat {
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
FrameFormat::RAWRGB => {
|
||||
data
|
||||
.chunks_exact(3)
|
||||
.enumerate()
|
||||
.for_each(|(idx, px)| {
|
||||
let index = idx * 4;
|
||||
dest[index] = px[0];
|
||||
dest[index + 1] = px[1];
|
||||
dest[index + 2] = px[2];
|
||||
dest[index + 3] = 255;
|
||||
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,6 +214,11 @@ impl FormatDecoder for LumaFormat {
|
||||
})
|
||||
.collect()),
|
||||
FrameFormat::GRAY => Ok(data.to_vec()),
|
||||
FrameFormat::RAWRGB => {
|
||||
Ok(data.chunks(3).map(|px| {
|
||||
((px[0] as i32 + px[1] as i32 + px[2] as i32) / 3) as u8
|
||||
}).collect())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,6 +247,11 @@ impl FormatDecoder for LumaFormat {
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
FrameFormat::RAWRGB => Err(NokhwaError::ProcessFrameError {
|
||||
src: fcc,
|
||||
destination: "RGB => RGB".to_string(),
|
||||
error: "Conversion Error".to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,6 +293,11 @@ impl FormatDecoder for LumaAFormat {
|
||||
})
|
||||
.collect()),
|
||||
FrameFormat::GRAY => Ok(data.iter().flat_map(|x| [*x, 255]).collect()),
|
||||
FrameFormat::RAWRGB => Err(NokhwaError::ProcessFrameError {
|
||||
src: fcc,
|
||||
destination: "RGB => RGB".to_string(),
|
||||
error: "Conversion Error".to_string(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,6 +339,13 @@ impl FormatDecoder for LumaAFormat {
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
FrameFormat::RAWRGB => {
|
||||
Err(NokhwaError::ProcessFrameError {
|
||||
src: fcc,
|
||||
destination: "RGB => RGB".to_string(),
|
||||
error: "Conversion Error".to_string(),
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ pub trait CaptureBackendTrait {
|
||||
let cfmt = self.camera_format();
|
||||
let resolution = cfmt.resolution();
|
||||
let pxwidth = match cfmt.format() {
|
||||
FrameFormat::MJPEG | FrameFormat::YUYV => 3,
|
||||
FrameFormat::MJPEG | FrameFormat::YUYV | FrameFormat::RAWRGB => 3,
|
||||
FrameFormat::GRAY => 1,
|
||||
};
|
||||
if alpha {
|
||||
|
||||
@@ -284,6 +284,7 @@ pub enum FrameFormat {
|
||||
MJPEG,
|
||||
YUYV,
|
||||
GRAY,
|
||||
RAWRGB,
|
||||
}
|
||||
|
||||
impl Display for FrameFormat {
|
||||
@@ -298,13 +299,16 @@ impl Display for FrameFormat {
|
||||
FrameFormat::GRAY => {
|
||||
write!(f, "GRAY")
|
||||
}
|
||||
FrameFormat::RAWRGB => {
|
||||
write!(f, "RAWRGB")
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn frame_formats() -> [FrameFormat; 3] {
|
||||
[FrameFormat::MJPEG, FrameFormat::YUYV, FrameFormat::GRAY]
|
||||
pub const fn frame_formats() -> &'static [FrameFormat] {
|
||||
&[FrameFormat::MJPEG, FrameFormat::YUYV, FrameFormat::GRAY, FrameFormat::RAWRGB]
|
||||
}
|
||||
|
||||
/// Describes a Resolution.
|
||||
|
||||
@@ -14,14 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
use crate::js_camera::{query_js_cameras, JSCameraConstraintsBuilder, JSCameraResizeMode};
|
||||
use image::{ImageBuffer, Rgb};
|
||||
use crate::js_camera::{ JSCamera};
|
||||
use nokhwa_core::{
|
||||
error::NokhwaError,
|
||||
traits::CaptureBackendTrait,
|
||||
types::{
|
||||
ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter,
|
||||
FrameFormat, KnownCameraControl, Resolution,
|
||||
FrameFormat, KnownCameraControl, Resolution, RequestedFormat,
|
||||
},
|
||||
};
|
||||
use std::{borrow::Cow, collections::HashMap};
|
||||
@@ -45,88 +44,90 @@ impl BrowserCaptureDevice {
|
||||
///
|
||||
/// # Errors
|
||||
/// If the device is not found, browser not supported, or camera is over-constrained this will error.
|
||||
pub fn new(index: &CameraIndex, cam_fmt: Option<CameraFormat>) -> Result<Self, NokhwaError> {
|
||||
let (group_id, device_id) = match &index {
|
||||
CameraIndex::Index(i) => {
|
||||
let query_devices =
|
||||
wasm_rs_async_executor::single_threaded::block_on(query_js_cameras())?;
|
||||
match query_devices.into_iter().nth(*i as usize) {
|
||||
Some(info) => {
|
||||
let ids = info
|
||||
.to_string()
|
||||
.split(' ')
|
||||
.map(ToString::to_string)
|
||||
.collect::<Vec<String>>();
|
||||
match (ids.get(0), ids.get(1)) {
|
||||
(Some(group_id), Some(device_id)) => {
|
||||
(group_id.clone(), device_id.clone())
|
||||
}
|
||||
(_, _) => {
|
||||
return Err(NokhwaError::OpenDeviceError(
|
||||
"Invalid Index".to_string(),
|
||||
index.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(NokhwaError::OpenDeviceError(
|
||||
"Device not found".to_string(),
|
||||
index.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
CameraIndex::String(id) => {
|
||||
let ids = id
|
||||
.to_string()
|
||||
.split(' ')
|
||||
.map(ToString::to_string)
|
||||
.collect::<Vec<String>>();
|
||||
match (ids.get(0), ids.get(1)) {
|
||||
(Some(group_id), Some(device_id)) => (group_id.clone(), device_id.clone()),
|
||||
(_, _) => {
|
||||
return Err(NokhwaError::OpenDeviceError(
|
||||
"Invalid Index".to_string(),
|
||||
index.to_string(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
pub fn new(index: &CameraIndex, requested: RequestedFormat) -> Result<Self, NokhwaError> {
|
||||
// let (group_id, device_id) = match &index {
|
||||
// CameraIndex::Index(i) => {
|
||||
// let query_devices =
|
||||
// wasm_rs_async_executor::single_threaded::block_on(query_js_cameras())?;
|
||||
// match query_devices.into_iter().nth(*i as usize) {
|
||||
// Some(info) => {
|
||||
// let ids = info
|
||||
// .to_string()
|
||||
// .split(' ')
|
||||
// .map(ToString::to_string)
|
||||
// .collect::<Vec<String>>();
|
||||
// match (ids.get(0), ids.get(1)) {
|
||||
// (Some(group_id), Some(device_id)) => {
|
||||
// (group_id.clone(), device_id.clone())
|
||||
// }
|
||||
// (_, _) => {
|
||||
// return Err(NokhwaError::OpenDeviceError(
|
||||
// "Invalid Index".to_string(),
|
||||
// index.to_string(),
|
||||
// ))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// None => {
|
||||
// return Err(NokhwaError::OpenDeviceError(
|
||||
// "Device not found".to_string(),
|
||||
// index.to_string(),
|
||||
// ))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// CameraIndex::String(id) => {
|
||||
// let ids = id
|
||||
// .to_string()
|
||||
// .split(' ')
|
||||
// .map(ToString::to_string)
|
||||
// .collect::<Vec<String>>();
|
||||
// match (ids.get(0), ids.get(1)) {
|
||||
// (Some(group_id), Some(device_id)) => (group_id.clone(), device_id.clone()),
|
||||
// (_, _) => {
|
||||
// return Err(NokhwaError::OpenDeviceError(
|
||||
// "Invalid Index".to_string(),
|
||||
// index.to_string(),
|
||||
// ))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
let camera_format = cam_fmt.unwrap_or_default();
|
||||
// let camera_format = cam_fmt.unwrap_or_default();
|
||||
|
||||
let constraints = JSCameraConstraintsBuilder::new()
|
||||
.frame_rate(camera_format.frame_rate())
|
||||
.resolution(camera_format.resolution())
|
||||
.aspect_ratio(f64::from(camera_format.width()) / f64::from(camera_format.height()))
|
||||
.group_id(&group_id)
|
||||
.group_id_exact(true)
|
||||
.device_id(&device_id)
|
||||
.device_id_exact(true)
|
||||
.resize_mode(JSCameraResizeMode::Any)
|
||||
.build();
|
||||
// let constraints = JSCameraConstraintsBuilder::new()
|
||||
// .frame_rate(camera_format.frame_rate())
|
||||
// .resolution(camera_format.resolution())
|
||||
// .aspect_ratio(f64::from(camera_format.width()) / f64::from(camera_format.height()))
|
||||
// .group_id(&group_id)
|
||||
// .group_id_exact(true)
|
||||
// .device_id(&device_id)
|
||||
// .device_id_exact(true)
|
||||
// .resize_mode(JSCameraResizeMode::Any)
|
||||
// .build();
|
||||
|
||||
let camera = wasm_rs_async_executor::single_threaded::block_on(JSCamera::new(constraints))?;
|
||||
// let camera = wasm_rs_async_executor::single_threaded::block_on(JSCamera::new(constraints))?;
|
||||
|
||||
let info = (|| {
|
||||
let cameras = wasm_rs_async_executor::single_threaded::block_on(query_js_cameras())?;
|
||||
let giddid = format!("{} {}", group_id, device_id);
|
||||
for cam in cameras {
|
||||
if cam.misc() == giddid {
|
||||
return Ok(cam);
|
||||
}
|
||||
}
|
||||
Ok(CameraInfo::new("", "videoinput", &giddid, index.clone()))
|
||||
})()?;
|
||||
Ok(BrowserCaptureDevice { camera, info })
|
||||
// let info = (|| {
|
||||
// let cameras = wasm_rs_async_executor::single_threaded::block_on(query_js_cameras())?;
|
||||
// let giddid = format!("{} {}", group_id, device_id);
|
||||
// for cam in cameras {
|
||||
// if cam.misc() == giddid {
|
||||
// return Ok(cam);
|
||||
// }
|
||||
// }
|
||||
// Ok(CameraInfo::new("", "videoinput", &giddid, index.clone()))
|
||||
// })()?;
|
||||
// Ok(BrowserCaptureDevice { camera, info })
|
||||
Err(NokhwaError::NotImplementedError("TODO".to_string()))
|
||||
}
|
||||
|
||||
/// Creates a new camera from an [`CameraIndex`] and raw parts. It can take [`CameraIndex::Index`] or [`CameraIndex::String`] (NOTE: blocks on [`CameraIndex::Index`])
|
||||
///
|
||||
/// # Errors
|
||||
/// If the device is not found, browser not supported, or camera is over-constrained this will error.
|
||||
#[deprecated(since = "0.10.0", note = "please use `new` instead.")]
|
||||
pub fn new_with(
|
||||
index: &CameraIndex,
|
||||
width: u32,
|
||||
@@ -134,10 +135,11 @@ impl BrowserCaptureDevice {
|
||||
fps: u32,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<Self, NokhwaError> {
|
||||
Self::new(
|
||||
index,
|
||||
Some(CameraFormat::new(Resolution::new(width, height))),
|
||||
)
|
||||
Err(NokhwaError::NotImplementedError("TODO".to_string()))
|
||||
// Self::new(
|
||||
// index,
|
||||
// Some(CameraFormat::new(Resolution::new(width, height), fourcc, fps)),
|
||||
// )
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,74 +153,53 @@ impl CaptureBackendTrait for BrowserCaptureDevice {
|
||||
}
|
||||
|
||||
fn refresh_camera_format(&mut self) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
self.camera.measure_resolution()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn camera_format(&self) -> CameraFormat {
|
||||
CameraFormat::new(self.camera.resolution())
|
||||
let constraints = self.camera.constraints();
|
||||
// CameraFormat::new(constraints.resolution(), , constraints.frame_rate())
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
||||
let current_constraints = self.camera.constraints();
|
||||
|
||||
let new_constraints = JSCameraConstraintsBuilder::new()
|
||||
.resolution(new_fmt.resolution())
|
||||
.aspect_ratio(f64::from(new_fmt.width()) / f64::from(new_fmt.height()))
|
||||
.frame_rate(new_fmt.frame_rate())
|
||||
.group_id(¤t_constraints.group_id())
|
||||
.device_id(¤t_constraints.device_id())
|
||||
.resize_mode(JSCameraResizeMode::Any)
|
||||
.build();
|
||||
|
||||
let _constraint_err = self.camera.set_constraints(new_constraints);
|
||||
match self.camera.apply_constraints() {
|
||||
Ok(_) => Ok(()),
|
||||
Err(why) => {
|
||||
let _returnerr = self.camera.set_constraints(current_constraints); // swallow errors - revert
|
||||
Err(why)
|
||||
}
|
||||
}
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compatible_list_by_resolution(
|
||||
&mut self,
|
||||
_: FrameFormat,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
|
||||
Err(NokhwaError::NotImplementedError(
|
||||
"Not Implemented".to_string(),
|
||||
))
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError> {
|
||||
Ok(vec![FrameFormat::MJPEG, FrameFormat::YUYV])
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn resolution(&self) -> Resolution {
|
||||
self.camera.resolution()
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
|
||||
let mut current_format = self.camera_format();
|
||||
current_format.set_resolution(new_res);
|
||||
self.set_camera_format(current_format)
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn frame_rate(&self) -> u32 {
|
||||
self.camera.constraints().frame_rate()
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_frame_rate(&mut self, new_fps: u32) -> Result<(), NokhwaError> {
|
||||
let mut current_format = self.camera_format();
|
||||
current_format.set_frame_rate(new_fps);
|
||||
self.set_camera_format(current_format)
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn frame_format(&self) -> FrameFormat {
|
||||
FrameFormat::MJPEG
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_frame_format(&mut self, _: FrameFormat) -> Result<(), NokhwaError> {
|
||||
Ok(())
|
||||
fn set_frame_format(&mut self, fourcc: FrameFormat) -> Result<(), NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn camera_control(&self, control: KnownCameraControl) -> Result<CameraControl, NokhwaError> {
|
||||
@@ -238,22 +219,22 @@ impl CaptureBackendTrait for BrowserCaptureDevice {
|
||||
}
|
||||
|
||||
fn open_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
Ok(())
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_stream_open(&self) -> bool {
|
||||
self.camera.is_open()
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn frame(&mut self) -> Result<ImageBuffer<Rgb<u8>, Vec<u8>>, NokhwaError> {
|
||||
self.camera.frame()
|
||||
fn frame(&mut self) -> Result<nokhwa_core::buffer::Buffer, NokhwaError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn frame_raw(&mut self) -> Result<Cow<[u8]>, NokhwaError> {
|
||||
self.camera.frame_raw()
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn stop_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
self.camera.stop_all()
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -32,7 +32,7 @@ use std::{
|
||||
fmt::{Debug, Display, Formatter},
|
||||
ops::Deref,
|
||||
};
|
||||
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use wasm_bindgen_futures::JsFuture;
|
||||
use web_sys::{
|
||||
console::log_1, CanvasRenderingContext2d, Document, Element, HtmlCanvasElement,
|
||||
@@ -1676,7 +1676,7 @@ impl Deref for JSCameraConstraints {
|
||||
/// # JS-WASM
|
||||
/// This is exported as `NokhwaCamera`.
|
||||
#[cfg(feature = "input-jscam")]
|
||||
#[cfg_attr(feature = "input-jscam", wasm_bindgen(js_name = NokhwaCamera))]
|
||||
#[cfg_attr(feature = "output-wasm", wasm_bindgen(js_name = NokhwaCamera))]
|
||||
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-jscam")))]
|
||||
pub struct JSCamera {
|
||||
media_stream: MediaStream,
|
||||
@@ -1688,7 +1688,7 @@ pub struct JSCamera {
|
||||
canvas_context: Option<CanvasRenderingContext2d>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "output-wasm")]
|
||||
#[cfg(feature = "input-jscam")]
|
||||
#[cfg_attr(feature = "output-wasm", wasm_bindgen(js_class = NokhwaCamera))]
|
||||
impl JSCamera {
|
||||
/// Creates a new [`JSCamera`] using [`JSCameraConstraints`].
|
||||
@@ -2007,7 +2007,7 @@ impl JSCamera {
|
||||
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
|
||||
pub fn measure_resolution(&mut self) -> Result<(), NokhwaError> {
|
||||
let stream = self
|
||||
.media_stream()
|
||||
.media_stream
|
||||
.get_video_tracks()
|
||||
.iter()
|
||||
.next()
|
||||
|
||||
+99
-40
@@ -15,18 +15,15 @@
|
||||
*/
|
||||
|
||||
use crate::Camera;
|
||||
use image::{ImageBuffer, Rgb};
|
||||
use nokhwa_core::{
|
||||
buffer::Buffer,
|
||||
error::NokhwaError,
|
||||
traits::CaptureBackendTrait,
|
||||
types::{
|
||||
ApiBackend, CameraControl, CameraFormat, CameraIndex, CameraInfo, ControlValueSetter,
|
||||
FrameFormat, KnownCameraControl, RequestedFormat, Resolution,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
any::Any,
|
||||
collections::HashMap,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
@@ -76,7 +73,7 @@ impl CallbackCamera {
|
||||
Ok(CallbackCamera {
|
||||
camera: arc_camera,
|
||||
frame_callback: Arc::new(Mutex::new(Box::new(callback))),
|
||||
last_frame_captured: Arc::new(Mutex::new(Buffer::new_with_vec(
|
||||
last_frame_captured: Arc::new(Mutex::new(Buffer::new(
|
||||
Resolution::new(0, 0),
|
||||
&vec![],
|
||||
FrameFormat::GRAY,
|
||||
@@ -86,52 +83,98 @@ impl CallbackCamera {
|
||||
}
|
||||
|
||||
/// Gets the current Camera's index.
|
||||
#[must_use]
|
||||
pub fn index(&self) -> usize {
|
||||
self.camera.lock().index().clone()
|
||||
pub fn index(&self) -> Result<&CameraIndex, NokhwaError> {
|
||||
Ok(self
|
||||
.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.index())
|
||||
}
|
||||
|
||||
/// Sets the current Camera's index. Note that this re-initializes the camera.
|
||||
/// # Errors
|
||||
/// The Backend may fail to initialize.
|
||||
pub fn set_index(&mut self, new_idx: usize) -> Result<(), NokhwaError> {
|
||||
self.camera.lock().set_index(new_idx)
|
||||
pub fn set_index(&mut self, new_idx: &CameraIndex) -> Result<(), NokhwaError> {
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.set_index(new_idx)
|
||||
}
|
||||
|
||||
/// Gets the current Camera's backend
|
||||
#[must_use]
|
||||
pub fn backend(&self) -> ApiBackend {
|
||||
self.camera.lock().backend()
|
||||
pub fn backend(&self) -> Result<ApiBackend, NokhwaError> {
|
||||
Ok(self
|
||||
.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.backend())
|
||||
}
|
||||
|
||||
/// Sets the current Camera's backend. Note that this re-initializes the camera.
|
||||
/// # Errors
|
||||
/// The new backend may not exist or may fail to initialize the new camera.
|
||||
pub fn set_backend(&mut self, new_backend: ApiBackend) -> Result<(), NokhwaError> {
|
||||
self.camera.lock().set_backend(new_backend)
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.set_backend(new_backend)
|
||||
}
|
||||
|
||||
/// Gets the camera information such as Name and Index as a [`CameraInfo`].
|
||||
#[must_use]
|
||||
pub fn info(&self) -> CameraInfo {
|
||||
self.camera.lock().info().clone()
|
||||
pub fn info(&self) -> Result<&CameraInfo, NokhwaError> {
|
||||
Ok(self
|
||||
.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.info())
|
||||
}
|
||||
|
||||
/// Gets the current [`CameraFormat`].
|
||||
pub fn camera_format(&self) -> Result<CameraFormat, NokhwaError> {
|
||||
self.camera.lock().camera_format()
|
||||
Ok(self
|
||||
.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.camera_format())
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[deprecated(since = "0.10.0", note = "please use `set_camera_requset` instead.")]
|
||||
pub fn set_camera_format(&mut self, new_fmt: CameraFormat) -> Result<(), NokhwaError> {
|
||||
*self.last_frame_captured.lock() =
|
||||
Buffer::new(new_res, &Vec::default(), self.camera_format()?.format());
|
||||
self.camera.lock().set_camera_format(new_fmt)
|
||||
*self
|
||||
.last_frame_captured
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? = Buffer::new(
|
||||
new_fmt.resolution(),
|
||||
&Vec::default(),
|
||||
self.camera_format()?.format(),
|
||||
);
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.set_camera_format(new_fmt)
|
||||
}
|
||||
|
||||
/// Will set the current [`CameraFormat`], using a [`RequestedFormat.`]
|
||||
/// This will reset the current stream if used while stream is opened.
|
||||
///
|
||||
/// This will also update the cache.
|
||||
///
|
||||
/// This will return the new [`CameraFormat`]
|
||||
/// # Errors
|
||||
/// If nothing fits the requested criteria, this will return an error.
|
||||
pub fn set_camera_requset(
|
||||
&mut self,
|
||||
request: RequestedFormat,
|
||||
) -> Result<CameraFormat, NokhwaError> {
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.set_camera_requset(request)
|
||||
}
|
||||
/// 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 [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError).
|
||||
@@ -139,14 +182,20 @@ impl CallbackCamera {
|
||||
&mut self,
|
||||
fourcc: FrameFormat,
|
||||
) -> Result<HashMap<Resolution, Vec<u32>>, NokhwaError> {
|
||||
self.camera.lock().compatible_list_by_resolution(fourcc)
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.compatible_list_by_resolution(fourcc)
|
||||
}
|
||||
|
||||
/// A Vector of compatible [`FrameFormat`]s.
|
||||
/// # Errors
|
||||
/// This will error if the camera is not queryable or a query operation has failed. Some backends will error this out as a [`UnsupportedOperationError`](crate::NokhwaError::UnsupportedOperationError).
|
||||
pub fn compatible_fourcc(&mut self) -> Result<Vec<FrameFormat>, NokhwaError> {
|
||||
self.camera.lock().compatible_fourcc()
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))?
|
||||
.compatible_fourcc()
|
||||
}
|
||||
|
||||
/// Gets the current camera resolution (See: [`Resolution`], [`CameraFormat`]).
|
||||
@@ -166,8 +215,11 @@ impl CallbackCamera {
|
||||
/// # Errors
|
||||
/// If you started the stream and the camera rejects the new resolution, this will return an error.
|
||||
pub fn set_resolution(&mut self, new_res: Resolution) -> Result<(), NokhwaError> {
|
||||
*self.last_frame_captured.lock() =
|
||||
Buffer::new_with_vec(new_res, Vec::default(), self.camera_format()?.format());
|
||||
*self
|
||||
.last_frame_captured
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? =
|
||||
Buffer::new(new_res, &Vec::default(), self.camera_format()?.format());
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::SetPropertyError {
|
||||
@@ -241,7 +293,7 @@ impl CallbackCamera {
|
||||
.map_err(|why| NokhwaError::GetPropertyError {
|
||||
property: "Supported Camera Controls".to_string(),
|
||||
error: why.to_string(),
|
||||
})
|
||||
})?
|
||||
.supported_camera_controls()
|
||||
}
|
||||
|
||||
@@ -379,29 +431,32 @@ impl CallbackCamera {
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::ReadFrameError(why.to_string()))?
|
||||
.frame()?;
|
||||
*self.last_frame_captured.lock() = frame.clone();
|
||||
*self
|
||||
.last_frame_captured
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GeneralError(why.to_string()))? = frame.clone();
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
/// Gets the last frame captured by the camera.
|
||||
#[must_use]
|
||||
pub fn last_frame(&self) -> Buffer {
|
||||
self.last_frame_captured
|
||||
pub fn last_frame(&self) -> Result<Buffer, NokhwaError> {
|
||||
Ok(self
|
||||
.last_frame_captured
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::ReadFrameError(why.to_string()))?
|
||||
.clone()
|
||||
.clone())
|
||||
}
|
||||
|
||||
/// Checks if stream if open. If it is, it will return true.
|
||||
#[must_use]
|
||||
pub fn is_stream_open(&self) -> bool {
|
||||
self.camera
|
||||
pub fn is_stream_open(&self) -> Result<bool, NokhwaError> {
|
||||
Ok(self
|
||||
.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::GetPropertyError {
|
||||
property: "is stream open".to_string(),
|
||||
error: why.to_string(),
|
||||
})?
|
||||
.is_stream_open()
|
||||
.is_stream_open())
|
||||
}
|
||||
|
||||
/// Will drop the stream.
|
||||
@@ -410,7 +465,7 @@ impl CallbackCamera {
|
||||
pub fn stop_stream(&mut self) -> Result<(), NokhwaError> {
|
||||
self.camera
|
||||
.lock()
|
||||
.map_err(|why| NokhwaError::StreamShutdownError(why.to_string()))
|
||||
.map_err(|why| NokhwaError::StreamShutdownError(why.to_string()))?
|
||||
.stop_stream()
|
||||
}
|
||||
}
|
||||
@@ -425,14 +480,18 @@ impl Drop for CallbackCamera {
|
||||
fn camera_frame_thread_loop(
|
||||
camera: &AtomicLock<Camera>,
|
||||
frame_callback: &HeldCallbackType,
|
||||
last_frame_captured: &AtomicLock<ImageBuffer<Rgb<u8>, Vec<u8>>>,
|
||||
last_frame_captured: &AtomicLock<Buffer>,
|
||||
die_bool: &Arc<AtomicBool>,
|
||||
) {
|
||||
loop {
|
||||
if let Ok(img) = camera.lock().fr {
|
||||
*last_frame_captured.lock() = img.clone();
|
||||
if let Some(cb) = (*frame_callback.lock()).as_mut() {
|
||||
cb(img);
|
||||
if let Ok(mut camera) = camera.lock() {
|
||||
if let Ok(frame) = camera.frame() {
|
||||
if let Ok(last_frame) = last_frame_captured.lock() {
|
||||
*last_frame = frame.clone();
|
||||
if let Ok(cb) = frame_callback.lock() {
|
||||
cb(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if die_bool.load(Ordering::SeqCst) {
|
||||
|
||||
Reference in New Issue
Block a user