From 3b0ae537baeab9ca953f911259d8c0a50d9bed1a Mon Sep 17 00:00:00 2001 From: l1npengtul Date: Tue, 11 Nov 2025 05:16:33 +0900 Subject: [PATCH] mjpeg, yuv test --- nokhwa-core/src/decoder.rs | 66 ++- nokhwa-core/src/frame_buffer.rs | 21 + nokhwa-decoders/Cargo.toml | 34 +- nokhwa-decoders/src/luma.rs | 604 ++++++++++++++---------- nokhwa-decoders/src/mjpeg.rs | 115 +++-- nokhwa-decoders/src/yuv.rs | 813 ++++++++++++++++++++++++-------- 6 files changed, 1119 insertions(+), 534 deletions(-) diff --git a/nokhwa-core/src/decoder.rs b/nokhwa-core/src/decoder.rs index b1011ca..7665118 100644 --- a/nokhwa-core/src/decoder.rs +++ b/nokhwa-core/src/decoder.rs @@ -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; - fn decode_to_pixel_buffer(&mut self, to_decode: FrameBuffer, mut buffer: impl AsMut<[P::Subpixel]>) -> Result + fn decode_to_pixel_buffer( + &mut self, + to_decode: FrameBuffer, + mut buffer: impl AsMut<[P::Subpixel]>, + ) -> Result where -

::Subpixel: NonFloatScalarWidth +

::Subpixel: NonFloatScalarWidth, { - let Some(destination) = PixelDestination::get_by_pixel::

() else { return Err(NokhwaError::DecoderUnknownDestinationPixelFormat(P::COLOR_MODEL, P::Subpixel::WIDTH_BYTES)) }; + let Some(destination) = PixelDestination::get_by_pixel::

() 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 = vec![P::Subpixel::DEFAULT_MIN_VALUE; min_size_alloc]; let meta = self.decode_to_pixel_buffer::

(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

(&self, resolution: Resolution) -> Result where - P: Pixel, -

::Subpixel: NonFloatScalarWidth { - PixelDestination::get_by_pixel::

().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

(&self, resolution: Resolution) -> Result + where + P: Pixel, +

::Subpixel: NonFloatScalarWidth, + { + PixelDestination::get_by_pixel::

() + .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 { + + fn output_decoder_min_size( + &self, + resolution: Resolution, + destination_format: PixelDestination, + ) -> Result { 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)) } diff --git a/nokhwa-core/src/frame_buffer.rs b/nokhwa-core/src/frame_buffer.rs index 5921124..e493659 100644 --- a/nokhwa-core/src/frame_buffer.rs +++ b/nokhwa-core/src/frame_buffer.rs @@ -146,3 +146,24 @@ impl Deref for FrameBuffer<'_> { self.buffer.as_ref() } } + +impl From> for FrameBuffer<'_> { + fn from(value: Vec) -> 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, + } + } +} diff --git a/nokhwa-decoders/Cargo.toml b/nokhwa-decoders/Cargo.toml index c50dcb4..e68897e 100644 --- a/nokhwa-decoders/Cargo.toml +++ b/nokhwa-decoders/Cargo.toml @@ -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" ] diff --git a/nokhwa-decoders/src/luma.rs b/nokhwa-decoders/src/luma.rs index e102b43..76d02ad 100644 --- a/nokhwa-decoders/src/luma.rs +++ b/nokhwa-decoders/src/luma.rs @@ -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 { - 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 { + 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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(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::(to_decode.buffer()); let destination_buffer_u16 = cast_slice_mut::(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 for LumaConfig { fn try_from(value: CameraFormat) -> Result { 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 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() {} +} diff --git a/nokhwa-decoders/src/mjpeg.rs b/nokhwa-decoders/src/mjpeg.rs index 9af3d56..937c23b 100644 --- a/nokhwa-decoders/src/mjpeg.rs +++ b/nokhwa-decoders/src/mjpeg.rs @@ -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 { + 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( - &mut self, - to_decode: FrameBuffer, - ) -> Result, NokhwaError> - where -

::Subpixel: NonFloatScalarWidth, - { - let min_size = self.output_decoder_min_size_pixel::

(self.config.resolution)?; - let mut out_buffer: Vec = vec![P::Subpixel::DEFAULT_MAX_VALUE; min_size]; - let output_metadata = - self.decode_to_pixel_buffer::

(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 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::>(decode_buffer).unwrap(); + + assert_eq!(out.as_raw(), test_image.as_raw()); + } +} diff --git a/nokhwa-decoders/src/yuv.rs b/nokhwa-decoders/src/yuv.rs index f7aac3b..8cb840d 100644 --- a/nokhwa-decoders/src/yuv.rs +++ b/nokhwa-decoders/src/yuv.rs @@ -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 { - 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 { fn figure_out_byte_width(format: FrameFormat) -> Option { 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(filename: String, resolution: Resolution, format: FrameFormat) -> ImageBuffer> -where -

::Subpixel: NonFloatScalarWidth { + fn base_test( + filename: String, + resolution: Resolution, + format: FrameFormat, + ) -> ImageBuffer> + where +

::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::

(frame_buffer).unwrap().buffer } - fn write_image(image: ImageBuffer>, filename: String) where - [

::Subpixel]: EncodableLayout + #[allow(dead_code)] + fn write_image( + image: ImageBuffer>, + filename: String, + ) where + [

::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::>(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::>(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::>(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::>(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::>(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::>(format!("{base_filename}.yuv"), resolution, format); assert_eq!(image_rgba8.as_raw(), out.as_raw()); } } - - }