Problem
When capturing compressed formats like MJPEG, data() gives you the entire allocated plane buffer — not just the bytes the camera actually wrote. A 1080p MJPEG frame might sit in a 4 MB buffer but only use 80 KB of it. The real length lives in metadata().planes()[i].bytes_used.
So right now every caller has to do this manually:
let planes = framebuffer.data();
let frame_data = planes.first().unwrap();
let bytes_used = framebuffer.metadata().unwrap()
.planes().get(0).unwrap()
.bytes_used as usize;
// hope bytes_used <= frame_data.len(), otherwise: panic
let actual = &frame_data[..bytes_used];
This is what both jpeg_capture.rs and video_capture.rs currently do. It is easy to forget, and has no bounds check — if a driver ever returns a bad bytes_used, you get a panic.
What can be done:
A data_used() method that trims automatically:
pub fn data_used(&self) -> Option<Vec<&[u8]>> {
let meta = self.fb.metadata()?;
let full_planes = self.data();
Some(
full_planes
.into_iter()
.zip(meta.planes().into_iter())
.map(|(slice, plane_meta)| {
let used = (plane_meta.bytes_used as usize).min(slice.len());
&slice[..used]
})
.collect(),
)
}
- Returns
None if the request has not completed yet (consistent with metadata())
- Clamps to
slice.len() so bad driver values never panic
- Zero-copy, no allocation
The call sites then simplify to:
let planes = framebuffer.data_used().expect("frame not ready");
let frame_data = planes.first().expect("no planes");
file.write_all(frame_data)?;
Happy to open a PR for this if the approach looks good.
Problem
When capturing compressed formats like MJPEG,
data()gives you the entire allocated plane buffer — not just the bytes the camera actually wrote. A 1080p MJPEG frame might sit in a 4 MB buffer but only use 80 KB of it. The real length lives inmetadata().planes()[i].bytes_used.So right now every caller has to do this manually:
This is what both
jpeg_capture.rsandvideo_capture.rscurrently do. It is easy to forget, and has no bounds check — if a driver ever returns a badbytes_used, you get a panic.What can be done:
A
data_used()method that trims automatically:Noneif the request has not completed yet (consistent withmetadata())slice.len()so bad driver values never panicThe call sites then simplify to:
Happy to open a PR for this if the approach looks good.