1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
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<gtk::Packet<()>>{
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: (),
});
}
}
}
}
|