forked from l1npengtul/nokhwa
-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support kCMPixelFormat_32BGRA and add github action for running tests #1
Open
darioalessandro
wants to merge
15
commits into
0.10
Choose a base branch
from
fix-yuyv-parser
base: 0.10
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
8c12b38
add bgra
darioalessandro 7eb5e9d
not ready for primetime but renameb yuyv to i420 because that is what…
darioalessandro 5584868
save
darioalessandro fec4d19
save
darioalessandro 3b0a2fe
save
darioalessandro aad27f7
add bgra to linux bindings
darioalessandro a701a6e
checkin test assets
darioalessandro c46d077
adding assets with license
darioalessandro 8a2f4fc
add tests to ci
darioalessandro ed9d6b5
added better tests
darioalessandro 1c9385b
remove unused imports
darioalessandro 9552a9c
move nokhwa ci to a different file
darioalessandro ac3fbfb
run fmt
darioalessandro 074f3da
revert unrelated ci change
darioalessandro 72dba49
add better logging for bad buffer size
darioalessandro File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,7 +19,7 @@ use crate::types::{ | |
mjpeg_to_rgb, nv12_to_rgb, yuyv422_to_rgb, FrameFormat, Resolution, | ||
}; | ||
use image::{Luma, LumaA, Pixel, Rgb, Rgba}; | ||
use std::fmt::Debug; | ||
use std::fmt::{format, Debug}; | ||
|
||
/// Trait that has methods to convert raw data from the webcam to a proper raw image. | ||
pub trait FormatDecoder: Clone + Sized + Send + Sync { | ||
|
@@ -77,6 +77,16 @@ impl FormatDecoder for RgbFormat { | |
.collect()), | ||
FrameFormat::RAWRGB => Ok(data.to_vec()), | ||
FrameFormat::NV12 => nv12_to_rgb(resolution, data, false), | ||
FrameFormat::BGRA => { | ||
let mut rgb = vec![0u8; data.len()]; | ||
data.chunks_exact(4).enumerate().for_each(|(idx, px)| { | ||
let index = idx * 3; | ||
rgb[index] = px[2]; | ||
rgb[index + 1] = px[1]; | ||
rgb[index + 2] = px[0]; | ||
}); | ||
Ok(rgb) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -112,6 +122,23 @@ impl FormatDecoder for RgbFormat { | |
Ok(()) | ||
} | ||
FrameFormat::NV12 => buf_nv12_to_rgb(resolution, data, dest, false), | ||
FrameFormat::BGRA => { | ||
if dest.len() != data.len() / 4 * 3 { | ||
return Err(NokhwaError::ProcessFrameError { | ||
src: fcc, | ||
destination: "BGRA => RGB".to_string(), | ||
error: "Bad buffer length".to_string(), | ||
}); | ||
} | ||
|
||
data.chunks_exact(4).enumerate().for_each(|(idx, px)| { | ||
let index = idx * 3; | ||
dest[index] = px[2]; | ||
dest[index + 1] = px[1]; | ||
dest[index + 2] = px[0]; | ||
}); | ||
Ok(()) | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -151,6 +178,17 @@ impl FormatDecoder for RgbAFormat { | |
.flat_map(|x| [x[0], x[1], x[2], 255]) | ||
.collect()), | ||
FrameFormat::NV12 => nv12_to_rgb(resolution, data, true), | ||
FrameFormat::BGRA => { | ||
let mut rgba = vec![0u8; data.len()]; | ||
data.chunks_exact(4).enumerate().for_each(|(idx, px)| { | ||
let index = idx * 4; | ||
rgba[index] = px[2]; | ||
rgba[index + 1] = px[1]; | ||
rgba[index + 2] = px[0]; | ||
rgba[index + 3] = px[3]; | ||
}); | ||
Ok(rgba) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -194,6 +232,24 @@ impl FormatDecoder for RgbAFormat { | |
Ok(()) | ||
} | ||
FrameFormat::NV12 => buf_nv12_to_rgb(resolution, data, dest, true), | ||
FrameFormat::BGRA => { | ||
if dest.len() != data.len() { | ||
return Err(NokhwaError::ProcessFrameError { | ||
src: fcc, | ||
destination: "BGRA => RGBA".to_string(), | ||
error: "Bad buffer length".to_string(), | ||
}); | ||
} | ||
|
||
data.chunks_exact(4).enumerate().for_each(|(idx, px)| { | ||
let index = idx * 4; | ||
dest[index] = px[2]; | ||
dest[index + 1] = px[1]; | ||
dest[index + 2] = px[0]; | ||
dest[index + 3] = px[3]; | ||
}); | ||
Ok(()) | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -253,6 +309,10 @@ impl FormatDecoder for LumaFormat { | |
.chunks(3) | ||
.map(|px| ((i32::from(px[0]) + i32::from(px[1]) + i32::from(px[2])) / 3) as u8) | ||
.collect()), | ||
FrameFormat::BGRA => Ok(data | ||
.chunks_exact(4) | ||
.map(|px| ((i32::from(px[0]) + i32::from(px[1]) + i32::from(px[2])) / 3) as u8) | ||
.collect()), | ||
} | ||
} | ||
|
||
|
@@ -284,6 +344,12 @@ impl FormatDecoder for LumaFormat { | |
destination: "RGB => RGB".to_string(), | ||
error: "Conversion Error".to_string(), | ||
}), | ||
FrameFormat::BGRA => { | ||
data.chunks_exact(4).zip(dest.iter_mut()).for_each(|(px, d)| { | ||
*d = ((i32::from(px[0]) + i32::from(px[1]) + i32::from(px[2])) / 3) as u8; | ||
}); | ||
Ok(()) | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -343,6 +409,16 @@ impl FormatDecoder for LumaAFormat { | |
destination: "RGB => RGB".to_string(), | ||
error: "Conversion Error".to_string(), | ||
}), | ||
FrameFormat::BGRA => { | ||
let mut luma_a = vec![0u8; data.len() / 4 * 2]; | ||
data.chunks_exact(4).enumerate().for_each(|(idx, px)| { | ||
let index = idx * 2; | ||
luma_a[index] = ((i32::from(px[0]) + i32::from(px[1]) + i32::from(px[2])) / 3) | ||
as u8; | ||
luma_a[index + 1] = px[3]; | ||
}); | ||
Ok(luma_a) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -396,6 +472,21 @@ impl FormatDecoder for LumaAFormat { | |
destination: "RGB => RGB".to_string(), | ||
error: "Conversion Error".to_string(), | ||
}), | ||
FrameFormat::BGRA => { | ||
if dest.len() != data.len() / 4 * 2 { | ||
return Err(NokhwaError::ProcessFrameError { | ||
src: fcc, | ||
destination: "BGRA => LumaA".to_string(), | ||
error: "Conversion Error".to_string(), | ||
}); | ||
} | ||
|
||
data.chunks_exact(4).zip(dest.chunks_exact_mut(2)).for_each(|(px, d)| { | ||
d[0] = ((i32::from(px[0]) + i32::from(px[1]) + i32::from(px[2])) / 3) as u8; | ||
d[1] = px[3]; | ||
}); | ||
Ok(()) | ||
} | ||
} | ||
} | ||
} | ||
|
@@ -405,9 +496,10 @@ 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; | ||
pub struct I420Format; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was never YUYV it was always meant to be i420 |
||
|
||
impl FormatDecoder for YuyvFormat { | ||
impl FormatDecoder for I420Format { | ||
// YUV 4:2:0 planar colors. but we need to change the image crate to use this format | ||
type Output = Rgb<u8>; | ||
const FORMATS: &'static [FrameFormat] = color_frame_formats(); | ||
|
||
|
@@ -426,7 +518,10 @@ impl FormatDecoder for YuyvFormat { | |
); | ||
Ok(i420) | ||
} | ||
_ => Err(NokhwaError::GeneralError("Invalid FrameFormat".into())), | ||
_ => Err(NokhwaError::GeneralError(format!( | ||
"Invalid FrameFormat in write_output: {:?}", | ||
fcc | ||
))), | ||
} | ||
} | ||
|
||
|
@@ -447,7 +542,28 @@ impl FormatDecoder for YuyvFormat { | |
)?; | ||
Ok(()) | ||
} | ||
_ => Err(NokhwaError::GeneralError("Invalid FrameFormat".into())), | ||
|
||
FrameFormat::NV12 => { | ||
let i420 = nv12_to_i420(data, resolution.width() as usize, resolution.height() as usize); | ||
// Slice the enough tata to fill the destination buffer, i420 is larger so we need to slice it | ||
let i420 = &i420[..dest.len()]; | ||
dest.copy_from_slice(&i420); | ||
Ok(()) | ||
} | ||
|
||
FrameFormat::BGRA => { | ||
// transform the BGRA buffer to i420 and write it to the destination buffer | ||
let i420 = nv12_to_i420(data, resolution.width() as usize, resolution.height() as usize); | ||
// Slice the enough tata to fill the destination buffer, i420 is larger so we need to slice it | ||
let i420 = &i420[..dest.len()]; | ||
dest.copy_from_slice(&i420); | ||
Ok(()) | ||
}, | ||
|
||
_ => Err(NokhwaError::GeneralError(format!( | ||
"Invalid FrameFormat in write_output_buffer: {:?}", | ||
fcc | ||
))), | ||
} | ||
} | ||
} | ||
|
@@ -521,3 +637,38 @@ fn convert_yuyv_to_i420_direct( | |
|
||
Ok(()) | ||
} | ||
|
||
fn nv12_to_i420(nv12: &[u8], width: usize, height: usize) -> Vec<u8> { | ||
assert!( | ||
width % 2 == 0 && height % 2 == 0, | ||
"Width and height must be even numbers." | ||
); | ||
|
||
let y_plane_size = width * height; | ||
let uv_plane_size = y_plane_size / 2; // Interleaved UV plane size | ||
let u_plane_size = uv_plane_size / 2; | ||
|
||
// Allocate space for I420 (Y + U + V planes) | ||
let mut i420 = vec![0u8; y_plane_size + 2 * u_plane_size]; | ||
|
||
let (y_plane, uv_plane) = i420.split_at_mut(y_plane_size); | ||
let (u_plane, v_plane) = uv_plane.split_at_mut(u_plane_size); | ||
|
||
// Step 1: Copy Y plane | ||
y_plane.copy_from_slice(&nv12[..y_plane_size]); | ||
|
||
// Step 2: Process interleaved UV data | ||
let nv12_uv = &nv12[y_plane_size..]; | ||
|
||
for row in 0..(height / 2) { | ||
for col in 0..(width / 2) { | ||
let nv12_index = row * width + col * 2; // Index in NV12 interleaved UV plane | ||
let uv_index = row * (width / 2) + col; // Index in U and V planes | ||
|
||
u_plane[uv_index] = nv12_uv[nv12_index]; // U value | ||
v_plane[uv_index] = nv12_uv[nv12_index + 1]; // V value | ||
} | ||
} | ||
|
||
i420 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is the
meat
of the change