fix compile errors except for ffmpeg

This commit is contained in:
l1npengtul
2025-09-13 22:53:49 +09:00
parent 6db4a46e60
commit 5319e517d9
13 changed files with 279 additions and 410 deletions
+42 -9
View File
@@ -8,7 +8,7 @@ use bytemuck::try_cast_slice_mut;
use crate::pixel_destination::PixelDestination;
pub trait Decoder {
type Config: Clone + Debug;
type Config: Clone + Debug + ConfigHasResolution;
type OutputMeta: Clone + Debug;
const SUPPORTED_DESTINATIONS: &'static [PixelDestination];
@@ -27,10 +27,7 @@ pub trait Decoder {
where
<P as Pixel>::Subpixel: NonFloatScalarWidth
{
let destination = match PixelDestination::get_by_pixel::<P>() {
Some(dest) => dest,
None => 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))
@@ -43,13 +40,29 @@ pub trait Decoder {
self.decode_to_buffer(to_decode, cast_slice, destination)
}
fn decode<P: Pixel>(
&mut self,
to_decode: FrameBuffer,
to_decode: FrameBuffer<'_>,
) -> Result<DecodedImage<P, Self::OutputMeta>, NokhwaError>
where
<P as Pixel>::Subpixel: NonFloatScalarWidth;
<P as Pixel>::Subpixel: NonFloatScalarWidth,
{
let resolution = self.config().resolution();
let min_size_alloc = self.output_decoder_min_size_pixel::<P>(resolution)?;
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(),
))?,
meta,
))
}
fn output_decoder_min_size_pixel<P>(&self, resolution: Resolution) -> Result<usize, NokhwaError> where
P: Pixel,
@@ -58,9 +71,29 @@ pub trait Decoder {
}
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))
}
let px_size = match destination_format {
PixelDestination::Rgb8 | PixelDestination::Bgr8 => 3_u32,
PixelDestination::Rgba8 | PixelDestination::Bgra8 | PixelDestination::LumaA16 => 4_u32,
PixelDestination::Rgb16 | PixelDestination::Bgr16 => 3_u32 * 2_u32,
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))
}
#[must_use]
fn supports_destination(pixel_destination: PixelDestination) -> bool {
Self::SUPPORTED_DESTINATIONS.contains(&pixel_destination)
}
}
pub trait ConfigHasResolution {
fn resolution(&self) -> Resolution;
}
+1
View File
@@ -206,6 +206,7 @@ define_frame_format_with_groups! {
}
impl FrameFormat {
#[must_use]
pub fn is_custom(&self) -> bool {
if let FrameFormat::Custom(_) = self {
return true
+1
View File
@@ -19,6 +19,7 @@ pub enum PixelDestination {
}
impl PixelDestination {
#[must_use]
pub fn get_by_pixel<P>() -> Option<Self>
where
P: Pixel,
+1 -1
View File
@@ -165,7 +165,7 @@ impl<'a> StreamHandle<'a> {
return Err(NokhwaError::ReadFrameError(why));
}
}
Event::Error(e) => return Err(NokhwaError::ReadFrameError(e.to_string())),
Event::Error(e) => return Err(NokhwaError::ReadFrameError(e.clone())),
_ => {}
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ impl CameraIndex {
pub fn as_string(&self) -> String {
match self {
CameraIndex::Index(i) => i.to_string(),
CameraIndex::String(s) | CameraIndex::Stable(s) => s.to_string(),
CameraIndex::String(s) | CameraIndex::Stable(s) => s.clone(),
}
}
+3 -7
View File
@@ -7,8 +7,8 @@ edition = "2024"
ffmpeg = ["ffmpeg-the-third"]
yuyv = ["dcv-color-primitives", "yuv"]
mjpeg = ["zune-jpeg", "zune-core"]
luma = ["itertools", "nokhwa-iter-extensions", "itermore"]
#static = ["ffmpeg-the-third/static"]
luma = ["nokhwa-iter-extensions", "itermore"]
static = ["ffmpeg-the-third/static"]
#async = []
[dependencies]
@@ -19,7 +19,7 @@ version = "0.2"
path = "../nokhwa-core"
[dependencies.ffmpeg-the-third]
version = "4.0.0+ffmpeg-8.0"
version = "4.0.0"
optional = true
[dependencies.yuv]
@@ -38,10 +38,6 @@ optional = true
version = "0.5.0-rc2"
optional = true
[dependencies.itertools]
version = "0.14"
optional = true
[dependencies.itermore]
version = "0.8"
features = ["array_chunks"]
+12 -99
View File
@@ -12,11 +12,12 @@ use ffmpeg_the_third::ffi::{
use ffmpeg_the_third::packet::{Borrow, Ref};
use ffmpeg_the_third::{Frame, decoder, packet::Packet};
use nokhwa_core::codec::Codec;
use nokhwa_core::decoder::{Decoder, ImageBuffer, Pixel, Primitive};
use nokhwa_core::decoder::{ConfigHasResolution, Decoder, Pixel};
use nokhwa_core::error::NokhwaError;
use nokhwa_core::frame_buffer::FrameBuffer;
use nokhwa_core::frame_format::{CustomFrameFormat, FrameFormat};
use nokhwa_core::image::{DecodedImage, NonFloatScalarWidth};
use nokhwa_core::image::{NonFloatScalarWidth};
use nokhwa_core::pixel_destination::PixelDestination;
use nokhwa_core::types::{CameraFormat, FrameRate, Resolution};
pub struct FfmpegDecoder {
@@ -56,7 +57,8 @@ impl FfmpegDecoder {
impl Decoder for FfmpegDecoder {
type Config = <FfmpegCodec as Codec>::Config;
type OutputMeta = <FfmpegCodec as Codec>::WrittenMeta;
type DestinationFormatHint = AVPixelFormat;
const SUPPORTED_DESTINATIONS: &'static [PixelDestination] = &[];
fn config(&self) -> &Self::Config {
self.codec.config()
@@ -71,7 +73,7 @@ impl Decoder for FfmpegDecoder {
&mut self,
to_decode: FrameBuffer,
mut buffer: impl AsMut<[u8]>,
_destination_format: Option<Self::DestinationFormatHint>,
_destination_format: PixelDestination,
) -> Result<Self::OutputMeta, NokhwaError> {
// TODO: add an extra zippy happy path for rgb/bgr/luma
let (frame, metadata) = self.receive_decoded_frame(to_decode)?;
@@ -188,54 +190,6 @@ impl Decoder for FfmpegDecoder {
Ok(decoded_meta)
}
}
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 buffer: Vec<P::Subpixel> = vec![<P::Subpixel>::DEFAULT_MIN_VALUE; min_size];
let meta = self.decode_to_buffer(
to_decode,
try_cast_slice_mut(&mut buffer)
.map_err(|why| NokhwaError::DecoderInvalidBuffer(why.to_string()))?,
None,
)?;
Ok(DecodedImage::new(
ImageBuffer::from_vec(
self.codec.config.resolution.width(),
self.codec.config.resolution.height(),
buffer,
)
.ok_or(NokhwaError::Decoder(
"Failed to create Image Buffer".to_string(),
))?,
meta,
))
}
fn output_decoder_min_size(
&self,
resolution: Resolution,
destination_format: Self::DestinationFormatHint,
) -> usize {
let size = unsafe {
av_image_get_buffer_size(
destination_format,
resolution.width() as i32,
resolution.height() as i32,
1,
)
};
size as usize
}
fn buffer_takes_destination_hint(&self) -> bool {
false
}
}
fn create_sws_context(
@@ -261,53 +215,6 @@ fn create_sws_context(
Ok(new_sws)
}
fn pixel_to_destination_px_fmt<P: Pixel>() -> Option<AVPixelFormat>
where
<P as Pixel>::Subpixel: NonFloatScalarWidth,
{
match P::COLOR_MODEL {
"RGB" => match <<P as Pixel>::Subpixel>::WIDTH_BYTES {
1 => Some(AVPixelFormat::AV_PIX_FMT_RGB24),
_ => None,
},
"RGBA" => match <<P as Pixel>::Subpixel>::WIDTH_BYTES {
1 => Some(AVPixelFormat::AV_PIX_FMT_RGBA),
2 => Some(switch_endian(
AVPixelFormat::AV_PIX_FMT_RGBA64LE,
AVPixelFormat::AV_PIX_FMT_RGBA64BE,
)),
_ => None,
},
"BGR" => match <<P as Pixel>::Subpixel>::WIDTH_BYTES {
1 => Some(AVPixelFormat::AV_PIX_FMT_BGR24),
_ => None,
},
"BGRA" => match <<P as Pixel>::Subpixel>::WIDTH_BYTES {
1 => Some(AVPixelFormat::AV_PIX_FMT_BGRA),
2 => Some(switch_endian(
AVPixelFormat::AV_PIX_FMT_BGRA64LE,
AVPixelFormat::AV_PIX_FMT_BGRA64BE,
)),
_ => None,
},
"Y" => match <<P as Pixel>::Subpixel>::WIDTH_BYTES {
1 => Some(AVPixelFormat::AV_PIX_FMT_GRAY8),
2 => Some(switch_endian(
AVPixelFormat::AV_PIX_FMT_GRAY16LE,
AVPixelFormat::AV_PIX_FMT_GRAY16BE,
)),
_ => None,
},
"YA" => match <<P as Pixel>::Subpixel>::WIDTH_BYTES {
1 => Some(AVPixelFormat::AV_PIX_FMT_GRAY8A),
_ => None,
},
_ => None,
}
}
pub struct Sws {
pub sws: *mut SwsContext,
pub source_pixel_format: AVPixelFormat,
@@ -686,6 +593,12 @@ pub struct FfmpegDecoderConfig {
pub video_delay: i32,
}
impl ConfigHasResolution for FfmpegDecoderConfig {
fn resolution(&self) -> Resolution {
self.resolution
}
}
impl FfmpegDecoderConfig {
pub fn with_camera_format(camera_format: &CameraFormat) -> Self {
FfmpegDecoderConfig::from(*camera_format)
+117 -133
View File
@@ -1,20 +1,16 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt::Debug;
use std::mem::swap;
use bytemuck::{cast_mut, cast_slice, cast_slice_mut, try_cast_slice_mut};
use image::Pixel;
use itertools::Itertools;
use nokhwa_core::decoder::Decoder;
use bytemuck::{cast_slice, cast_slice_mut};
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::image::{DecodedImage, NonFloatScalarWidth};
use nokhwa_core::types::{CameraFormat, Resolution};
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};
#[derive(Clone, Debug, PartialEq)]
pub struct LumaDecoder {
@@ -44,29 +40,15 @@ impl Decoder for LumaDecoder {
Ok(())
}
fn decode_to_buffer(&mut self, mut to_decode: FrameBuffer, mut buffer: impl AsMut<[u8]>, destination_format: PixelDestination) -> Result<Self::OutputMeta, NokhwaError> {
let destination_hint = match destination_format {
Some(h) => h,
None => return Err(NokhwaError::DecoderDestinationHintRequired)
};
let (width, max_value) = match self.config().format {
FrameFormat::Luma_8 => (1, u8::MAX as u32),
FrameFormat::Luma_10 => (2, 2_u32.pow(10)),
FrameFormat::Luma_12 => (2, 2_u32.pow(12)),
FrameFormat::Luma_14 => (2, 2_u32.pow(14)),
FrameFormat::Luma_16 | FrameFormat::Depth_16 => (2, u16::MAX as u32),
fmt => return Err(NokhwaError::DecoderUnsupportedFrameFormat(fmt))
};
let format = self.config().custom_frame_format_map.as_ref().map(|m| {
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,
}
}).flatten().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);
@@ -82,18 +64,20 @@ impl Decoder for LumaDecoder {
match format {
FrameFormat::Luma_8 => {
match destination_hint {
match destination_format {
PixelDestination::Luma8 => {
if to_decode.len() != buffer.len() {
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
match to_decode.consume().0 {
Cow::Borrowed(data) => {
buffer.copy_from_slice(data)
buffer.copy_from_slice(data);
Ok(())
}
Cow::Owned(mut owned) => {
buffer.swap_with_slice(owned.as_mut_slice())
buffer.swap_with_slice(owned.as_mut_slice());
Ok(())
}
}
}
@@ -101,52 +85,56 @@ impl Decoder for LumaDecoder {
let default_alpha = u8::MAX * a;
if (to_decode.len() * 2) != buffer.len() {
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
to_decode.buffer().into_iter().interweave(&default_alpha, false).enumerate()
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!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
to_decode.buffer().into_iter().duplicate_const::<3>().arrays::<3>().map(|pixel| {
let px_r = &pixel[0_usize] * r;
let px_g = &pixel[1_usize] * g;
let px_b = &pixel[2_usize] * b;
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]
}).flatten().enumerate().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*buffer.get_unchecked_mut(len) = *data;
*buffer.get_unchecked_mut(len) = data;
}
});
Ok(())
}
PixelDestination::Rgba8 => {
if (to_decode.len() * 4) != buffer.len() {
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
to_decode.buffer().into_iter().duplicate_const::<3>().arrays::<3>().map(|pixel| {
let px_r = &pixel[0_usize] * r;
let px_g = &pixel[1_usize] * g;
let px_b = &pixel[2_usize] * b;
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]
}).flatten().enumerate().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*buffer.get_unchecked_mut(len) = *data;
*buffer.get_unchecked_mut(len) = data;
}
});
Ok(())
}
PixelDestination::Rgb16 => {
if (to_decode.len() * 6) != buffer.len() {
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
let temp_buffer = cast_slice_mut::<u8, u16>(buffer);
@@ -159,20 +147,21 @@ impl Decoder for LumaDecoder {
}
};
to_decode.buffer().into_iter().duplicate_const::<3>().arrays::<3>().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;
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]
}).flatten().enumerate().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*temp_buffer.get_unchecked_mut(len) = *data;
*temp_buffer.get_unchecked_mut(len) = data;
}
});
}); Ok(())
}
PixelDestination::Rgba16 => {
if (to_decode.len() * 8) != buffer.len() {
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
let temp_buffer = cast_slice_mut::<u8, u16>(buffer);
@@ -185,23 +174,24 @@ impl Decoder for LumaDecoder {
}
};
to_decode.buffer().into_iter().duplicate_const::<3>().arrays::<3>().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;
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]
}).flatten().enumerate().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*temp_buffer.get_unchecked_mut(len) = *data;
*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!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
let factor = match self.config().mode {
@@ -209,21 +199,22 @@ impl Decoder for LumaDecoder {
ConvertMode::Clipped => 0,
};
to_decode.buffer().into_iter().map(|px| {
to_decode.buffer().iter().map(|px| {
(*px as u16) << factor
}).enumerate()
.for_each(|(len, data)| {
unsafe {
*buffer_u16.get_unchecked_mut(len) = *data;
*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!"))
return Err(NokhwaError::DecoderInvalidBuffer("Lengths differ!".to_string()))
}
let factor = match self.config().mode {
@@ -231,38 +222,28 @@ impl Decoder for LumaDecoder {
ConvertMode::Clipped => 0,
};
to_decode.buffer().into_iter().map(|px| {
to_decode.buffer().iter().map(|px| {
(*px as u16) << factor
}).interweave(&default_alpha, false).enumerate()
}).interweave::<0>(default_alpha, false).enumerate()
.for_each(|(len, data)| {
unsafe {
*buffer_u16.get_unchecked_mut(len) = *data;
*buffer_u16.get_unchecked_mut(len) = data;
}
});
}); Ok(())
}
fmt => Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(fmt))
}
}
FrameFormat::Luma_10 => convert_u16_type_buffers(to_decode, buffer, destination_hint, self.config().mode, self.config().channel_filters, 10),
FrameFormat::Luma_12 => convert_u16_type_buffers(to_decode, buffer, destination_hint, self.config().mode, self.config().channel_filters, 12),
FrameFormat::Luma_14 => convert_u16_type_buffers(to_decode, buffer, destination_hint, self.config().mode, self.config().channel_filters, 14),
FrameFormat::Luma_16 | FrameFormat::Depth_16 => convert_u16_type_buffers(to_decode, buffer, destination_hint, self.config().mode, self.config().channel_filters, 16),
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 => {
return Err(NokhwaError::DecoderUnsupportedFrameFormat(fmt))
Err(NokhwaError::DecoderUnsupportedFrameFormat(fmt))
}
}
}
fn decode<P: Pixel>(&mut self, to_decode: FrameBuffer) -> Result<DecodedImage<P, Self::OutputMeta>, NokhwaError>
where
<P as Pixel>::Subpixel: NonFloatScalarWidth
{
todo!()
}
fn output_decoder_min_size(&self, resolution: Resolution, destination_format: PixelDestination) -> usize {
todo!()
}
}
fn filter_to_u8(filter: bool) -> u8 {
@@ -288,9 +269,9 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
let b_u16 = filter_to_u16(channel_filters.blue);
let a_u16 = filter_to_u16(channel_filters.alpha);
let r = filter_to_u8(channel_filters.red);
let g = filter_to_u8(channel_filters.green);
let b = filter_to_u8(channel_filters.blue);
// let r = filter_to_u8(channel_filters.red);
// let g = filter_to_u8(channel_filters.green);
// let b = filter_to_u8(channel_filters.blue);
let a = filter_to_u8(channel_filters.alpha);
match hint {
@@ -308,12 +289,12 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
ConvertMode::Clipped => 0,
};
to_decode_u16.into_iter().map(|px| {
to_decode_u16.iter().map(|px| {
(*px >> factor) as u8
}).enumerate()
.for_each(|(len, data)| {
unsafe {
*destination.get_unchecked_mut(len) = *data;
*destination.get_unchecked_mut(len) = data;
}
});
Ok(())
@@ -332,12 +313,12 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
ConvertMode::Clipped => 0,
};
to_decode_u16.into_iter().map(|px| {
to_decode_u16.iter().map(|px| {
(*px >> factor) as u8
}).interweave(255 * a, false).enumerate()
}).interweave::<0>(255 * a, false).enumerate()
.for_each(|(len, data)| {
unsafe {
*destination.get_unchecked_mut(len) = *data;
*destination.get_unchecked_mut(len) = data;
}
});
Ok(())
@@ -356,14 +337,14 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
ConvertMode::Clipped => 0,
};
to_decode_u16.into_iter().duplicate_const::<3>().array_chunks::<3>().map(|px| {
let px_r = (&px[0_usize] >> factor) * r;
let px_g = (&px[1_usize] >> factor) * g;
let px_b = (&px[2_usize] >> factor)* b;
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]
}).flatten().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*destination.get_unchecked_mut(len) = *data;
*destination.get_unchecked_mut(len) = data;
}
});
Ok(())
@@ -382,15 +363,15 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
ConvertMode::Clipped => 0,
};
to_decode_u16.into_iter().duplicate_const::<3>().array_chunks::<3>().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 ;
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]
}).flatten().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*destination.get_unchecked_mut(len) = *data;
*destination.get_unchecked_mut(len) = data;
}
});
Ok(())
@@ -410,14 +391,14 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
ConvertMode::Clipped => 0,
};
to_decode_u16.into_iter().duplicate_const::<3>().array_chunks::<3>().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;
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]
}).flatten().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*destination_buffer_u16.get_unchecked_mut(len) = *data;
*destination_buffer_u16.get_unchecked_mut(len) = data;
}
});
Ok(())
@@ -437,15 +418,15 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
ConvertMode::Clipped => 0,
};
to_decode_u16.into_iter().duplicate_const::<3>().array_chunks::<3>().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;
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]
}).flatten().for_each(|(len, data)| {
}).enumerate().for_each(|(len, data)| {
unsafe {
*destination_buffer_u16.get_unchecked_mut(len) = *data;
*destination_buffer_u16.get_unchecked_mut(len) = data;
}
});
Ok(())
@@ -473,9 +454,9 @@ fn convert_u16_type_buffers(to_decode: FrameBuffer, destination: &mut [u8], hint
let to_decode_u16 = cast_slice::<u8, u16>(to_decode.buffer());
let destination_buffer_u16 = cast_slice_mut::<u8, u16>(destination);
to_decode_u16.into_iter().interweave(&(u16::MAX * a_u16), false).enumerate().for_each(|(len, data)| {
to_decode_u16.iter().interweave::<0>(&(u16::MAX * a_u16), false).enumerate().for_each(|(len, data)| {
unsafe {
*destination.get_unchecked_mut(len) = *data;
*destination_buffer_u16.get_unchecked_mut(len) = *data;
}
});
@@ -491,38 +472,41 @@ pub struct LumaConfig {
pub mode: ConvertMode,
pub channel_filters: ChannelFilters,
pub format: FrameFormat,
pub custom_frame_format_map: Option<HashMap<CustomFrameFormat, FrameFormat>>
pub custom_frame_format_map: Option<HashMap<CustomFrameFormat, FrameFormat>>,
pub resolution: Resolution,
}
impl TryFrom<FrameFormat> for LumaConfig {
impl ConfigHasResolution for LumaConfig {
fn resolution(&self) -> Resolution {
self.resolution
}
}
impl TryFrom<CameraFormat> for LumaConfig {
type Error = NokhwaError;
fn try_from(value: FrameFormat) -> Result<Self, Self::Error> {
if !FrameFormat::BRIGHTNESS_LUMA.contains(&value) {
return Err(NokhwaError::DecoderUnsupportedFrameFormat(value))
fn try_from(value: CameraFormat) -> Result<Self, Self::Error> {
if !FrameFormat::BRIGHTNESS_LUMA.contains(&value.format()) {
return Err(NokhwaError::DecoderUnsupportedFrameFormat(value.format()))
}
Ok(LumaConfig {
mode: ConvertMode::default(),
channel_filters: ChannelFilters::default(),
format: value,
format: value.format(),
custom_frame_format_map: None,
resolution: value.resolution(),
})
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
#[derive(Copy, Clone, Default, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub enum ConvertMode {
#[default]
Scaled,
Clipped
}
impl Default for ConvertMode {
fn default() -> Self {
ConvertMode::Scaled
}
}
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct ChannelFilters {
pub red: bool,
+8 -19
View File
@@ -1,4 +1,4 @@
use nokhwa_core::decoder::{Decoder, ImageBuffer, Pixel};
use nokhwa_core::decoder::{ConfigHasResolution, Decoder, ImageBuffer, Pixel};
use nokhwa_core::error::NokhwaError;
use nokhwa_core::frame_buffer::FrameBuffer;
use nokhwa_core::image::Primitive;
@@ -51,7 +51,7 @@ impl Decoder for MJpegDecoder {
let colorspace = convert_destination_to_colorspace(destination_format).ok_or(NokhwaError::DecoderUnsupportedDestinationPixelFormat(destination_format))?;
let mut 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)?;
@@ -89,23 +89,6 @@ impl Decoder for MJpegDecoder {
))?;
Ok(DecodedImage::new(image_buffer, output_metadata))
}
fn output_decoder_min_size(
&self,
resolution: Resolution,
destination_format: PixelDestination,
) -> Result<usize, NokhwaError> {
let stride = match destination_format {
PixelDestination::Rgb8 => 3,
PixelDestination::Rgba8 => 4,
PixelDestination::Bgr8 => 3,
PixelDestination::Bgra8 => 4,
PixelDestination::Luma8 => 1,
PixelDestination::LumaA8 => 2,
fmt => return Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(fmt))
};
Ok((resolution.width() * resolution.height() * stride) as usize)
}
}
#[derive(Clone, Debug, PartialEq)]
@@ -137,6 +120,12 @@ pub struct MJpegOptions {
pub decoder_options: DecoderOptions,
}
impl ConfigHasResolution for MJpegOptions {
fn resolution(&self) -> Resolution {
self.resolution
}
}
fn err_to_err(decode_errors: DecodeErrors) -> NokhwaError {
match decode_errors {
DecodeErrors::Format(fmt) => NokhwaError::Decoder(fmt),
+56 -95
View File
@@ -1,11 +1,10 @@
use std::collections::HashMap;
use bytemuck::{cast_slice, cast_slice_mut, try_cast_slice_mut};
use bytemuck::{cast_slice, cast_slice_mut};
use nokhwa_core::decoder::{Decoder, ImageBuffer, Pixel, Primitive};
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::image::{DecodedImage, NonFloatScalarWidth};
use nokhwa_core::types::{CameraFormat, Resolution};
use yuv::{
YuvBiPlanarImage, YuvConversionMode, YuvPackedImage, YuvPlanarImage, YuvRange,
@@ -53,13 +52,12 @@ impl Decoder for YUVDecoder {
return Err(NokhwaError::DecoderUnsupportedFrameFormat(config.yuv_type));
}
if let Some(custom_map) = &config.custom_frame_format_map {
if let Some((src, dest)) = custom_map.iter().find(|(_, value)| {
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))
}
}
self.config = config;
Ok(())
@@ -71,29 +69,23 @@ impl Decoder for YUVDecoder {
mut buffer: impl AsMut<[u8]>,
destination_format: PixelDestination,
) -> Result<Self::OutputMeta, NokhwaError> {
let destination_format = match destination_format {
Some(df) => df,
None => return Err(NokhwaError::DecoderDestinationHintRequired),
};
let yuv_format = self.config().custom_frame_format_map.as_ref().map(|m| {
match self.config.yuv_type {
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,
}
}).flatten().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(yuv_format).ok_or(NokhwaError::DecoderUnsupportedFrameFormat(yuv_format))?;
let byte_width = figure_out_byte_width(yuv_format).ok_or(NokhwaError::DecoderUnsupportedFrameFormat(yuv_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 *
@@ -103,10 +95,10 @@ impl Decoder for YUVDecoder {
let stride_4px_2w = 8 * self.config.resolution.width();
// todo: clean up ts into a macro </3
let decode_status = match stride {
let decode_status = match stride {
Stride::Packed(stride) => {
let image = prepare_to_packed_image(&to_decode, self.config.resolution, byte_width, stride);
match yuv_format {
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)),
@@ -117,41 +109,45 @@ impl Decoder for YUVDecoder {
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::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)),
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::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)),
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::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)),
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::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)),
PixelDestination::Bgra8 => Some(yvyu422_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
_ => None,
}
}
_ => {
@@ -159,64 +155,64 @@ impl Decoder for YUVDecoder {
return Err(NokhwaError::NotImplementedError("etto blehhh! ()".to_string()))
}
// shouldnt happen
return Err(NokhwaError::DecoderUnsupportedFrameFormat(yuv_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);
match yuv_format {
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::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)),
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::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)),
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::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)),
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::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)),
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::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)),
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::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)),
PixelDestination::Bgra8 => Some(yuv_nv21_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix, self.config.mode)),
_ => None,
}
}
@@ -224,12 +220,12 @@ impl Decoder for YUVDecoder {
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::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::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,
_ => None,
}
}
FrameFormat::P012 => {
@@ -240,32 +236,32 @@ impl Decoder for YUVDecoder {
}
}
_ => {
if FrameFormat::YCBCR_SEMI.contains(&yuv_format) {
if FrameFormat::YCBCR_SEMI.contains(&format) {
return Err(NokhwaError::NotImplementedError("etto blehhh!".to_string()))
}
// shouldnt happen
return Err(NokhwaError::DecoderUnsupportedFrameFormat(yuv_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);
match yuv_format {
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::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)),
PixelDestination::Bgra8 => Some(yuv420_to_bgra(&image, buffer, stride_4px, self.config.range, self.config.matrix)),
_ => None,
}
}
_ => {
if FrameFormat::YCBCR_PLANAR.contains(&yuv_format) {
if FrameFormat::YCBCR_PLANAR.contains(&format) {
return Err(NokhwaError::NotImplementedError("etto blehhh!".to_string()))
}
// shouldnt happen
return Err(NokhwaError::DecoderUnsupportedFrameFormat(yuv_format))
return Err(NokhwaError::DecoderUnsupportedFrameFormat(format))
}
}
}
@@ -274,50 +270,10 @@ impl Decoder for YUVDecoder {
Some(Ok(_)) => Ok(()),
Some(Err(why)) => Err(NokhwaError::Decoder(why.to_string())),
None => Err(NokhwaError::DecoderUnsupportedFrameFormat(
yuv_format,
format,
)),
}
}
fn decode<P: Pixel>(
&mut self,
to_decode: FrameBuffer<'_>,
) -> Result<DecodedImage<P, Self::OutputMeta>, NokhwaError>
where
<P as Pixel>::Subpixel: NonFloatScalarWidth,
{
let min_size_alloc = self.output_decoder_min_size_pixel::<P>(self.config.resolution);
let mut out_buffer: Vec<P::Subpixel> = vec![P::Subpixel::DEFAULT_MIN_VALUE; min_size_alloc];
self.decode_to_pixel_buffer::<P>(to_decode, &mut out_buffer)?;
Ok(DecodedImage::new(
ImageBuffer::from_vec(
self.config.resolution.width(),
self.config.resolution.height(),
out_buffer,
)
.ok_or(NokhwaError::Decoder(
"failed to convert into an image buffer".to_string(),
))?,
(),
))
}
fn output_decoder_min_size(
&self,
resolution: Resolution,
destination_format: PixelDestination,
) -> Result<usize, NokhwaError> {
let px_size = match destination_format {
PixelDestination::Rgb8 | PixelDestination::Bgr8 => 3,
PixelDestination::Rgba8 | PixelDestination::Bgra8 => 4,
PixelDestination::Rgb16 => 3 * 2,
PixelDestination::Rgba16 => 4 * 2,
_ => return Err(NokhwaError::DecoderUnsupportedDestinationPixelFormat(destination_format))
};
let reso = resolution.width() * resolution.height();
Ok((reso as usize) * (px_size as usize))
}
}
#[derive(Clone, Debug, PartialEq)]
@@ -331,6 +287,12 @@ pub struct YUVConfig {
pub custom_frame_format_map: Option<HashMap<CustomFrameFormat, FrameFormat>>,
}
impl ConfigHasResolution for YUVConfig {
fn resolution(&self) -> Resolution {
self.resolution
}
}
impl TryFrom<CameraFormat> for YUVConfig {
type Error = NokhwaError;
@@ -420,7 +382,6 @@ fn planar_stride(format: FrameFormat) -> Option<(u32, u32, u32, u32)> {
fn prepare_to_packed_image<'a>(
frame_buffer: &'a FrameBuffer<'a>,
resolution: Resolution,
byte_width: u32,
yuy_stride: u32,
) -> YuvPackedImage<'a, u8> {
YuvPackedImage {
+22 -28
View File
@@ -44,45 +44,39 @@ impl<I, const MULTIPLIER: usize> Iterator for DuplicateConst<I, MULTIPLIER> wher
fn next(&mut self) -> Option<Self::Item> {
match self.state {
DuplicateConstState::Started => {
match self.iter.next() {
Some(i) => {
if MULTIPLIER <= 1 {
self.state = DuplicateConstState::EmitReal;
} else {
self.state = DuplicateConstState::EmitDupe;
}
self.last_iter_item = Some(i.clone());
Some(i)
}
None => {
self.state = DuplicateConstState::Finished;
None
if let Some(i) = self.iter.next() {
if MULTIPLIER <= 1 {
self.state = DuplicateConstState::EmitReal;
} else {
self.state = DuplicateConstState::EmitDupe;
}
self.last_iter_item = Some(i.clone());
Some(i)
} else {
self.state = DuplicateConstState::Finished;
None
}
}
DuplicateConstState::EmitDupe => {
self.running_count = self.running_count.saturating_sub(1);
if self.running_count <= 0 {
if self.running_count == 0 {
self.state = DuplicateConstState::EmitReal;
}
self.last_iter_item.clone()
}
DuplicateConstState::EmitReal => {
match self.iter.next() {
Some(i) => {
self.last_iter_item = Some(i.clone());
self.running_count = MULTIPLIER.saturating_sub(1);
if MULTIPLIER <= 1 {
self.state = DuplicateConstState::EmitReal;
} else {
self.state = DuplicateConstState::EmitDupe;
}
Some(i)
}
None => {
self.state = DuplicateConstState::Finished;
None
if let Some(i) = self.iter.next() {
self.last_iter_item = Some(i.clone());
self.running_count = MULTIPLIER.saturating_sub(1);
if MULTIPLIER <= 1 {
self.state = DuplicateConstState::EmitReal;
} else {
self.state = DuplicateConstState::EmitDupe;
}
Some(i)
} else {
self.state = DuplicateConstState::Finished;
None
}
}
DuplicateConstState::Finished => {
+14 -17
View File
@@ -58,23 +58,20 @@ impl<I, const PER: usize> Iterator for Interweave<I, PER> where I: Iterator, <I
}
InterweaveState::EmitReal => {
self.count = self.count.saturating_sub(1);
match self.iter.next() {
Some(i) => {
if self.count <= 0 {
self.state = InterweaveState::EmitFake;
} else {
self.state = InterweaveState::EmitReal;
}
self.prev_state = InterweaveState::EmitReal;
Some(i)
if let Some(i) = self.iter.next() {
if self.count == 0 {
self.state = InterweaveState::EmitFake;
} else {
self.state = InterweaveState::EmitReal;
}
None => {
self.state = InterweaveState::Finished;
if self.emit_last && self.prev_state != InterweaveState::EmitFake {
Some(self.element.clone())
} else {
None
}
self.prev_state = InterweaveState::EmitReal;
Some(i)
} else {
self.state = InterweaveState::Finished;
if self.emit_last && self.prev_state != InterweaveState::EmitFake {
Some(self.element.clone())
} else {
None
}
}
}
@@ -91,7 +88,7 @@ impl<I, const PER: usize> Iterator for Interweave<I, PER> where I: Iterator, <I
return (lower * 2, upper.map(|u| u * 2))
}
let last = if self.emit_last { 1 } else { 0 };
let last = usize::from(self.emit_last);
let new_lower = lower + (lower / PER) + last;
let new_upper = upper.map(|u| { u + (u / PER) + last });
(new_lower, new_upper)
+1 -1
View File
@@ -1,5 +1,5 @@
#![cfg_attr(not(test), no_std)]
#[warn(clippy::pedantic)]
#![warn(clippy::pedantic)]
pub mod interweave;
pub mod duplicate;