Merge remote-tracking branch 'origin/senpai' into senpai

This commit is contained in:
l1npengtul
2023-08-03 15:04:48 +09:00
10 changed files with 219 additions and 29 deletions
+2 -6
View File
@@ -34,7 +34,6 @@ output-wgpu = ["wgpu", "nokhwa-core/wgpu-types"]
#output-wasm = ["input-jscam"]
output-threaded = []
output-async = ["nokhwa-core/async", "async-trait"]
small-wasm = []
docs-only = ["input-native", "input-opencv", "input-jscam","output-wgpu", "output-threaded", "serialize"]
docs-nolink = ["nokhwa-core/docs-features"]
docs-features = []
@@ -43,6 +42,7 @@ test-fail-warning = []
[dependencies]
thiserror = "1.0"
paste = "1.0"
dcv-color-primitives = "0.5"
[dependencies.nokhwa-core]
version = "0.2"
@@ -60,10 +60,6 @@ optional = true
version = "0.24"
default-features = false
[dependencies.v4l]
version = "0.13"
optional = true
[dependencies.usb_enumeration]
version = "0.2"
optional = true
@@ -73,7 +69,7 @@ version = "0.16"
optional = true
[dependencies.opencv]
version = "0.80"
version = "0.82"
default-features = false
features = ["videoio"]
optional = true
+11 -14
View File
@@ -16,6 +16,8 @@
use crate::{frame_format::SourceFrameFormat, types::Resolution};
use bytes::Bytes;
use image::ImageBuffer;
use crate::error::NokhwaError;
/// A buffer returned by a camera to accommodate custom decoding.
/// Contains information of Resolution, the buffer's [`FrameFormat`], and the buffer.
@@ -152,6 +154,9 @@ impl Buffer {
}
}
#[cfg(feature = "wgpu-types")]
use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, ImageCopyTexture, TextureAspect, ImageDataLayout};
#[cfg(feature = "wgpu-types")]
impl Buffer {
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "wgpu-types")))]
@@ -160,12 +165,10 @@ impl Buffer {
/// If the frame cannot be captured or the resolution is 0 on any axis, this will error.
fn frame_texture<'a>(
&mut self,
device: &WgpuDevice,
queue: &WgpuQueue,
device: &wgpu::Device,
queue: &wgpu::Queue,
label: Option<&'a str>,
) -> Result<WgpuTexture, NokhwaError> {
use crate::pixel_format::RgbAFormat;
use std::num::NonZeroU32;
) -> Result<wgpu::Texture, NokhwaError> {
let frame = self.frame()?.decode_image::<RgbAFormat>()?;
let texture_size = Extent3d {
@@ -182,17 +185,11 @@ impl Buffer {
dimension: TextureDimension::D2,
format: TextureFormat::Rgba8UnormSrgb,
usage: TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST,
view_formats: &[TextureFormat::Rgba8UnormSrgb],
});
let width_nonzero = match NonZeroU32::try_from(4 * frame.width()) {
Ok(w) => Some(w),
Err(why) => return Err(NokhwaError::ReadFrameError(why.to_string())),
};
let height_nonzero = match NonZeroU32::try_from(frame.height()) {
Ok(h) => Some(h),
Err(why) => return Err(NokhwaError::ReadFrameError(why.to_string())),
};
let width_nonzero = 4 * frame.width();
let height_nonzero = frame.height();
queue.write_texture(
ImageCopyTexture {
+76
View File
@@ -0,0 +1,76 @@
use std::ops::Deref;
use image::{ImageBuffer, Pixel};
use serde::de::Error;
use crate::buffer::Buffer;
use crate::frame_format::{SourceFrameFormat};
/// Trait to define a struct that can decode a [`Buffer`]
pub trait Decoder {
/// Formats that the decoder can decode.
const ALLOWED_FORMATS: &'static [SourceFrameFormat];
/// Output pixel type (e.g. [`Rgb<u8>`](image::Rgb))
type Pixel: Pixel;
/// Container for [`Self::Pixel`] - must have the same [`Pixel::Subpixel`]
type Container: Deref<Target = [Pixel::Subpixel]>;
/// Error that the decoder will output (use [`NokhwaError`] if you're not sure)
type Error: Error;
/// Decode function.
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
/// Decode to user-provided Buffer
///
/// Incase that the buffer is not large enough this should error.
fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
/// Decoder Predicted Size
fn predicted_size_of_frame(&mut self, ) -> Option<usize>;
}
/// Decoder that can be used statically (struct contains no state)
///
/// This is useful for times that a simple function is all that is required.
pub trait StaticDecoder: Decoder {
fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
}
/// Decoder that does not change its internal state.
pub trait IdemptDecoder: Decoder {
/// Decoder that does not change its internal state.
fn decode_nm(&self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
/// Decoder that does not change its internal state, decoding to a user provided buffer.
fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncDecoder: Decoder {
/// Asynchronous decoder
async fn decode_async(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
/// Asynchronous decoder to user buffer.
async fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncStaticDecoder: Decoder {
/// Asynchronous decoder
async fn decode_static_async(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
/// Asynchronous decoder to user buffer.
async fn decode_static_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
}
#[cfg(feature = "async")]
#[cfg_attr(feature = "async", async_trait::async_trait)]
pub trait AsyncIdemptDecoder: Decoder {
/// Asynchronous decoder
async fn decode_nm_async(&self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error>;
/// Asynchronous decoder to user buffer.
async fn decode_nm_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error>;
}
+1
View File
@@ -25,3 +25,4 @@ pub mod format_filter;
pub mod frame_format;
pub mod traits;
pub mod types;
pub mod decoder;
-9
View File
@@ -1333,15 +1333,6 @@ pub fn yuyv422_predicted_size(size: usize, rgba: bool) -> usize {
(size / 4) * (2 * pixel_size)
}
// For those maintaining this, I recommend you read: https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#yuy2
// https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
// and this too: https://stackoverflow.com/questions/16107165/convert-from-yuv-420-to-imagebgr-byte
// The YUY2(Yuv422) format is a 16 bit format. We read 4 bytes at a time to get 6 bytes of RGB888.
// First, the YUY2 is converted to YCbCr 4:4:4 (4:2:2 -> 4:4:4)
// then it is converted to 6 bytes (2 pixels) of RGB888
/// Converts a Yuv422 4:2:2 datastream to a RGB888 Stream. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB)
/// # Errors
/// This may error when the data stream size is not divisible by 4, a i32 -> u8 conversion fails, or it fails to read from a certain index.
#[inline]
pub fn yuyv422_to_rgb(data: &[u8], rgba: bool) -> Result<Vec<u8>, NokhwaError> {
let capacity = yuyv422_predicted_size(data.len(), rgba);
+30
View File
@@ -0,0 +1,30 @@
use image::{ImageBuffer, Rgb};
use nokhwa_core::buffer::Buffer;
use nokhwa_core::decoder::{Decoder, IdemptDecoder, StaticDecoder};
use nokhwa_core::error::NokhwaError;
use nokhwa_core::frame_format::{FrameFormat, SourceFrameFormat};
pub struct MJPegDecoder;
impl Decoder for MJPegDecoder {
const ALLOWED_FORMATS: &'static [SourceFrameFormat] = &[SourceFrameFormat::FrameFormat(FrameFormat::MJpeg)];
type Pixel = Rgb<u8>;
type Container = Vec<u8>;
type Error = NokhwaError;
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
}
impl StaticDecoder for MJPegDecoder {
fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
}
impl IdemptDecoder for MJPegDecoder {
fn decode_nm(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
}
+3
View File
@@ -0,0 +1,3 @@
pub mod mjpeg;
pub mod yuyv;
pub mod nv12;
+41
View File
@@ -0,0 +1,41 @@
use image::{ImageBuffer, Rgb};
use nokhwa_core::buffer::Buffer;
use nokhwa_core::decoder::{Decoder, IdemptDecoder, StaticDecoder};
use nokhwa_core::frame_format::SourceFrameFormat;
pub struct NV12Decoder {}
impl Decoder for NV12Decoder {
const ALLOWED_FORMATS: &'static [SourceFrameFormat] = &[];
type Pixel = Rgb<u8>;
type Container = Vec<u8>;
type Error = ();
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
todo!()
}
fn predicted_size_of_frame(&mut self) -> Option<usize> {
todo!()
}
}
impl StaticDecoder for NV12Decoder {
fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
todo!()
}
}
impl IdemptDecoder for NV12Decoder {
fn decode_nm(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
}
+54
View File
@@ -0,0 +1,54 @@
use image::ImageBuffer;
use nokhwa_core::buffer::Buffer;
use nokhwa_core::decoder::{Decoder, IdemptDecoder, StaticDecoder};
use nokhwa_core::frame_format::SourceFrameFormat;
// For those maintaining this, I recommend you read: https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#yuy2
// https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB
// and this too: https://stackoverflow.com/questions/16107165/convert-from-yuv-420-to-imagebgr-byte
// The YUY2(Yuv422) format is a 16 bit format. We read 4 bytes at a time to get 6 bytes of RGB888.
// First, the YUY2 is converted to YCbCr 4:4:4 (4:2:2 -> 4:4:4)
// then it is converted to 6 bytes (2 pixels) of RGB888
/// Converts a Yuv422 4:2:2 datastream to a RGB888 Stream. [For further reading](https://en.wikipedia.org/wiki/YUV#Converting_between_Y%E2%80%B2UV_and_RGB)
/// # Errors
/// This may error when the data stream size is not divisible by 4, a i32 -> u8 conversion fails, or it fails to read from a certain index.
pub struct YUYVDecoder {}
impl Decoder for YUYVDecoder {
const ALLOWED_FORMATS: &'static [SourceFrameFormat] = &[];
type Pixel = ();
type Container = ();
type Error = ();
fn decode(&mut self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
fn decode_buffer(&mut self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
todo!()
}
fn predicted_size_of_frame(&mut self) -> Option<usize> {
todo!()
}
}
impl StaticDecoder for YUYVDecoder {
fn decode_static(buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
fn decode_static_to_buffer(buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
todo!()
}
}
impl IdemptDecoder for YUYVDecoder {
fn decode_nm(&self, buffer: Buffer) -> Result<ImageBuffer<Self::Pixel, Self::Container>, Self::Error> {
todo!()
}
fn decode_nm_to_buffer(&self, buffer: &mut [Pixel::Subpixel]) -> Result<(), Self::Error> {
todo!()
}
}
+1
View File
@@ -49,6 +49,7 @@ mod query;
#[cfg(feature = "output-threaded")]
#[cfg_attr(feature = "docs-features", doc(cfg(feature = "output-threaded")))]
pub mod threaded;
pub mod decoders;
pub use camera::Camera;
pub use init::*;