mirror of
https://github.com/l1npengtul/nokhwa.git
synced 2026-07-04 02:27:26 +00:00
mjpeg, yuv test
This commit is contained in:
+42
-24
@@ -1,11 +1,11 @@
|
||||
use crate::error::NokhwaError;
|
||||
use crate::frame_buffer::FrameBuffer;
|
||||
use crate::image::{DecodedImage, NonFloatScalarWidth};
|
||||
use crate::types::{Resolution};
|
||||
use crate::pixel_destination::PixelDestination;
|
||||
use crate::types::Resolution;
|
||||
use bytemuck::try_cast_slice_mut;
|
||||
pub use image::{ImageBuffer, Pixel, Primitive};
|
||||
use std::fmt::Debug;
|
||||
use bytemuck::try_cast_slice_mut;
|
||||
use crate::pixel_destination::PixelDestination;
|
||||
|
||||
pub trait Decoder {
|
||||
type Config: Clone + Debug + ConfigHasResolution;
|
||||
@@ -23,14 +23,25 @@ pub trait Decoder {
|
||||
destination_format: PixelDestination,
|
||||
) -> Result<Self::OutputMeta, NokhwaError>;
|
||||
|
||||
fn decode_to_pixel_buffer<P: Pixel>(&mut self, to_decode: FrameBuffer, mut buffer: impl AsMut<[P::Subpixel]>) -> Result<Self::OutputMeta, NokhwaError>
|
||||
fn decode_to_pixel_buffer<P: Pixel>(
|
||||
&mut self,
|
||||
to_decode: FrameBuffer,
|
||||
mut buffer: impl AsMut<[P::Subpixel]>,
|
||||
) -> Result<Self::OutputMeta, NokhwaError>
|
||||
where
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth,
|
||||
{
|
||||
let Some(destination) = PixelDestination::get_by_pixel::<P>() else { return Err(NokhwaError::DecoderUnknownDestinationPixelFormat(P::COLOR_MODEL, P::Subpixel::WIDTH_BYTES)) };
|
||||
let Some(destination) = PixelDestination::get_by_pixel::<P>() else {
|
||||
return Err(NokhwaError::DecoderUnknownDestinationPixelFormat(
|
||||
P::COLOR_MODEL,
|
||||
P::Subpixel::WIDTH_BYTES,
|
||||
));
|
||||
};
|
||||
|
||||
if !Self::supports_destination(destination) {
|
||||
return Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(destination))
|
||||
return Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(
|
||||
destination,
|
||||
));
|
||||
}
|
||||
|
||||
let buffer = buffer.as_mut();
|
||||
@@ -52,28 +63,35 @@ pub trait Decoder {
|
||||
let mut out_buffer: Vec<P::Subpixel> = vec![P::Subpixel::DEFAULT_MIN_VALUE; min_size_alloc];
|
||||
let meta = self.decode_to_pixel_buffer::<P>(to_decode, &mut out_buffer)?;
|
||||
Ok(DecodedImage::new(
|
||||
ImageBuffer::from_vec(
|
||||
resolution.width(),
|
||||
resolution.height(),
|
||||
out_buffer,
|
||||
)
|
||||
.ok_or(NokhwaError::Decoder(
|
||||
"failed to convert into an image buffer".to_string(),
|
||||
))?,
|
||||
ImageBuffer::from_vec(resolution.width(), resolution.height(), out_buffer).ok_or(
|
||||
NokhwaError::Decoder("failed to convert into an image buffer".to_string()),
|
||||
)?,
|
||||
meta,
|
||||
))
|
||||
}
|
||||
|
||||
fn output_decoder_min_size_pixel<P>(&self, resolution: Resolution) -> Result<usize, NokhwaError> where
|
||||
P: Pixel,
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth {
|
||||
PixelDestination::get_by_pixel::<P>().map(|dest| self.output_decoder_min_size(resolution, dest)).ok_or(NokhwaError::DecoderUnknownDestinationPixelFormat(P::COLOR_MODEL, P::Subpixel::WIDTH_BYTES))?
|
||||
|
||||
fn output_decoder_min_size_pixel<P>(&self, resolution: Resolution) -> Result<usize, NokhwaError>
|
||||
where
|
||||
P: Pixel,
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth,
|
||||
{
|
||||
PixelDestination::get_by_pixel::<P>()
|
||||
.map(|dest| self.output_decoder_min_size(resolution, dest))
|
||||
.ok_or(NokhwaError::DecoderUnknownDestinationPixelFormat(
|
||||
P::COLOR_MODEL,
|
||||
P::Subpixel::WIDTH_BYTES,
|
||||
))?
|
||||
}
|
||||
|
||||
fn output_decoder_min_size(&self, resolution: Resolution, destination_format: PixelDestination) -> Result<usize, NokhwaError> {
|
||||
|
||||
fn output_decoder_min_size(
|
||||
&self,
|
||||
resolution: Resolution,
|
||||
destination_format: PixelDestination,
|
||||
) -> Result<usize, NokhwaError> {
|
||||
if !Self::supports_destination(destination_format) {
|
||||
return Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(destination_format))
|
||||
return Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(
|
||||
destination_format,
|
||||
));
|
||||
}
|
||||
|
||||
let px_size = match destination_format {
|
||||
@@ -83,7 +101,7 @@ pub trait Decoder {
|
||||
PixelDestination::Rgba16 | PixelDestination::Bgra16 => 4_u32 * 2_u32,
|
||||
PixelDestination::Luma8 => 1_u32,
|
||||
PixelDestination::LumaA8 | PixelDestination::Luma16 => 2_u32,
|
||||
};
|
||||
};
|
||||
let reso = resolution.width() * resolution.height();
|
||||
Ok((reso as usize) * (px_size as usize))
|
||||
}
|
||||
|
||||
@@ -146,3 +146,24 @@ impl Deref for FrameBuffer<'_> {
|
||||
self.buffer.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for FrameBuffer<'_> {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
let buffer = Cow::Owned(value);
|
||||
|
||||
FrameBuffer {
|
||||
buffer,
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for FrameBuffer<'a> {
|
||||
fn from(value: &'a [u8]) -> Self {
|
||||
let buffer = Cow::Borrowed(value);
|
||||
FrameBuffer {
|
||||
buffer,
|
||||
metadata: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-17
@@ -1,14 +1,14 @@
|
||||
[package]
|
||||
name = "nokhwa-decoders"
|
||||
name = "nokhwa-decoders"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
ffmpeg = ["ffmpeg-the-third"]
|
||||
yuyv = ["dcv-color-primitives", "yuv"]
|
||||
mjpeg = ["zune-jpeg", "zune-core"]
|
||||
luma = ["nokhwa-iter-extensions", "itermore"]
|
||||
static = ["ffmpeg-the-third/static"]
|
||||
ffmpeg = [ "ffmpeg-the-third" ]
|
||||
yuyv = [ "dcv-color-primitives", "yuv" ]
|
||||
mjpeg = [ "zune-jpeg", "zune-core" ]
|
||||
luma = [ "nokhwa-iter-extensions", "itermore" ]
|
||||
# static = ["ffmpeg-the-third/static"]
|
||||
#async = []
|
||||
|
||||
[dependencies]
|
||||
@@ -16,38 +16,38 @@ bytemuck = "1.23"
|
||||
|
||||
[dependencies.nokhwa-core]
|
||||
version = "0.2"
|
||||
path = "../nokhwa-core"
|
||||
path = "../nokhwa-core"
|
||||
|
||||
[dependencies.ffmpeg-the-third]
|
||||
version = "4.0.0"
|
||||
version = "4.0.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.yuv]
|
||||
version = "0.8"
|
||||
version = "0.8"
|
||||
optional = true
|
||||
|
||||
[dependencies.dcv-color-primitives]
|
||||
version = "0.7"
|
||||
version = "0.7"
|
||||
optional = true
|
||||
|
||||
[dependencies.zune-jpeg]
|
||||
version = "0.5.0-rc9"
|
||||
version = "0.5.0-rc9"
|
||||
optional = true
|
||||
|
||||
[dependencies.zune-core]
|
||||
version = "0.5.0-rc2"
|
||||
version = "0.5.0-rc2"
|
||||
optional = true
|
||||
|
||||
[dependencies.itermore]
|
||||
version = "0.8"
|
||||
features = ["array_chunks"]
|
||||
version = "0.8"
|
||||
features = [ "array_chunks" ]
|
||||
optional = true
|
||||
|
||||
[dependencies.nokhwa-iter-extensions]
|
||||
version = "0.1"
|
||||
path = "../nokhwa-iter-extensions"
|
||||
version = "0.1"
|
||||
path = "../nokhwa-iter-extensions"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.image]
|
||||
workspace = true
|
||||
features = ["png", "jpeg", "avif"]
|
||||
features = [ "png", "jpeg", "avif" ]
|
||||
|
||||
+342
-262
@@ -1,16 +1,16 @@
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use bytemuck::{cast_slice, cast_slice_mut};
|
||||
use itermore::IterArrayChunks;
|
||||
use nokhwa_core::decoder::{ConfigHasResolution, Decoder};
|
||||
use nokhwa_core::error::NokhwaError;
|
||||
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||
use nokhwa_core::frame_format::{CustomFrameFormat, FrameFormat};
|
||||
use nokhwa_iter_extensions::duplicate::IterDuplicateConst;
|
||||
use nokhwa_iter_extensions::interweave::IterInterweave;
|
||||
use itermore::{IterArrayChunks};
|
||||
use nokhwa_core::pixel_destination::PixelDestination;
|
||||
use nokhwa_core::types::{CameraFormat, Resolution};
|
||||
use nokhwa_iter_extensions::duplicate::IterDuplicateConst;
|
||||
use nokhwa_iter_extensions::interweave::IterInterweave;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct LumaDecoder {
|
||||
@@ -40,15 +40,21 @@ impl Decoder for LumaDecoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decode_to_buffer(&mut self, to_decode: FrameBuffer, mut buffer: impl AsMut<[u8]>, destination_format: PixelDestination) -> Result<Self::OutputMeta, NokhwaError> {
|
||||
let format = self.config().custom_frame_format_map.as_ref().and_then(|m| {
|
||||
match self.config().format {
|
||||
FrameFormat::Custom(cfmt) => {
|
||||
m.get(&cfmt).copied()
|
||||
}
|
||||
fn decode_to_buffer(
|
||||
&mut self,
|
||||
to_decode: FrameBuffer,
|
||||
mut buffer: impl AsMut<[u8]>,
|
||||
destination_format: PixelDestination,
|
||||
) -> Result<Self::OutputMeta, NokhwaError> {
|
||||
let format = self
|
||||
.config()
|
||||
.custom_frame_format_map
|
||||
.as_ref()
|
||||
.and_then(|m| match self.config().format {
|
||||
FrameFormat::Custom(cfmt) => m.get(&cfmt).copied(),
|
||||
_ => None,
|
||||
}
|
||||
}).unwrap_or(self.config().format);
|
||||
})
|
||||
.unwrap_or(self.config().format);
|
||||
|
||||
let r = filter_to_u8(self.config().channel_filters.red);
|
||||
let g = filter_to_u8(self.config().channel_filters.green);
|
||||
@@ -63,207 +69,259 @@ impl Decoder for LumaDecoder {
|
||||
let buffer = buffer.as_mut();
|
||||
|
||||
match format {
|
||||
FrameFormat::Luma_8 => {
|
||||
match destination_format {
|
||||
PixelDestination::Luma8 => {
|
||||
if to_decode.len() != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
FrameFormat::Luma_8 => match destination_format {
|
||||
PixelDestination::Luma8 => {
|
||||
if to_decode.len() != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
match to_decode.consume().0 {
|
||||
Cow::Borrowed(data) => {
|
||||
buffer.copy_from_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
Cow::Owned(mut owned) => {
|
||||
buffer.swap_with_slice(owned.as_mut_slice());
|
||||
Ok(())
|
||||
}
|
||||
match to_decode.consume().0 {
|
||||
Cow::Borrowed(data) => {
|
||||
buffer.copy_from_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
Cow::Owned(mut owned) => {
|
||||
buffer.swap_with_slice(owned.as_mut_slice());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
PixelDestination::LumaA8 => {
|
||||
let default_alpha = u8::MAX * a;
|
||||
}
|
||||
PixelDestination::LumaA8 => {
|
||||
let default_alpha = u8::MAX * a;
|
||||
|
||||
if (to_decode.len() * 2) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
to_decode.buffer().iter().interweave::<0>(&default_alpha, false).enumerate()
|
||||
.for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*buffer.get_unchecked_mut(len) = *data;
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
if (to_decode.len() * 2) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
PixelDestination::Rgb8 => {
|
||||
if (to_decode.len() * 3) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
to_decode.buffer().iter().duplicate_const::<3>().arrays::<3>().flat_map(|pixel| {
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.interweave::<0>(&default_alpha, false)
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*buffer.get_unchecked_mut(len) = *data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgb8 => {
|
||||
if (to_decode.len() * 3) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|pixel| {
|
||||
let px_r = *pixel[0_usize] * r;
|
||||
let px_g = *pixel[1_usize] * g;
|
||||
let px_b = *pixel[2_usize] * b;
|
||||
[px_r, px_g, px_b]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*buffer.get_unchecked_mut(len) = data;
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*buffer.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgba8 => {
|
||||
if (to_decode.len() * 4) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
PixelDestination::Rgba8 => {
|
||||
if (to_decode.len() * 4) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
to_decode.buffer().iter().duplicate_const::<3>().arrays::<3>().flat_map(|pixel| {
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|pixel| {
|
||||
let px_r = *pixel[0_usize] * r;
|
||||
let px_g = *pixel[1_usize] * g;
|
||||
let px_b = *pixel[2_usize] * b;
|
||||
let px_a = 255 * b;
|
||||
[px_r, px_g, px_b, px_a]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*buffer.get_unchecked_mut(len) = data;
|
||||
}
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*buffer.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgb16 => {
|
||||
if (to_decode.len() * 6) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
PixelDestination::Rgb16 => {
|
||||
if (to_decode.len() * 6) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
let temp_buffer = cast_slice_mut::<u8, u16>(buffer);
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => {
|
||||
u16::MAX / (u8::MAX as u16)
|
||||
}
|
||||
ConvertMode::Clipped => {
|
||||
1_u16
|
||||
}
|
||||
};
|
||||
let temp_buffer = cast_slice_mut::<u8, u16>(buffer);
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => u16::MAX / (u8::MAX as u16),
|
||||
ConvertMode::Clipped => 1_u16,
|
||||
};
|
||||
|
||||
to_decode.buffer().iter().duplicate_const::<3>().arrays::<3>().flat_map(|pixel| {
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|pixel| {
|
||||
let px_r = (*pixel[0_usize] as u16) * r_u16 * factor;
|
||||
let px_g = (*pixel[1_usize] as u16) * g_u16 * factor;
|
||||
let px_b = (*pixel[2_usize] as u16) * b_u16 * factor;
|
||||
[px_r, px_g, px_b]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*temp_buffer.get_unchecked_mut(len) = data;
|
||||
}
|
||||
}); Ok(())
|
||||
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*temp_buffer.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgba16 => {
|
||||
if (to_decode.len() * 8) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
PixelDestination::Rgba16 => {
|
||||
if (to_decode.len() * 8) != buffer.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
let temp_buffer = cast_slice_mut::<u8, u16>(buffer);
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => {
|
||||
u16::MAX / (u8::MAX as u16)
|
||||
}
|
||||
ConvertMode::Clipped => {
|
||||
1_u16
|
||||
}
|
||||
};
|
||||
let temp_buffer = cast_slice_mut::<u8, u16>(buffer);
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => u16::MAX / (u8::MAX as u16),
|
||||
ConvertMode::Clipped => 1_u16,
|
||||
};
|
||||
|
||||
to_decode.buffer().iter().duplicate_const::<3>().arrays::<3>().flat_map(|pixel| {
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|pixel| {
|
||||
let px_r = (*pixel[0_usize] as u16) * r_u16 * factor;
|
||||
let px_g = (*pixel[1_usize] as u16) * g_u16 * factor;
|
||||
let px_b = (*pixel[2_usize] as u16) * b_u16 * factor;
|
||||
let px_a = u16::MAX * a_u16;
|
||||
[px_r, px_g, px_b, px_a]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*temp_buffer.get_unchecked_mut(len) = data;
|
||||
}
|
||||
}); Ok(())
|
||||
|
||||
}
|
||||
PixelDestination::Luma16 => {
|
||||
let buffer_u16 = cast_slice_mut::<u8, u16>(buffer);
|
||||
|
||||
if to_decode.len() != buffer_u16.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => 8,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode.buffer().iter().map(|px| {
|
||||
(*px as u16) << factor
|
||||
}).enumerate()
|
||||
.for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*buffer_u16.get_unchecked_mut(len) = data;
|
||||
}
|
||||
}); Ok(())
|
||||
|
||||
}
|
||||
PixelDestination::LumaA16 => {
|
||||
let default_alpha = u16::MAX * a_u16;
|
||||
let buffer_u16 = cast_slice_mut::<u8, u16>(buffer);
|
||||
|
||||
if (to_decode.len() * 2) != buffer_u16.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
|
||||
}
|
||||
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => 8,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode.buffer().iter().map(|px| {
|
||||
(*px as u16) << factor
|
||||
}).interweave::<0>(default_alpha, false).enumerate()
|
||||
.for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*buffer_u16.get_unchecked_mut(len) = data;
|
||||
}
|
||||
}); Ok(())
|
||||
|
||||
}
|
||||
fmt => Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(fmt))
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*temp_buffer.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
FrameFormat::Luma_10 => convert_u16_type_buffers(to_decode, buffer, destination_format, self.config().mode, self.config().channel_filters, 10),
|
||||
FrameFormat::Luma_12 => convert_u16_type_buffers(to_decode, buffer, destination_format, self.config().mode, self.config().channel_filters, 12),
|
||||
FrameFormat::Luma_14 => convert_u16_type_buffers(to_decode, buffer, destination_format, self.config().mode, self.config().channel_filters, 14),
|
||||
FrameFormat::Luma_16 | FrameFormat::Depth_16 => convert_u16_type_buffers(to_decode, buffer, destination_format, self.config().mode, self.config().channel_filters, 16),
|
||||
fmt => {
|
||||
Err(NokhwaError::DecoderUnsupportedFrameFormat(fmt))
|
||||
}
|
||||
PixelDestination::Luma16 => {
|
||||
let buffer_u16 = cast_slice_mut::<u8, u16>(buffer);
|
||||
|
||||
if to_decode.len() != buffer_u16.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => 8,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.map(|px| (*px as u16) << factor)
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*buffer_u16.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::LumaA16 => {
|
||||
let default_alpha = u16::MAX * a_u16;
|
||||
let buffer_u16 = cast_slice_mut::<u8, u16>(buffer);
|
||||
|
||||
if (to_decode.len() * 2) != buffer_u16.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"Lengths differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match self.config().mode {
|
||||
ConvertMode::Scaled => 8,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode
|
||||
.buffer()
|
||||
.iter()
|
||||
.map(|px| (*px as u16) << factor)
|
||||
.interweave::<0>(default_alpha, false)
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*buffer_u16.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
fmt => Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(fmt)),
|
||||
},
|
||||
FrameFormat::Luma_10 => convert_u16_type_buffers(
|
||||
to_decode,
|
||||
buffer,
|
||||
destination_format,
|
||||
self.config().mode,
|
||||
self.config().channel_filters,
|
||||
10,
|
||||
),
|
||||
FrameFormat::Luma_12 => convert_u16_type_buffers(
|
||||
to_decode,
|
||||
buffer,
|
||||
destination_format,
|
||||
self.config().mode,
|
||||
self.config().channel_filters,
|
||||
12,
|
||||
),
|
||||
FrameFormat::Luma_14 => convert_u16_type_buffers(
|
||||
to_decode,
|
||||
buffer,
|
||||
destination_format,
|
||||
self.config().mode,
|
||||
self.config().channel_filters,
|
||||
14,
|
||||
),
|
||||
FrameFormat::Luma_16 | FrameFormat::Depth_16 => convert_u16_type_buffers(
|
||||
to_decode,
|
||||
buffer,
|
||||
destination_format,
|
||||
self.config().mode,
|
||||
self.config().channel_filters,
|
||||
16,
|
||||
),
|
||||
fmt => Err(NokhwaError::DecoderUnsupportedFrameFormat(fmt)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn filter_to_u8(filter: bool) -> u8 {
|
||||
if filter {
|
||||
1_u8
|
||||
} else {
|
||||
0_u8
|
||||
}
|
||||
if filter { 1_u8 } else { 0_u8 }
|
||||
}
|
||||
|
||||
|
||||
fn filter_to_u16(filter: bool) -> u16 {
|
||||
if filter {
|
||||
1_u16
|
||||
} else {
|
||||
0_u16
|
||||
}
|
||||
if filter { 1_u16 } else { 0_u16 }
|
||||
}
|
||||
|
||||
fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint: PixelDestination, mode: ConvertMode, channel_filters: ChannelFilters, original_bit_num: u32) -> Result<(), NokhwaError> {
|
||||
fn convert_u16_type_buffers(
|
||||
to_decode: FrameBuffer,
|
||||
destination: &mut [u8],
|
||||
hint: PixelDestination,
|
||||
mode: ConvertMode,
|
||||
channel_filters: ChannelFilters,
|
||||
original_bit_num: u32,
|
||||
) -> Result<(), NokhwaError> {
|
||||
let r_u16 = filter_to_u16(channel_filters.red);
|
||||
let g_u16 = filter_to_u16(channel_filters.green);
|
||||
let b_u16 = filter_to_u16(channel_filters.blue);
|
||||
@@ -279,23 +337,22 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
|
||||
let to_decode_u16 = cast_slice::<u8, u16>(to_decode.buffer());
|
||||
|
||||
if to_decode_u16.len() != destination.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match mode {
|
||||
ConvertMode::Scaled => {
|
||||
original_bit_num - 8_u32
|
||||
}
|
||||
ConvertMode::Scaled => original_bit_num - 8_u32,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode_u16.iter().map(|px| {
|
||||
(*px >> factor) as u8
|
||||
}).enumerate()
|
||||
.for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*destination.get_unchecked_mut(len) = data;
|
||||
}
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.map(|px| (*px >> factor) as u8)
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -303,23 +360,23 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
|
||||
let to_decode_u16 = cast_slice::<u8, u16>(to_decode.buffer());
|
||||
|
||||
if (to_decode_u16.len() * 2) != destination.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match mode {
|
||||
ConvertMode::Scaled => {
|
||||
original_bit_num - 8_u32
|
||||
}
|
||||
ConvertMode::Scaled => original_bit_num - 8_u32,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode_u16.iter().map(|px| {
|
||||
(*px >> factor) as u8
|
||||
}).interweave::<0>(255 * a, false).enumerate()
|
||||
.for_each(|(len, data)| {
|
||||
unsafe {
|
||||
*destination.get_unchecked_mut(len) = data;
|
||||
}
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.map(|px| (*px >> factor) as u8)
|
||||
.interweave::<0>(255 * a, false)
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination.get_unchecked_mut(len) = data;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -327,53 +384,61 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
|
||||
let to_decode_u16 = cast_slice::<u8, u16>(to_decode.buffer());
|
||||
|
||||
if (to_decode_u16.len() * 3) != destination.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match mode {
|
||||
ConvertMode::Scaled => {
|
||||
original_bit_num - 8_u32
|
||||
}
|
||||
ConvertMode::Scaled => original_bit_num - 8_u32,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode_u16.iter().duplicate_const::<3>().arrays::<3>().flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor)* b_u16;
|
||||
[px_r as u8, px_g as u8, px_b as u8]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16;
|
||||
[px_r as u8, px_g as u8, px_b as u8]
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination.get_unchecked_mut(len) = data;
|
||||
}
|
||||
});
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgba8 => {
|
||||
let to_decode_u16 = cast_slice::<u8, u16>(to_decode.buffer());
|
||||
|
||||
if (to_decode_u16.len() * 4) != destination.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match mode {
|
||||
ConvertMode::Scaled => {
|
||||
original_bit_num - 8_u32
|
||||
}
|
||||
ConvertMode::Scaled => original_bit_num - 8_u32,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode_u16.iter().duplicate_const::<3>().arrays::<3>().flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16 ;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16 ;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16 ;
|
||||
let px_a = u8::MAX * a;
|
||||
[px_r as u8, px_g as u8, px_b as u8, px_a]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16;
|
||||
let px_a = u8::MAX * a;
|
||||
[px_r as u8, px_g as u8, px_b as u8, px_a]
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination.get_unchecked_mut(len) = data;
|
||||
}
|
||||
});
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgb16 => {
|
||||
@@ -381,26 +446,30 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
|
||||
let destination_buffer_u16 = cast_slice_mut::<u8, u16>(destination);
|
||||
|
||||
if (to_decode_u16.len() * 3) != destination_buffer_u16.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match mode {
|
||||
ConvertMode::Scaled => {
|
||||
original_bit_num - 8_u32
|
||||
}
|
||||
ConvertMode::Scaled => original_bit_num - 8_u32,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode_u16.iter().duplicate_const::<3>().arrays::<3>().flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16;
|
||||
[px_r, px_g, px_b]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16;
|
||||
[px_r, px_g, px_b]
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination_buffer_u16.get_unchecked_mut(len) = data;
|
||||
}
|
||||
});
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Rgba16 => {
|
||||
@@ -408,63 +477,68 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
|
||||
let destination_buffer_u16 = cast_slice_mut::<u8, u16>(destination);
|
||||
|
||||
if (to_decode_u16.len() * 3) != destination_buffer_u16.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let factor = match mode {
|
||||
ConvertMode::Scaled => {
|
||||
original_bit_num - 8_u32
|
||||
}
|
||||
ConvertMode::Scaled => original_bit_num - 8_u32,
|
||||
ConvertMode::Clipped => 0,
|
||||
};
|
||||
|
||||
to_decode_u16.iter().duplicate_const::<3>().arrays::<3>().flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16;
|
||||
let px_a = u16::MAX * a_u16;
|
||||
[px_r, px_g, px_b, px_a]
|
||||
}).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.duplicate_const::<3>()
|
||||
.arrays::<3>()
|
||||
.flat_map(|px| {
|
||||
let px_r = (*px[0_usize] >> factor) * r_u16;
|
||||
let px_g = (*px[1_usize] >> factor) * g_u16;
|
||||
let px_b = (*px[2_usize] >> factor) * b_u16;
|
||||
let px_a = u16::MAX * a_u16;
|
||||
[px_r, px_g, px_b, px_a]
|
||||
})
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination_buffer_u16.get_unchecked_mut(len) = data;
|
||||
}
|
||||
});
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::Luma16 => {
|
||||
if to_decode.len() != destination.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
match to_decode.consume().0 {
|
||||
Cow::Borrowed(data) => {
|
||||
destination.copy_from_slice(data)
|
||||
}
|
||||
Cow::Owned(mut owned) => {
|
||||
destination.swap_with_slice(owned.as_mut_slice())
|
||||
}
|
||||
Cow::Borrowed(data) => destination.copy_from_slice(data),
|
||||
Cow::Owned(mut owned) => destination.swap_with_slice(owned.as_mut_slice()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
PixelDestination::LumaA16 => {
|
||||
if (to_decode.len() * 2) != destination.len() {
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("sizes differ!".to_string()))
|
||||
return Err(NokhwaError::DecoderInvalidBuffer(
|
||||
"sizes differ!".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let to_decode_u16 = cast_slice::<u8, u16>(to_decode.buffer());
|
||||
let destination_buffer_u16 = cast_slice_mut::<u8, u16>(destination);
|
||||
|
||||
to_decode_u16.iter().interweave::<0>(&(u16::MAX * a_u16), false).enumerate().for_each(|(len, data)| {
|
||||
unsafe {
|
||||
to_decode_u16
|
||||
.iter()
|
||||
.interweave::<0>(&(u16::MAX * a_u16), false)
|
||||
.enumerate()
|
||||
.for_each(|(len, data)| unsafe {
|
||||
*destination_buffer_u16.get_unchecked_mut(len) = *data;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(hint))
|
||||
_ => Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(hint)),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -487,7 +561,7 @@ impl TryFrom<CameraFormat> for LumaConfig {
|
||||
|
||||
fn try_from(value: CameraFormat) -> Result<Self, Self::Error> {
|
||||
if !FrameFormat::BRIGHTNESS_LUMA.contains(&value.format()) {
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(value.format()))
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(value.format()));
|
||||
}
|
||||
|
||||
Ok(LumaConfig {
|
||||
@@ -504,7 +578,7 @@ impl TryFrom<CameraFormat> for LumaConfig {
|
||||
pub enum ConvertMode {
|
||||
#[default]
|
||||
Scaled,
|
||||
Clipped
|
||||
Clipped,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
|
||||
@@ -525,3 +599,9 @@ impl Default for ChannelFilters {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
pub fn luma8() {}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,44 @@
|
||||
use nokhwa_core::decoder::{ConfigHasResolution, Decoder, ImageBuffer, Pixel};
|
||||
use nokhwa_core::decoder::{ConfigHasResolution, Decoder};
|
||||
use nokhwa_core::error::NokhwaError;
|
||||
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||
use nokhwa_core::image::Primitive;
|
||||
use nokhwa_core::image::{DecodedImage, NonFloatScalarWidth};
|
||||
use nokhwa_core::types::Resolution;
|
||||
use nokhwa_core::frame_format::FrameFormat;
|
||||
use nokhwa_core::pixel_destination::PixelDestination;
|
||||
use nokhwa_core::types::{CameraFormat, Resolution};
|
||||
use zune_core::bytestream::ZCursor;
|
||||
use zune_core::colorspace::ColorSpace;
|
||||
pub use zune_core::options::DecoderOptions;
|
||||
pub use zune_jpeg::ImageInfo;
|
||||
use zune_jpeg::JpegDecoder;
|
||||
use zune_jpeg::errors::DecodeErrors;
|
||||
use nokhwa_core::pixel_destination::PixelDestination;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MJpegDecoder {
|
||||
config: MJpegOptions,
|
||||
config: MJpegConfig,
|
||||
}
|
||||
|
||||
impl MJpegDecoder {
|
||||
pub fn new(config: MJpegConfig) -> Self {
|
||||
MJpegDecoder { config }
|
||||
}
|
||||
|
||||
pub fn from_camera_format(camera_format: CameraFormat) -> Result<Self, NokhwaError> {
|
||||
let resolution = camera_format.resolution();
|
||||
if camera_format.format() != FrameFormat::MJPEG {
|
||||
return Err(NokhwaError::DecoderInvalidFrameData(
|
||||
"Not MJPEG!".to_string(),
|
||||
));
|
||||
}
|
||||
let decoder_options = DecoderOptions::new_safe();
|
||||
let config = MJpegConfig {
|
||||
resolution,
|
||||
decoder_options,
|
||||
};
|
||||
Ok(MJpegDecoder { config })
|
||||
}
|
||||
}
|
||||
|
||||
impl Decoder for MJpegDecoder {
|
||||
type Config = MJpegOptions;
|
||||
type Config = MJpegConfig;
|
||||
type OutputMeta = ImageMeta;
|
||||
const SUPPORTED_DESTINATIONS: &'static [PixelDestination] = &[
|
||||
PixelDestination::Rgb8,
|
||||
@@ -49,9 +69,14 @@ impl Decoder for MJpegDecoder {
|
||||
|
||||
let mut decoder = JpegDecoder::new(cursor);
|
||||
|
||||
let colorspace = convert_destination_to_colorspace(destination_format).ok_or(NokhwaError::DecoderUnsupportedDestinationPixelFormat(destination_format))?;
|
||||
let colorspace = convert_destination_to_colorspace(destination_format).ok_or(
|
||||
NokhwaError::DecoderUnsupportedDestinationPixelFormat(destination_format),
|
||||
)?;
|
||||
|
||||
let config = self.config.decoder_options.jpeg_set_out_colorspace(colorspace);
|
||||
let config = self
|
||||
.config
|
||||
.decoder_options
|
||||
.jpeg_set_out_colorspace(colorspace);
|
||||
|
||||
decoder.set_options(config);
|
||||
decoder.decode_into(buffer).map_err(err_to_err)?;
|
||||
@@ -67,28 +92,6 @@ impl Decoder for MJpegDecoder {
|
||||
|
||||
Ok(info.into())
|
||||
}
|
||||
|
||||
fn decode<P: Pixel>(
|
||||
&mut self,
|
||||
to_decode: FrameBuffer,
|
||||
) -> Result<DecodedImage<P, Self::OutputMeta>, NokhwaError>
|
||||
where
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth,
|
||||
{
|
||||
let min_size = self.output_decoder_min_size_pixel::<P>(self.config.resolution)?;
|
||||
let mut out_buffer: Vec<P::Subpixel> = vec![P::Subpixel::DEFAULT_MAX_VALUE; min_size];
|
||||
let output_metadata =
|
||||
self.decode_to_pixel_buffer::<P>(to_decode, out_buffer.as_mut_slice())?;
|
||||
let image_buffer = ImageBuffer::from_raw(
|
||||
output_metadata.resolution.width(),
|
||||
output_metadata.resolution.height(),
|
||||
out_buffer,
|
||||
)
|
||||
.ok_or(NokhwaError::Decoder(
|
||||
"Failed to make imagebuffer".to_string(),
|
||||
))?;
|
||||
Ok(DecodedImage::new(image_buffer, output_metadata))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@@ -115,12 +118,12 @@ impl From<ImageInfo> for ImageMeta {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct MJpegOptions {
|
||||
pub struct MJpegConfig {
|
||||
pub resolution: Resolution,
|
||||
pub decoder_options: DecoderOptions,
|
||||
}
|
||||
|
||||
impl ConfigHasResolution for MJpegOptions {
|
||||
impl ConfigHasResolution for MJpegConfig {
|
||||
fn resolution(&self) -> Resolution {
|
||||
self.resolution
|
||||
}
|
||||
@@ -170,3 +173,49 @@ fn convert_destination_to_colorspace(pixel_destination: PixelDestination) -> Opt
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read},
|
||||
};
|
||||
|
||||
use image::{DynamicImage, ImageFormat, Rgb};
|
||||
use nokhwa_core::{decoder::Decoder, frame_buffer::FrameBuffer, types::Resolution};
|
||||
use zune_core::options::DecoderOptions;
|
||||
|
||||
use crate::mjpeg::{MJpegConfig, MJpegDecoder};
|
||||
|
||||
fn load_image(filename: String, format: ImageFormat) -> DynamicImage {
|
||||
let file = File::open(filename).unwrap();
|
||||
let image = image::load(BufReader::new(file), format).unwrap();
|
||||
image
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn decode_mjpeg_rgb8() {
|
||||
let mut source_file = File::open("test_images/mjpeg/iwillquit.mjpeg").unwrap();
|
||||
let mut data = Vec::new();
|
||||
|
||||
let test_image = load_image(
|
||||
"test_images/mjpeg/iwillquit.rgb8.png".to_string(),
|
||||
ImageFormat::Png,
|
||||
)
|
||||
.to_rgb8();
|
||||
source_file.read_to_end(&mut data).unwrap();
|
||||
let resolution = Resolution::new(1044, 409);
|
||||
let decoder_options = DecoderOptions::new_fast();
|
||||
let config = MJpegConfig {
|
||||
resolution,
|
||||
decoder_options,
|
||||
};
|
||||
|
||||
let decode_buffer = FrameBuffer::from(data);
|
||||
|
||||
let mut decoder = MJpegDecoder::new(config);
|
||||
let out = decoder.decode::<Rgb<u8>>(decode_buffer).unwrap();
|
||||
|
||||
assert_eq!(out.as_raw(), test_image.as_raw());
|
||||
}
|
||||
}
|
||||
|
||||
+615
-198
@@ -1,10 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
use bytemuck::{cast_slice, cast_slice_mut};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use nokhwa_core::decoder::{ConfigHasResolution, Decoder};
|
||||
use nokhwa_core::error::NokhwaError;
|
||||
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||
use nokhwa_core::frame_format::{CustomFrameFormat, FrameFormat};
|
||||
use nokhwa_core::pixel_destination::PixelDestination;
|
||||
use nokhwa_core::types::{CameraFormat, Resolution};
|
||||
use yuv::{
|
||||
YuvBiPlanarImage, YuvConversionMode, YuvPackedImage, YuvPlanarImage, YuvRange,
|
||||
@@ -21,7 +22,6 @@ use yuv::{
|
||||
yuyv422_to_rgb, yuyv422_to_rgb_p16, yuyv422_to_rgba, yuyv422_to_rgba_p16, yvyu422_to_bgr,
|
||||
yvyu422_to_bgra, yvyu422_to_rgb, yvyu422_to_rgb_p16, yvyu422_to_rgba, yvyu422_to_rgba_p16,
|
||||
};
|
||||
use nokhwa_core::pixel_destination::PixelDestination;
|
||||
|
||||
pub struct YUVDecoder {
|
||||
config: YUVConfig,
|
||||
@@ -53,11 +53,14 @@ impl Decoder for YUVDecoder {
|
||||
}
|
||||
|
||||
if let Some(custom_map) = &config.custom_frame_format_map
|
||||
&& let Some((src, dest)) = custom_map.iter().find(|(_, value)| {
|
||||
FrameFormat::YCBCR.contains(value)
|
||||
}) {
|
||||
return Err(NokhwaError::DecoderUnsupportedCustomFrameFormatDestination(*src, *dest))
|
||||
}
|
||||
&& let Some((src, dest)) = custom_map
|
||||
.iter()
|
||||
.find(|(_, value)| FrameFormat::YCBCR.contains(value))
|
||||
{
|
||||
return Err(NokhwaError::DecoderUnsupportedCustomFrameFormatDestination(
|
||||
*src, *dest,
|
||||
));
|
||||
}
|
||||
|
||||
self.config = config;
|
||||
Ok(())
|
||||
@@ -69,27 +72,29 @@ impl Decoder for YUVDecoder {
|
||||
mut buffer: impl AsMut<[u8]>,
|
||||
destination_format: PixelDestination,
|
||||
) -> Result<Self::OutputMeta, NokhwaError> {
|
||||
let format = self.config().custom_frame_format_map.as_ref().and_then(|m| {
|
||||
match self.config().yuv_type {
|
||||
FrameFormat::Custom(cfmt) => {
|
||||
m.get(&cfmt).copied()
|
||||
}
|
||||
let format = self
|
||||
.config()
|
||||
.custom_frame_format_map
|
||||
.as_ref()
|
||||
.and_then(|m| match self.config().yuv_type {
|
||||
FrameFormat::Custom(cfmt) => m.get(&cfmt).copied(),
|
||||
_ => None,
|
||||
}
|
||||
}).unwrap_or(self.config().yuv_type);
|
||||
|
||||
})
|
||||
.unwrap_or(self.config().yuv_type);
|
||||
|
||||
let buffer = buffer.as_mut();
|
||||
if buffer.len() < self.output_decoder_min_size(self.config.resolution, destination_format)? {
|
||||
if buffer.len()
|
||||
< self.output_decoder_min_size(self.config.resolution, destination_format)?
|
||||
{
|
||||
return Err(NokhwaError::DecoderInvalidBuffer("Too small!".to_string()));
|
||||
}
|
||||
|
||||
let stride = figure_out_stride(format).ok_or(NokhwaError::DecoderUnsupportedFrameFormat(format))?;
|
||||
let byte_width = figure_out_byte_width(format).ok_or(NokhwaError::DecoderUnsupportedFrameFormat(format))?;
|
||||
let stride =
|
||||
figure_out_stride(format).ok_or(NokhwaError::DecoderUnsupportedFrameFormat(format))?;
|
||||
let byte_width = figure_out_byte_width(format)
|
||||
.ok_or(NokhwaError::DecoderUnsupportedFrameFormat(format))?;
|
||||
|
||||
|
||||
let stride_3px = 3 *
|
||||
self.config.resolution.width();
|
||||
let stride_3px = 3 * self.config.resolution.width();
|
||||
let stride_4px = 4 * self.config.resolution.width();
|
||||
let stride_3px_2w = 6 * self.config.resolution.width();
|
||||
let stride_4px_2w = 8 * self.config.resolution.width();
|
||||
@@ -99,169 +104,573 @@ impl Decoder for YUVDecoder {
|
||||
Stride::Packed(stride) => {
|
||||
let image = prepare_to_packed_image(&to_decode, self.config.resolution, stride);
|
||||
match format {
|
||||
FrameFormat::Ayuv_32 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(ayuv_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.premultiply_alpha)),
|
||||
PixelDestination::Rgba8 => Some(ayuv_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.premultiply_alpha)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::Yuyv_4_2_2 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuyv422_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba8 => Some(yuyv422_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgb16 => Some(yuyv422_to_rgb_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba16 => Some(yuyv422_to_rgba_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgr8 => Some(yuyv422_to_bgr(&image, buffer, stride_4px_2w, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgra8 => Some(yuyv422_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::Uyvy_4_2_2 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(uyvy422_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba8 => Some(uyvy422_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgb16 => Some(uyvy422_to_rgb_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba16 => Some(uyvy422_to_rgba_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgr8 => Some(uyvy422_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgra8 => Some(uyvy422_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::Vyuy_4_2_2 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(vyuy422_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba8 => Some(vyuy422_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgb16 => Some(vyuy422_to_rgb_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba16 => Some(vyuy422_to_rgba_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgr8 => Some(vyuy422_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgra8 => Some(vyuy422_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::Yvyu_4_2_2 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yvyu422_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba8 => Some(yvyu422_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgb16 => Some(yvyu422_to_rgb_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba16 => Some(yvyu422_to_rgba_p16(&convert_packed_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, 16, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgr8 => Some(yvyu422_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgra8 => Some(yvyu422_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::Ayuv_32 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(ayuv_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.premultiply_alpha,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(ayuv_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.premultiply_alpha,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::Yuyv_4_2_2 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuyv422_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuyv422_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgb16 => Some(yuyv422_to_rgb_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba16 => Some(yuyv422_to_rgba_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuyv422_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px_2w,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuyv422_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::Uyvy_4_2_2 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(uyvy422_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(uyvy422_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgb16 => Some(uyvy422_to_rgb_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba16 => Some(uyvy422_to_rgba_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(uyvy422_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(uyvy422_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::Vyuy_4_2_2 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(vyuy422_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(vyuy422_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgb16 => Some(vyuy422_to_rgb_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba16 => Some(vyuy422_to_rgba_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(vyuy422_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(vyuy422_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::Yvyu_4_2_2 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yvyu422_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yvyu422_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgb16 => Some(yvyu422_to_rgb_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba16 => Some(yvyu422_to_rgba_p16(
|
||||
&convert_packed_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
16,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yvyu422_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yvyu422_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
_ => {
|
||||
if FrameFormat::YCBCR_PACKED.contains(&self.config.yuv_type) {
|
||||
return Err(NokhwaError::NotImplementedError("etto blehhh! ()".to_string()))
|
||||
return Err(NokhwaError::NotImplementedError(
|
||||
"etto blehhh! ()".to_string(),
|
||||
));
|
||||
}
|
||||
// shouldnt happen
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format))
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
Stride::Semi(y_stride, uv_stride) => {
|
||||
let image = prepare_to_semi_planar_image(&to_decode, self.config.resolution, byte_width, y_stride, uv_stride);
|
||||
let image = prepare_to_semi_planar_image(
|
||||
&to_decode,
|
||||
self.config.resolution,
|
||||
byte_width,
|
||||
y_stride,
|
||||
uv_stride,
|
||||
);
|
||||
match format {
|
||||
FrameFormat::NV24 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv24_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv24_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv24_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv24_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::NV42 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv42_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv42_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv42_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv42_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::NV16 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv16_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv16_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv16_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv16_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::NV61 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv61_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv61_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv61_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv61_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::NV12 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv12_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv12_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv12_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv12_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::NV21 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv21_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv21_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv21_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv21_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::NV24 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv24_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv24_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv24_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv24_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::NV42 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv42_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv42_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv42_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv42_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::NV16 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv16_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv16_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv16_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv16_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::NV61 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv61_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv61_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv61_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv61_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::NV12 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv12_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv12_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv12_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv12_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::NV21 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv_nv21_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv_nv21_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv_nv21_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv_nv21_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
FrameFormat::P010 => {
|
||||
let a = convert_bi_planar_image_to_u16(image);
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(p010_to_rgb(&a, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgba8 => Some(p010_to_rgba(&a, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgr8 => Some(p010_to_bgr(&a, buffer, stride_3px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Bgra8 => Some(p010_to_bgra(&a, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
|
||||
PixelDestination::Rgb16 => Some(p010_to_rgb10(&a, cast_slice_mut(buffer), stride_3px_2w, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba16 => Some(p010_to_rgba10(&a, cast_slice_mut(buffer), stride_4px, self.config.range, self.config.matrix)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::P012 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb16 => Some(p012_to_rgb12(&convert_bi_planar_image_to_u16(image), cast_slice_mut(buffer), stride_3px_2w, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba16 => Some(p012_to_rgba12(&convert_bi_planar_image_to_u16(image), cast_slice_mut(buffer), stride_4px_2w, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgb8 => Some(p010_to_rgb(
|
||||
&a,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(p010_to_rgba(
|
||||
&a,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(p010_to_bgr(
|
||||
&a,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(p010_to_bgra(
|
||||
&a,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
self.config.mode,
|
||||
)),
|
||||
PixelDestination::Rgb16 => Some(p010_to_rgb10(
|
||||
&a,
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba16 => Some(p010_to_rgba10(
|
||||
&a,
|
||||
cast_slice_mut(buffer),
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::P012 => match destination_format {
|
||||
PixelDestination::Rgb16 => Some(p012_to_rgb12(
|
||||
&convert_bi_planar_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_3px_2w,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba16 => Some(p012_to_rgba12(
|
||||
&convert_bi_planar_image_to_u16(image),
|
||||
cast_slice_mut(buffer),
|
||||
stride_4px_2w,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
_ => {
|
||||
if FrameFormat::YCBCR_SEMI.contains(&format) {
|
||||
return Err(NokhwaError::NotImplementedError("etto blehhh!".to_string()))
|
||||
return Err(NokhwaError::NotImplementedError(
|
||||
"etto blehhh!".to_string(),
|
||||
));
|
||||
}
|
||||
// shouldnt happen
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format))
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
Stride::Planar(y_stride, u_stride, v_stride, line_ratio) => {
|
||||
let image = prepare_to_planar_image(&to_decode, self.config.resolution, byte_width, y_stride, u_stride, v_stride, line_ratio);
|
||||
let image = prepare_to_planar_image(
|
||||
&to_decode,
|
||||
self.config.resolution,
|
||||
byte_width,
|
||||
y_stride,
|
||||
u_stride,
|
||||
v_stride,
|
||||
line_ratio,
|
||||
);
|
||||
match format {
|
||||
FrameFormat::Yuv_4_2_0 => {
|
||||
match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv420_to_rgb(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Rgba8 => Some(yuv420_to_rgba(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgr8 => Some(yuv420_to_bgr(&image, buffer, stride_3px, self.config.range, self.config.matrix)),
|
||||
PixelDestination::Bgra8 => Some(yuv420_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
FrameFormat::Yuv_4_2_0 => match destination_format {
|
||||
PixelDestination::Rgb8 => Some(yuv420_to_rgb(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Rgba8 => Some(yuv420_to_rgba(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgr8 => Some(yuv420_to_bgr(
|
||||
&image,
|
||||
buffer,
|
||||
stride_3px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
PixelDestination::Bgra8 => Some(yuv420_to_bgra(
|
||||
&image,
|
||||
buffer,
|
||||
stride_4px,
|
||||
self.config.range,
|
||||
self.config.matrix,
|
||||
)),
|
||||
_ => None,
|
||||
},
|
||||
_ => {
|
||||
if FrameFormat::YCBCR_PLANAR.contains(&format) {
|
||||
return Err(NokhwaError::NotImplementedError("etto blehhh!".to_string()))
|
||||
return Err(NokhwaError::NotImplementedError(
|
||||
"etto blehhh!".to_string(),
|
||||
));
|
||||
}
|
||||
// shouldnt happen
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format))
|
||||
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,9 +678,7 @@ impl Decoder for YUVDecoder {
|
||||
match decode_status {
|
||||
Some(Ok(_)) => Ok(()),
|
||||
Some(Err(why)) => Err(NokhwaError::Decoder(why.to_string())),
|
||||
None => Err(NokhwaError::DecoderUnsupportedFrameFormat(
|
||||
format,
|
||||
)),
|
||||
None => Err(NokhwaError::DecoderUnsupportedFrameFormat(format)),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,11 +744,17 @@ fn figure_out_stride(frame_format: FrameFormat) -> Option<Stride> {
|
||||
|
||||
fn figure_out_byte_width(format: FrameFormat) -> Option<u32> {
|
||||
match format {
|
||||
FrameFormat::Ayuv_32 | FrameFormat::Yuyv_4_2_2
|
||||
FrameFormat::Ayuv_32
|
||||
| FrameFormat::Yuyv_4_2_2
|
||||
| FrameFormat::Uyvy_4_2_2
|
||||
| FrameFormat::Vyuy_4_2_2
|
||||
| FrameFormat::Yvyu_4_2_2 => Some(1),
|
||||
FrameFormat::NV24 | FrameFormat::NV42 | FrameFormat::NV16 | FrameFormat::NV61 | FrameFormat::NV12 | FrameFormat::NV21 => Some(1),
|
||||
FrameFormat::NV24
|
||||
| FrameFormat::NV42
|
||||
| FrameFormat::NV16
|
||||
| FrameFormat::NV61
|
||||
| FrameFormat::NV12
|
||||
| FrameFormat::NV21 => Some(1),
|
||||
FrameFormat::P010 | FrameFormat::P012 => Some(2),
|
||||
FrameFormat::Yuv_4_2_0 => Some(1),
|
||||
_ => None,
|
||||
@@ -427,7 +840,6 @@ fn prepare_to_planar_image<'a>(
|
||||
v_stride_ratio: u32,
|
||||
line_ratio: u32,
|
||||
) -> YuvPlanarImage<'a, u8> {
|
||||
|
||||
let y_stride = resolution.width() * y_stride_base;
|
||||
let u_stride = y_stride / u_stride_ratio;
|
||||
let v_stride = y_stride / v_stride_ratio;
|
||||
@@ -435,7 +847,7 @@ fn prepare_to_planar_image<'a>(
|
||||
|
||||
// size of y area
|
||||
let u_start = resolution.height() * resolution.width() * byte_width;
|
||||
let v_start = u_start + u_stride * chroma_lines * byte_width;
|
||||
let v_start = u_start + u_stride * chroma_lines * byte_width;
|
||||
|
||||
let us = u_start as usize;
|
||||
let vs = v_start as usize;
|
||||
@@ -480,7 +892,10 @@ fn convert_bi_planar_image_to_u16(
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::yuv::{YUVConfig, YUVDecoder};
|
||||
use image::{DynamicImage, EncodableLayout, ImageBuffer, ImageFormat, Pixel, PixelWithColorType, Rgb, Rgba};
|
||||
use image::{
|
||||
DynamicImage, EncodableLayout, ImageBuffer, ImageFormat, Pixel, PixelWithColorType, Rgb,
|
||||
Rgba,
|
||||
};
|
||||
use nokhwa_core::decoder::Decoder;
|
||||
use nokhwa_core::frame_buffer::FrameBuffer;
|
||||
use nokhwa_core::frame_format::FrameFormat;
|
||||
@@ -491,39 +906,38 @@ mod test {
|
||||
use std::io::{BufReader, Read};
|
||||
use yuv::{YuvConversionMode, YuvRange, YuvStandardMatrix};
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
enum PixelFormat {
|
||||
Rgb8,
|
||||
RgbA8,
|
||||
Rgb16,
|
||||
RgbA16,
|
||||
}
|
||||
|
||||
fn base_test<P: Pixel>(filename: String, resolution: Resolution, format: FrameFormat) -> ImageBuffer<P, Vec<P::Subpixel>>
|
||||
where
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth {
|
||||
fn base_test<P: Pixel>(
|
||||
filename: String,
|
||||
resolution: Resolution,
|
||||
format: FrameFormat,
|
||||
) -> ImageBuffer<P, Vec<P::Subpixel>>
|
||||
where
|
||||
<P as Pixel>::Subpixel: NonFloatScalarWidth,
|
||||
{
|
||||
let mut file = File::open(filename).unwrap();
|
||||
let mut nv12_data = Vec::new();
|
||||
file.read_to_end(&mut nv12_data).unwrap();
|
||||
|
||||
let mut decoder = YUVDecoder::new(
|
||||
YUVConfig {
|
||||
resolution,
|
||||
yuv_type: format,
|
||||
range: YuvRange::Full,
|
||||
matrix: YuvStandardMatrix::Bt601,
|
||||
mode: YuvConversionMode::Balanced,
|
||||
premultiply_alpha: false,
|
||||
custom_frame_format_map: None,
|
||||
}
|
||||
);
|
||||
let mut decoder = YUVDecoder::new(YUVConfig {
|
||||
resolution,
|
||||
yuv_type: format,
|
||||
range: YuvRange::Full,
|
||||
matrix: YuvStandardMatrix::Bt601,
|
||||
mode: YuvConversionMode::Balanced,
|
||||
premultiply_alpha: false,
|
||||
custom_frame_format_map: None,
|
||||
});
|
||||
|
||||
let frame_buffer = FrameBuffer::new(Cow::Owned(nv12_data), None);
|
||||
decoder.decode::<P>(frame_buffer).unwrap().buffer
|
||||
}
|
||||
|
||||
fn write_image<P: Pixel + PixelWithColorType>(image: ImageBuffer<P, Vec<P::Subpixel>>, filename: String) where
|
||||
[<P as Pixel>::Subpixel]: EncodableLayout
|
||||
#[allow(dead_code)]
|
||||
fn write_image<P: Pixel + PixelWithColorType>(
|
||||
image: ImageBuffer<P, Vec<P::Subpixel>>,
|
||||
filename: String,
|
||||
) where
|
||||
[<P as Pixel>::Subpixel]: EncodableLayout,
|
||||
{
|
||||
image.save_with_format(filename, ImageFormat::Png).unwrap();
|
||||
}
|
||||
@@ -533,7 +947,7 @@ where
|
||||
let image = image::load(BufReader::new(file), format).unwrap();
|
||||
image
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_nv12() {
|
||||
let base_filename = "test_images/yuv/nv12/crimeandsekai";
|
||||
@@ -550,7 +964,8 @@ where
|
||||
}
|
||||
// test nv12 rgba8
|
||||
{
|
||||
let image_rgba8 = load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let image_rgba8 =
|
||||
load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
|
||||
let out = base_test::<Rgba<u8>>(format!("{base_filename}.yuv"), resolution, format);
|
||||
|
||||
@@ -595,11 +1010,11 @@ where
|
||||
}
|
||||
|
||||
{
|
||||
let image_rgba8 = load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let image_rgba8 =
|
||||
load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let out = base_test::<Rgba<u8>>(format!("{base_filename}.yuv"), resolution, format);
|
||||
assert_eq!(image_rgba8.as_raw(), out.as_raw());
|
||||
// write_image(out, format!("{base_filename}.rgba8.png"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,7 +1033,8 @@ where
|
||||
}
|
||||
|
||||
{
|
||||
let image_rgba8 = load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let image_rgba8 =
|
||||
load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let out = base_test::<Rgba<u8>>(format!("{base_filename}.yuv"), resolution, format);
|
||||
assert_eq!(image_rgba8.as_raw(), out.as_raw());
|
||||
// write_image(out, format!("{base_filename}.rgba8.png"));
|
||||
@@ -640,7 +1056,8 @@ where
|
||||
}
|
||||
|
||||
{
|
||||
let image_rgba8 = load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let image_rgba8 =
|
||||
load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let out = base_test::<Rgba<u8>>(format!("{base_filename}.yuv"), resolution, format);
|
||||
assert_eq!(image_rgba8.as_raw(), out.as_raw());
|
||||
// write_image(out, format!("{base_filename}.rgba8.png"));
|
||||
@@ -669,7 +1086,8 @@ where
|
||||
}
|
||||
|
||||
{
|
||||
let image_rgba8 = load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let image_rgba8 =
|
||||
load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let out = base_test::<Rgba<u8>>(format!("{base_filename}.yuv"), resolution, format);
|
||||
// write_image(out, format!("{base_filename}.rgba8.png"));
|
||||
assert_eq!(image_rgba8.as_raw(), out.as_raw());
|
||||
@@ -690,11 +1108,10 @@ where
|
||||
}
|
||||
|
||||
{
|
||||
let image_rgba8 = load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let image_rgba8 =
|
||||
load_image(format!("{base_filename}.rgba8.png"), img_format).to_rgba8();
|
||||
let out = base_test::<Rgba<u8>>(format!("{base_filename}.yuv"), resolution, format);
|
||||
assert_eq!(image_rgba8.as_raw(), out.as_raw());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user