start wrapping up public api of 0.10

This commit is contained in:
l1npengtul
2022-07-26 01:09:31 +09:00
parent d248f2cbdc
commit a38f377f57
10 changed files with 330 additions and 100 deletions
+1 -1
View File
@@ -78,7 +78,7 @@ version = "0.13"
optional = true
[dependencies.opencv]
version = "0.65"
version = "0.66"
optional = true
[dependencies.rgb]
+2 -2
View File
@@ -17,7 +17,7 @@
use crate::{
mjpeg_to_rgb, nokhwa_check, nokhwa_initialize, yuyv422_to_rgb, ApiBackend, CameraControl,
CameraFormat, CameraInfo, CaptureBackendTrait, ControlValueSetter, FrameFormat,
KnownCameraControl, NokhwaError, PixelFormat, Resolution,
KnownCameraControl, NokhwaError, FormatDecoder, Resolution,
};
use image::{ImageBuffer, Rgb};
use nokhwa_bindings_macos::avfoundation::{
@@ -269,7 +269,7 @@ impl CaptureBackendTrait for AVFoundationCaptureDevice {
Ok(image_buf)
}
fn frame_typed<F: PixelFormat>(
fn frame_typed<F: FormatDecoder>(
&mut self,
) -> Result<ImageBuffer<crate::pixel_format::Output, Vec<u8>>, NokhwaError> {
todo!()
+2 -2
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
use crate::pixel_format::PixelFormat;
use crate::pixel_format::FormatDecoder;
use crate::{
ApiBackend, CameraControl, CameraFormat, CameraInfo, CaptureBackendTrait, FrameFormat,
KnownCameraControl, NokhwaError, Resolution,
@@ -584,7 +584,7 @@ impl CaptureBackendTrait for OpenCvCaptureDevice {
Ok(image_buf)
}
fn frame_typed<F: PixelFormat>(
fn frame_typed<F: FormatDecoder>(
&mut self,
) -> Result<ImageBuffer<crate::pixel_format::Output, Vec<u8>>, NokhwaError> {
todo!()
+2 -2
View File
@@ -18,7 +18,7 @@ use crate::{
buffer::Buffer,
error::NokhwaError,
mjpeg_to_rgb,
pixel_format::PixelFormat,
pixel_format::FormatDecoder,
utils::{CameraFormat, CameraInfo},
yuyv422_to_rgb, ApiBackend, CameraControl, CaptureBackendTrait, ControlValueDescription,
ControlValueSetter, FrameFormat, KnownCameraControl, KnownCameraControlFlag, Resolution,
@@ -659,7 +659,7 @@ impl<'a> CaptureBackendTrait for V4LCaptureDevice<'a> {
Ok(Buffer::new(cam_fmt.resolution(), conv, cam_fmt.format()))
}
fn frame_typed<F: PixelFormat>(
fn frame_typed<F: FormatDecoder>(
&mut self,
) -> Result<ImageBuffer<F::Output, Vec<u8>>, NokhwaError> {
self.frame()?.to_image_with_custom_format::<F>()
+153 -48
View File
@@ -14,77 +14,182 @@
* limitations under the License.
*/
use crate::pixel_format::PixelFormat;
use crate::{mjpeg_to_rgb, yuyv422_to_rgb, FrameFormat, NokhwaError, Resolution};
use crate::{
mjpeg_to_rgb, pixel_format::FormatDecoder, yuyv422_to_rgb, FrameFormat, NokhwaError, Resolution,
};
use image::{ImageBuffer, Pixel};
#[cfg(feature = "input-opencv")]
use opencv::core::Mat;
#[cfg(feature = "input-opencv")]
use rgb::{FromSlice, RGB};
use opencv::core::{Mat, Mat_AUTO_STEP, CV_8U, CV_8UC1, CV_8UC2, CV_8UC3, CV_8UC4};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
/// A buffer returned by a camera to accomodate custom decoding.
/// Contains information of Resolution, the buffer's [`FrameFormat`], and the buffer.
#[derive(Clone, Debug, Default, Hash, PartialOrd, PartialEq)]
#[cfg_attr(feature = "serde", Serialize, Deserialize)]
pub struct Buffer {
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Buffer<'a> {
resolution: Resolution,
buffer: Vec<u8>,
buffer: Cow<'a, [u8]>,
source_frame_format: FrameFormat,
}
impl Buffer {
pub fn new(res: Resolution, buf: Vec<u8>, source_frame_format: FrameFormat) -> Self {
impl<'a> Buffer<'a> {
/// Creates a new buffer with a [`Vec`].
pub fn new_with_vec(res: Resolution, buf: Vec<u8>, source_frame_format: FrameFormat) -> Self {
Self {
resolution: res,
buffer: buf,
buffer: Cow::Owned(buf),
source_frame_format,
}
}
/// Creates a new buffer with a [`&[u8]`].
pub fn new_with_slice(res: Resolution, buf: &[u8], source_frame_format: FrameFormat) -> Self {
Self {
resolution: res,
buffer: Cow::Borrowed(buf),
source_frame_format,
}
}
pub fn to_image<F: PixelFormat>(self) -> Result<ImageBuffer<F::Output, Vec<u8>>, NokhwaError> {
let new_data = F::buffer_to_output(self.source_frame_format, &self.buffer)?;
}
#[cfg(feature = "input-opencv")]
pub fn to_opencv_mat(self) -> Result<Mat, NokhwaError> {
let buffer = match self.source_frame_format {
FrameFormat::MJPEG => mjpeg_to_rgb(&self.buffer, use_alpha)?,
FrameFormat::YUYV => yuyv422_to_rgb(&self.buffer, use_alpha)?,
FrameFormat::GRAY8 => {
if use_alpha {
self.buffer.into_iter().flat_map(|x| [x, 255])
} else {
self.buffer
}
}
};
Ok(match self.source_frame_format {
FrameFormat::MJPEG | FrameFormat::YUYV => Mat::from_slice_2d(
buffer
.as_rgb()
.chunks(self.resolution.height_y as usize)
.collect::<&[&[RGB<u8>]]>(),
),
FrameFormat::GRAY8 => Mat::from_slice_2d(
buffer
.chunks(self.resolution.height_y as usize)
.collect::<&[&[u8]]>(),
),
}
.map_err(|why| NokhwaError::ProcessFrameError {
src: self.source_frame_format,
destination: "OpenCV Mat".to_string(),
error: why.to_string(),
})?)
}
/// Get the [`Resolution`] of this buffer.
pub fn resolution(&self) -> Resolution {
self.resolution
}
/// Get the data of this buffer.
pub fn buffer(&self) -> &[u8] {
&self.buffer
}
/// Get a mutable reference to this buffer.
///
/// NOTE: Editing this may lead to decoding failure or unsafety!
pub fn buffer_mut(&mut self) -> &mut [u8] {
&mut self.buffer
}
/// Get the [`FrameFormat`] of this buffer.
pub fn source_frame_format(&self) -> FrameFormat {
self.source_frame_format
}
/// Decodes a image with allocation using the provided [`FormatDecoder`].
/// # Errors
/// Will error when the decoding fails.
pub fn decode_image<F: FormatDecoder>(
&self,
) -> Result<ImageBuffer<F::Output, Vec<u8>>, NokhwaError> {
let new_data = F::write_output(self.source_frame_format, &self.buffer)?;
let image =
ImageBuffer::from_raw(self.resolution.width_x, self.resolution.height_y, new_data)
.ok_or(Err(NokhwaError::ProcessFrameError {
src: self.source_frame_format,
destination: stringify!(F).to_string(),
error: "Failed to create buffer".to_string(),
}))?;
Ok(image)
}
/// Decodes a image with allocation using the provided [`FormatDecoder`] into a `buffer`.
/// # Errors
/// Will error when the decoding fails, or the provided buffer is too small.
pub fn decode_image_to_buffer<F: FormatDecoder>(
&self,
buffer: &mut [u8],
) -> Result<(), NokhwaError> {
F::write_output_buffer(self.source_frame_format, &self.buffer, buffer)
}
/// Decodes a image with allocation using the provided [`FormatDecoder`] into a [`Mat`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html).
///
/// Note that this does a clone when creating the buffer, to decouple the lifetime of the internal data to the temporary Buffer. If you want to avoid this, please see [`decode_as_opencv_mat`](Self::decode_as_opencv_mat).
/// # Errors
/// Will error when the decoding fails, or `OpenCV` failed to create/copy the [`Mat`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html).
/// # Safety
/// This function uses `unsafe` in order to create the [`Mat`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html). Please see [`Mat::new_rows_cols_with_data`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html#method.new_rows_cols_with_data) for more.
#[cfg(feature = "input-opencv")]
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-opencv")))]
pub fn decode_opencv_mat<F: FormatDecoder>(&self) -> Result<Mat, NokhwaError> {
let mut buffer = F::write_output(self.source_frame_format, &self.buffer)?;
let array_type = match F::Output::CHANNEL_COUNT {
1 => CV_8UC1,
2 => CV_8UC2,
3 => CV_8UC3,
4 => CV_8UC4,
_ => {
return Err(NokhwaError::ProcessFrameError {
src: self.source_frame_format,
destination: "OpenCV Mat".to_string(),
error: "Invalid Decoder FormatDecoder Channel Count".to_string(),
})
}
};
unsafe {
// TODO: Look into removing this unnecessary copy.
let mat1 = Mat::new_rows_cols_with_data(
self.resolution.height_y as i32,
self.resolution.width_x as i32,
array_type,
&mut buffer as *mut std::os::raw::c_void,
Mat_AUTO_STEP,
)
.map_err(|why| NokhwaError::ProcessFrameError {
src: self.source_frame_format,
destination: "OpenCV Mat".to_string(),
error: why.to_string(),
})?;
Ok(mat1.clone().map_err(|why| NokhwaError::ProcessFrameError {
src: self.source_frame_format,
destination: "OpenCV Mat".to_string(),
error: why.to_string(),
})?)
}
}
/// Decodes a image with allocation using the provided [`FormatDecoder`] into a [`Mat`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html).
/// # Errors
/// Will error when the decoding fails, or `OpenCV` failed to create/copy the [`Mat`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html).
/// # Safety
/// This function uses `unsafe` in order to create the [`Mat`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html). Please see [`Mat::new_rows_cols_with_data`](https://docs.rs/opencv/latest/opencv/core/struct.Mat.html#method.new_rows_cols_with_data) for more.
///
/// THIS WILL CAUSE UNSOUNDNESS IF YOU USE THE MAT WHILE THE BUFFER ITSELF IS DROPPED.
#[cfg(feature = "input-opencv")]
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-opencv")))]
pub unsafe fn decode_as_opencv_mat<F: FormatDecoder>(&mut self) -> Result<Mat, NokhwaError> {
let resolution = self.resolution();
let frame_format = self.source_frame_format();
let array_type = match F::Output::CHANNEL_COUNT {
1 => CV_8UC1,
2 => CV_8UC2,
3 => CV_8UC3,
4 => CV_8UC4,
_ => {
return Err(NokhwaError::ProcessFrameError {
src: frame_format,
destination: "OpenCV Mat".to_string(),
error: "Invalid Decoder FormatDecoder Channel Count".to_string(),
})
}
};
unsafe {
Ok(Mat::new_rows_cols_with_data(
resolution.height_y as i32,
resolution.width_x as i32,
array_type,
self.buffer_mut() as *mut std::os::raw::c_void,
Mat_AUTO_STEP,
)
.map_err(|why| NokhwaError::ProcessFrameError {
src: frame_format,
destination: "OpenCV Mat".to_string(),
error: why.to_string(),
})?)
}
}
}
+4 -5
View File
@@ -16,7 +16,7 @@
use crate::{
buffer::Buffer, ApiBackend, CameraControl, CameraFormat, CameraInfo, CaptureBackendTrait,
ControlValueSetter, FrameFormat, KnownCameraControl, NokhwaError, Resolution,
ControlValueSetter, FormatDecoder, FrameFormat, KnownCameraControl, NokhwaError, Resolution,
};
use std::{borrow::Cow, collections::HashMap};
#[cfg(feature = "output-wgpu")]
@@ -347,12 +347,11 @@ impl Camera {
/// Directly writes the current frame(RGB24) into said `buffer`. If `convert_rgba` is true, the buffer written will be written as an RGBA frame instead of a RGB frame. Returns the amount of bytes written on successful capture.
/// # Errors
/// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, this will error.
pub fn write_frame_to_buffer(
pub fn write_frame_to_buffer<F: FormatDecoder>(
&mut self,
buffer: &mut [u8],
write_alpha: bool,
) -> Result<usize, NokhwaError> {
self.device.write_frame_to_buffer(buffer, write_alpha)
let buffer = self.device.frame()?;
}
#[cfg(feature = "output-wgpu")]
@@ -360,7 +359,7 @@ impl Camera {
/// Directly copies a frame to a Wgpu texture. This will automatically convert the frame into a RGBA frame.
/// # Errors
/// If the frame cannot be captured or the resolution is 0 on any axis, this will error.
pub fn frame_texture<'a, F: crate::PixelFormat>(
pub fn frame_texture<'a, F: crate::FormatDecoder>(
&mut self,
device: &WgpuDevice,
queue: &WgpuQueue,
+14 -27
View File
@@ -14,12 +14,13 @@
* limitations under the License.
*/
use crate::pixel_format::RgbAFormat;
use crate::{
error::NokhwaError,
utils::{
buf_mjpeg_to_rgb, buf_yuyv422_to_rgb, CameraFormat, CameraInfo, FrameFormat, Resolution,
},
Buffer, CameraControl, ControlValueSetter, KnownCameraControl, PixelFormat,
Buffer, CameraControl, ControlValueSetter, FormatDecoder, KnownCameraControl,
};
use std::{borrow::Cow, collections::HashMap};
#[cfg(feature = "output-wgpu")]
@@ -151,19 +152,19 @@ pub trait CaptureBackendTrait {
/// Checks if stream if open. If it is, it will return true.
fn is_stream_open(&self) -> bool;
/// Will get a frame from the camera as a Raw RGB image buffer. Depending on the backend, if you have not called [`open_stream()`](CaptureBackendTrait::open_stream()) before you called this,
/// Will get a frame from the camera as a [`Buffer`]. Depending on the backend, if you have not called [`open_stream()`](CaptureBackendTrait::open_stream()) before you called this,
/// it will either return an error.
/// # Errors
/// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), the decoding fails (e.g. MJPEG -> u8), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet,
/// this will error.
fn frame(&mut self) -> Result<Buffer, NokhwaError>;
fn frame<'a>(&mut self) -> Result<Buffer<'a>, NokhwaError>;
/// Will get a frame from the camera **without** any processing applied, meaning you will usually get a frame you need to decode yourself.
/// # Errors
/// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, this will error.
fn frame_raw(&mut self) -> Result<Cow<[u8]>, NokhwaError>;
/// The minimum buffer size needed to write the current frame. If `alpha` is true, it will instead return the minimum size of the RGBA buffer needed.
/// The minimum buffer size needed to write the current frame. If `alpha` is true, it will instead return the minimum size of the buffer with an alpha channel as well.
fn decoded_buffer_size(&self, alpha: bool) -> Result<usize, NokhwaError> {
let cfmt = self.camera_format();
let resolution = cfmt.resolution();
@@ -177,34 +178,20 @@ pub trait CaptureBackendTrait {
Ok((resolution.width() * resolution.height() * pxwidth) as usize)
}
/// Directly writes the current frame(RGB24) into said `buffer`. If `convert_rgba` is true, the buffer written will be written as an RGBA frame instead of a RGB frame. Returns the amount of bytes written on successful capture.
/// Directly writes the current frame into said `buffer` when provided a [`decoder`](crate::pixel_format::FormatDecoder).
/// # Errors
/// If the backend fails to get the frame (e.g. already taken, busy, doesn't exist anymore), or [`open_stream()`](CaptureBackendTrait::open_stream()) has not been called yet, this will error.
fn write_frame_to_buffer(
&mut self,
buffer: &mut [u8],
write_alpha: bool,
decoder: &dyn FormatDecoder,
) -> Result<usize, NokhwaError> {
// FIXME: ??????
let cfmt = self.camera_format();
let frame = self.frame_raw()?;
match cfmt.format() {
FrameFormat::MJPEG => buf_mjpeg_to_rgb(&frame, buffer, write_alpha)?,
FrameFormat::YUYV => buf_yuyv422_to_rgb(&frame, buffer, write_alpha)?,
FrameFormat::GRAY8 => {
let data = if write_alpha {
frame
.into_iter()
.flat_map(|px| [*px, u8::MAX])
.collect::<Cow<[u8]>>()
} else {
frame
};
let data = &self.frame_raw()?;
let data_length = data.len();
decoder.write_output_buffer(self.frame_format(), data, buffer)?;
buffer.copy_from_slice(&data)
}
};
Ok(frame.len())
Ok(data_length)
}
#[cfg(feature = "output-wgpu")]
@@ -218,9 +205,9 @@ pub trait CaptureBackendTrait {
queue: &WgpuQueue,
label: Option<&'a str>,
) -> Result<WgpuTexture, NokhwaError> {
use image::RgbaImage;
use crate::pixel_format::RgbAFormat;
use std::{convert::TryFrom, num::NonZeroU32};
let frame = self.frame()?.to_image();
let frame = self.frame()?.decode_image::<RgbAFormat>()?;
let texture_size = Extent3d {
width: frame.width(),
@@ -255,7 +242,7 @@ pub trait CaptureBackendTrait {
origin: wgpu::Origin3d::ZERO,
aspect: TextureAspect::All,
},
&rgba_frame.to_vec(),
&frame.to_vec(),
ImageDataLayout {
offset: 0,
bytes_per_row: width_nonzero,
+1 -1
View File
@@ -42,7 +42,7 @@ pub mod js_camera;
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "input-ipcam")))]
pub mod network_camera;
mod pixel_format;
pub use pixel_format::PixelFormat;
pub use pixel_format::FormatDecoder;
mod query;
/// A camera that runs in a different thread and can call your code based on callbacks.
#[cfg(feature = "output-threaded")]
+149 -10
View File
@@ -22,11 +22,18 @@ use image::{Luma, LumaA, Primitive};
use image::{Pixel, Rgb, Rgba};
use std::{fmt::Debug, hash::Hash};
pub trait PixelFormat: Copy + Clone + Debug + Default + Hash + Send + Sync {
/// Trait that has methods to convert raw data from the webcam to a proper raw image.
pub trait FormatDecoder: Copy + Clone + Debug + Default + Hash + Send + Sync {
type Output: Pixel;
/// Allocates and returns a `Vec`
/// # Errors
/// If the data is malformed, or the source [`FrameFormat`] is incompatible, this will error.
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError>;
/// Writes to a user provided buffer.
/// # Errors
/// If the data is malformed, the source [`FrameFormat`] is incompatible, or the user-alloted buffer is not large enough, this will error.
fn write_output_buffer(
fcc: FrameFormat,
data: &[u8],
@@ -34,10 +41,16 @@ pub trait PixelFormat: Copy + Clone + Debug + Default + Hash + Send + Sync {
) -> Result<(), NokhwaError>;
}
/// A Zero-Size-Type that contains the definition to convert a given image stream to an RGB888 in the [`Buffer`](crate::buffer::Buffer)'s [`.to_image()`](crate::buffer::Buffer::to_image)
///
/// ```.ignore
/// use image::{ImageBuffer, Rgb};
/// let image: ImageBuffer<Rgb<u8>, Vec<u8>> = buffer.to_image::<RgbFormat>();
/// ```
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct RgbFormat;
impl PixelFormat for RgbFormat {
impl FormatDecoder for RgbFormat {
type Output = Rgb<u8>;
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
@@ -62,18 +75,39 @@ impl PixelFormat for RgbFormat {
match fcc {
FrameFormat::MJPEG => buf_mjpeg_to_rgb(data, dest, false),
FrameFormat::YUYV => buf_yuyv422_to_rgb(data, dest, false),
FrameFormat::GRAY8 => {}
FrameFormat::GRAY8 => {
if dest.len() != data * 3 {
return Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "Luma => RGB".to_string(),
error: "Bad buffer length".to_string(),
});
}
data.into_iter().enumerate().for_each(|(idx, pixel_value)| {
let index = idx * 3;
dest[index] = *pixel_value;
dest[index + 1] = *pixel_value;
dest[index + 2] = *pixel_value;
})
}
}
}
}
/// A Zero-Size-Type that contains the definition to convert a given image stream to an RGBA8888 in the [`Buffer`](crate::buffer::Buffer)'s [`.to_image()`](crate::buffer::Buffer::to_image)
///
/// ```.ignore
/// use image::{ImageBuffer, Rgba};
/// let image: ImageBuffer<Rgba<u8>, Vec<u8>> = buffer.to_image::<RgbAFormat>();
/// ```
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct RgbaFormat;
pub struct RgbAFormat;
impl PixelFormat for RgbaFormat {
impl FormatDecoder for RgbAFormat {
type Output = Rgba<u8>;
fn buffer_to_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
match fcc {
FrameFormat::MJPEG => mjpeg_to_rgb(data, true),
FrameFormat::YUYV => yuyv422_to_rgb(data, true),
@@ -86,15 +120,49 @@ impl PixelFormat for RgbaFormat {
.collect(),
}
}
fn write_output_buffer(
fcc: FrameFormat,
data: &[u8],
dest: &mut [u8],
) -> Result<(), NokhwaError> {
match fcc {
FrameFormat::MJPEG => buf_mjpeg_to_rgb(data, dest, true),
FrameFormat::YUYV => buf_yuyv422_to_rgb(data, dest, true),
FrameFormat::GRAY8 => {
if dest.len() != data * 4 {
return Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "Luma => RGBA".to_string(),
error: "Bad buffer length".to_string(),
});
}
data.into_iter().enumerate().for_each(|(idx, pixel_value)| {
let index = idx * 4;
dest[index] = *pixel_value;
dest[index + 1] = *pixel_value;
dest[index + 2] = *pixel_value;
dest[index + 3] = 255;
})
}
}
}
}
/// A Zero-Size-Type that contains the definition to convert a given image stream to an Luma8(Grayscale 8-bit) in the [`Buffer`](crate::buffer::Buffer)'s [`.to_image()`](crate::buffer::Buffer::to_image)
///
/// ```.ignore
/// use image::{ImageBuffer, Luma};
/// let image: ImageBuffer<Luma<u8>, Vec<u8>> = buffer.to_image::<LumaFormat>();
/// ```
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct LumaFormat;
impl PixelFormat for LumaFormat {
impl FormatDecoder for LumaFormat {
type Output = Luma<u8>;
fn buffer_to_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
match fcc {
FrameFormat::MJPEG => Ok(mjpeg_to_rgb(data, false)?
.as_slice()
@@ -117,15 +185,46 @@ impl PixelFormat for LumaFormat {
FrameFormat::GRAY8 => data.to_vec(),
}
}
fn write_output_buffer(
fcc: FrameFormat,
data: &[u8],
dest: &mut [u8],
) -> Result<(), NokhwaError> {
match fcc {
FrameFormat::MJPEG => {
// FIXME: implement!
Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "Luma => RGB".to_string(),
error: "Conversion Error".to_string(),
})
}
FrameFormat::YUYV => Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "Luma => RGB".to_string(),
error: "Conversion Error".to_string(),
}),
FrameFormat::GRAY8 => data.into_iter().zip(dest.iter_mut()).for_each(|(pxv, d)| {
*d = *pxv;
}),
}
}
}
/// A Zero-Size-Type that contains the definition to convert a given image stream to an LumaA8(Grayscale 8-bit with 8-bit alpha) in the [`Buffer`](crate::buffer::Buffer)'s [`.to_image()`](crate::buffer::Buffer::to_image)
///
/// ```.ignore
/// use image::{ImageBuffer, LumaA};
/// let image: ImageBuffer<LumaA<u8>, Vec<u8>> = buffer.to_image::<LumaAFormat>();
/// ```
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct LumaAFormat;
impl PixelFormat for LumaAFormat {
impl FormatDecoder for LumaAFormat {
type Output = LumaA<u8>;
fn buffer_to_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
fn write_output(fcc: FrameFormat, data: &[u8]) -> Result<Vec<u8>, NokhwaError> {
match fcc {
FrameFormat::MJPEG => Ok(mjpeg_to_rgb(data, false)?
.as_slice()
@@ -148,4 +247,44 @@ impl PixelFormat for LumaAFormat {
FrameFormat::GRAY8 => data.into_iter().flat_map(|x| [*x, 255]).collect(),
}
}
fn write_output_buffer(
fcc: FrameFormat,
data: &[u8],
dest: &mut [u8],
) -> Result<(), NokhwaError> {
match fcc {
FrameFormat::MJPEG => {
// FIXME: implement!
Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "MJPEG => LumaA".to_string(),
error: "Conversion Error".to_string(),
})
}
FrameFormat::YUYV => Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "YUYV => LumaA".to_string(),
error: "Conversion Error".to_string(),
}),
FrameFormat::GRAY8 => {
if dest.len() != data.len() * 2 {
return Err(NokhwaError::ProcessFrameError {
src: fcc,
destination: "GRAY8 => LumaA".to_string(),
error: "Conversion Error".to_string(),
});
}
data.into_iter()
.zip(dest.chunks_exact_mut(2))
.enumerate()
.for_each(|(idx, (pxv, d))| {
let index = idx * 2;
*d[index] = pxv;
*d[index + 1] = 255;
})
}
}
}
}
+2 -2
View File
@@ -14,7 +14,7 @@
* limitations under the License.
*/
use crate::{pixel_format::PixelFormat, NokhwaError};
use crate::{pixel_format::FormatDecoder, NokhwaError};
#[cfg(any(
all(
feature = "input-avfoundation",
@@ -82,7 +82,7 @@ impl Display for FrameFormat {
impl<P> From<P> for FrameFormat
where
P: PixelFormat,
P: FormatDecoder,
{
fn from(_: P) -> Self {
P::CODE