Skip to content

Commit

Permalink
add yuyv (#181)
Browse files Browse the repository at this point in the history
  • Loading branch information
darioalessandro authored Oct 14, 2024
1 parent fc64a23 commit cf9b8a0
Showing 1 changed file with 122 additions and 0 deletions.
122 changes: 122 additions & 0 deletions nokhwa-core/src/pixel_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,3 +399,125 @@ impl FormatDecoder for LumaAFormat {
}
}
}



/// let image: ImageBuffer<Rgb<u8>, Vec<u8>> = buffer.to_image::<YuyvFormat>();
/// ```
#[derive(Copy, Clone, Debug, Default, Hash, Ord, PartialOrd, Eq, PartialEq)]
pub struct YuyvFormat;

impl FormatDecoder for YuyvFormat {
type Output = Rgb<u8>;
const FORMATS: &'static [FrameFormat] = color_frame_formats();

#[inline]
fn write_output(
fcc: FrameFormat,
resolution: Resolution,
data: &[u8],
) -> Result<Vec<u8>, NokhwaError> {
match fcc {
FrameFormat::YUYV => {
let i420 = private_convert_yuyv_to_i420(
data,
resolution.width() as usize,
resolution.height() as usize,
);
Ok(i420)
}
_ => Err(NokhwaError::GeneralError("Invalid FrameFormat".into())),
}
}

#[inline]
fn write_output_buffer(
fcc: FrameFormat,
resolution: Resolution,
data: &[u8],
dest: &mut [u8],
) -> Result<(), NokhwaError> {
match fcc {
FrameFormat::YUYV => {
convert_yuyv_to_i420_direct(
data,
dest,
resolution.width() as usize,
resolution.height() as usize,
)?;
Ok(())
}
_ => Err(NokhwaError::GeneralError("Invalid FrameFormat".into())),
}
}
}

fn private_convert_yuyv_to_i420(yuyv: &[u8], width: usize, height: usize) -> Vec<u8> {
assert!(
width % 2 == 0 && height % 2 == 0,
"Width and height must be even numbers."
);

let mut i420 = vec![0u8; width * height + 2 * (width / 2) * (height / 2)];
let (y_plane, uv_plane) = i420.split_at_mut(width * height);
let (u_plane, v_plane) = uv_plane.split_at_mut(uv_plane.len() / 2);

for y in 0..height {
for x in (0..width).step_by(2) {
let base_index = (y * width + x) * 2;
let y0 = yuyv[base_index];
let u = yuyv[base_index + 1];
let y1 = yuyv[base_index + 2];
let v = yuyv[base_index + 3];

y_plane[y * width + x] = y0;
y_plane[y * width + x + 1] = y1;

if y % 2 == 0 {
u_plane[y / 2 * (width / 2) + x / 2] = u;
v_plane[y / 2 * (width / 2) + x / 2] = v;
}
}
}

i420
}

fn convert_yuyv_to_i420_direct(
yuyv: &[u8],
dest: &mut [u8],
width: usize,
height: usize,
) -> Result<(), NokhwaError> {
// Ensure the destination buffer is large enough
if dest.len() < width * height + 2 * (width / 2) * (height / 2) {
return Err(NokhwaError::GeneralError(
"Destination buffer is too small".into(),
));
}

// Split the destination buffer into Y, U, and V planes
let (y_plane, uv_plane) = dest.split_at_mut(width * height);
let (u_plane, v_plane) = uv_plane.split_at_mut(uv_plane.len() / 2);

// Convert YUYV to I420
for y in 0..height {
for x in (0..width).step_by(2) {
let base_index = (y * width + x) * 2;
let y0 = yuyv[base_index];
let u = yuyv[base_index + 1];
let y1 = yuyv[base_index + 2];
let v = yuyv[base_index + 3];

y_plane[y * width + x] = y0;
y_plane[y * width + x + 1] = y1;

if y % 2 == 0 {
u_plane[y / 2 * (width / 2) + x / 2] = u;
v_plane[y / 2 * (width / 2) + x / 2] = v;
}
}
}

Ok(())
}

0 comments on commit cf9b8a0

Please sign in to comment.