use anyhow::{anyhow, Result}; use crate::gtk; use crate::v4l2; use crate::color::yuv2rgb; use zune_jpeg::JpegDecoder as JpegDec; use zune_jpeg::zune_core::options::DecoderOptions as JpegOptions; use zune_jpeg::zune_core::colorspace::ColorSpace as JpegColorSpace; pub struct V4l2Cairo(v4l2::CaptStream); impl V4l2Cairo{ pub fn new(inner: v4l2::CaptStream) -> Self{ V4l2Cairo(inner) } } impl gtk::Source for V4l2Cairo{ type Attr = (); fn next(&mut self, fbpool: impl gtk::FbSourceOnce) -> Result>{ let mut fbpool = Some(fbpool); let (w, h) = (self.0.width(), self.0.height()); let s = self.0.bytesperline(); let pixelformat = self.0.pixelformat(); loop{ let img = self.0.next(|frame, _|{ if &pixelformat == "YUYV"{ if w % 2 != 0{ return Err(anyhow!("invalid width of YUYV")); } if frame.len() < w*h*2{ return Err(anyhow!("invalid size of YUYV")); } let mut img = fbpool.take().unwrap().get(w, h)?; let stride: usize = img.stride().try_into()?; let mut imgslice = img.data()?; for (x, y) in (0..h).map( |y| (0..w).map(move |x|(x, y))).flatten(){ let p = s*y + x*2; let (r, g, b) = yuv2rgb( frame[p], frame[p/4*4 + 1], frame[p/4*4 + 3]); imgslice[stride*y + x*4 + 0] = b; imgslice[stride*y + x*4 + 1] = g; imgslice[stride*y + x*4 + 2] = r; imgslice[stride*y + x*4 + 3] = 0; } drop(imgslice); Ok(img) }else if &pixelformat == "MJPG" || &pixelformat == "JPEG"{ // Jpeg is not placed in start of slice in some situation. // It is even possible that there are no Jpeg data. let jindex = (0..frame.len()-1) .filter(|i| frame[*i] == 0xff && frame[i+1] == 0xd8) .next() .ok_or(anyhow!("jpeg not found"))?; let mut jpeg = JpegDec::new_with_options( &frame[jindex..], JpegOptions::new_fast() .jpeg_set_out_colorspace(JpegColorSpace::BGRA)); let b = jpeg.decode()?; let info = jpeg.info().unwrap(); if info.width as usize != w || info.height as usize != h{ return Err(anyhow!("invalid size of jpeg")); } let mut img = fbpool.take().unwrap().get(w, h)?; let stride: usize = img.stride().try_into()?; let mut imgslice = img.data()?; for y in 0..h{ imgslice[stride*y..stride*y+w*4] .copy_from_slice(&b[y*w*4..((y+1)*w)*4]); } drop(imgslice); Ok(img) }else{ unimplemented!() } })?; if let Ok(img) = img{ return Ok(gtk::Packet{ image: img.take_data()?, attr: (), }); } } } }