makepad_platform/
video.rs

1use {
2    crate::{
3        makepad_live_id::{LiveId, FromLiveId},
4    }
5};
6
7pub type VideoInputFn = Box<dyn FnMut(VideoBufferRef) + Send  + 'static>;
8
9pub const MAX_VIDEO_DEVICE_INDEX: usize = 32;
10
11#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
12pub struct VideoInputId(pub LiveId);
13
14#[derive(Clone, Debug, Default, Eq, Hash, Copy, PartialEq, FromLiveId)]
15pub struct VideoFormatId(pub LiveId);
16
17#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
18pub enum VideoPixelFormat {
19    RGB24,
20    YUY2,
21    NV12,
22    YUV420,
23    GRAY,
24    MJPEG,
25    Unsupported(u32)
26}
27
28impl VideoPixelFormat{
29    fn quality_priority(&self)->usize{
30        match self{
31            Self::RGB24 => 6,
32            Self::YUY2 => 5,
33            Self::NV12 => 4 ,
34            Self::YUV420=> 3,
35            Self::MJPEG => 2,
36            Self::GRAY => 1,
37            Self::Unsupported(_)=>0
38        }
39    }
40    
41    //TODO make SIMD version of this
42    pub fn buffer_to_bgra_32(&self, input:&[u32], width:usize, height:usize, rgba:&mut Vec<u32>){
43        fn yuv_to_rgb(y: i32, u: i32, v: i32)->u32{
44            fn clip(a: i32) -> u32 {
45                if a< 0 {
46                    return 0
47                }
48                if a > 255 {
49                    return 255
50                }
51                return a as u32
52            }
53            let c = y as i32 - 16;
54            let d = v as i32 - 128;
55            let e = u as i32 - 128;
56            return (clip((298 * c + 516 * d + 128) >> 8) << 16)
57            | (clip((298 * c - 100 * d - 208 * e + 128) >> 8) << 8)
58            | (clip((298 * c + 409 * e + 128) >> 8) << 0)
59            | (255 << 24);
60        }
61        
62        match self{
63            Self::NV12=>{
64                rgba.resize(width * height,0u32);
65                for y in 0..height{
66                    for x in (0..width).step_by(2){
67                        let d = input[y*(width>>1) + (x>>1)];
68                        let y1 = (d>>16)&0xff;
69                        let y2 = (d>>0)&0xff ;
70                        let u = (d>>8)&0xff;
71                        let v = (d>>24)&0xff;
72                        rgba[y*width + x] = yuv_to_rgb(y1 as i32, u as i32, v as i32);
73                        rgba[y*width + x + 1] = yuv_to_rgb(y2 as i32, u as i32, v as i32);
74                    }
75                }
76            }
77            _=>{
78                crate::error!("convert to bgra not supported");
79            }
80        }
81    }
82    
83    pub fn buffer_to_rgb_8(&self, input:&[u32], rgb:&mut Vec<u8>, in_width:usize, _in_height:usize, left:usize, top:usize, out_width:usize, out_height:usize){
84        fn yuv_to_rgb(y: i32, u: i32, v: i32)->(u8,u8,u8){
85            fn clip(a: i32) -> u32 {
86                if a< 0 {
87                    return 0
88                }
89                if a > 255 {
90                    return 255
91                }
92                return a as u32
93            }
94            let c = y as i32 - 16;
95            let d = v as i32 - 128;
96            let e = u as i32 - 128;
97            let r = clip((298 * c + 516 * d + 128) >> 8) as u8;
98            let g = clip((298 * c - 100 * d - 208 * e + 128) >> 8) as u8;
99            let b = clip((298 * c + 409 * e + 128) >> 8) as u8;
100            (r,g,b)
101        }
102                
103        match self{
104            Self::NV12=>{
105                rgb.clear();
106                rgb.reserve(out_width * out_height * 3);
107                for y in top..top+out_height{
108                    for x in (left..left+out_width).step_by(2){
109                        let d = input[y*(in_width>>1) + (x>>1)];
110                        let y1 = (d>>16)&0xff;
111                        let y2 = (d>>0)&0xff ;
112                        let u = (d>>8)&0xff;
113                        let v = (d>>24)&0xff;
114                        let (r,g,b) = yuv_to_rgb(y1 as i32, u as i32, v as i32);
115                        rgb.push(r);
116                        rgb.push(g);
117                        rgb.push(b);
118                        let (r,g,b) = yuv_to_rgb(y2 as i32, u as i32, v as i32);
119                        rgb.push(r);
120                        rgb.push(g);
121                        rgb.push(b);
122                    }
123                }
124            }
125            _=>{
126                crate::error!("convert to bgra not supported");
127            }
128        }
129    }
130}
131
132pub enum VideoBufferRefData<'a>{
133    U8(&'a [u8]),
134    U32(&'a [u32])
135}
136
137pub struct VideoBufferRef<'a>{
138    pub format: VideoFormat,
139    pub data: VideoBufferRefData<'a>
140}
141
142
143impl<'a> VideoBufferRef<'a>{
144    pub fn to_buffer(&self)->VideoBuffer{
145        VideoBuffer{
146            format: self.format.clone(),
147            data: match self.data{
148                VideoBufferRefData::U8(data)=>VideoBufferData::U8(data.to_vec()),
149                VideoBufferRefData::U32(data)=>VideoBufferData::U32(data.to_vec()),
150            }
151        }
152    }
153
154    pub fn as_slice_u32(&mut self)->Option<&[u32]>{
155        match &mut self.data{
156            VideoBufferRefData::U32(v)=>return Some(v),
157            _=>return None
158        }
159    }
160    pub fn as_slice_u8(&mut self)->Option<&[u8]>{
161        match &mut self.data{
162            VideoBufferRefData::U8(v)=>return Some(v),
163            _=>return None
164        }
165    }
166}
167
168pub enum VideoBufferData{
169    U8(Vec<u8>),
170    U32(Vec<u32>)
171}
172
173pub struct VideoBuffer{
174    pub format:VideoFormat,
175    pub data: VideoBufferData
176}
177
178impl VideoBuffer{
179    pub fn as_vec_u32(&mut self)->Option<&mut Vec<u32>>{
180        match &mut self.data{
181            VideoBufferData::U32(v)=>return Some(v),
182            _=>return None
183        }
184    }
185    pub fn as_vec_u8(&mut self)->Option<&mut Vec<u8>>{
186        match &mut self.data{
187            VideoBufferData::U8(v)=>return Some(v),
188            _=>return None
189        }
190    }
191    
192}
193
194impl VideoBuffer{
195    pub fn into_vec_u32(self)->Option<Vec<u32>>{
196        match self.data{
197            VideoBufferData::U32(v)=>return Some(v),
198            _=>return None
199        }
200    }
201    pub fn into_vec_u8(self)->Option<Vec<u8>>{
202        match self.data{
203            VideoBufferData::U8(v)=>return Some(v),
204            _=>return None
205        }
206    }
207}
208
209
210#[derive(Clone, Copy, Debug)]
211pub struct VideoFormat {
212    pub format_id: VideoFormatId,
213    pub width: usize,
214    pub height: usize,
215    pub frame_rate: Option<f64>,
216    pub pixel_format: VideoPixelFormat
217}
218
219#[derive(Clone, Debug)]
220pub struct VideoInputDesc {
221    pub input_id: VideoInputId,
222    pub name: String,
223    pub formats: Vec<VideoFormat>
224}
225
226#[derive(Clone)]
227pub struct VideoInputsEvent {
228    pub descs: Vec<VideoInputDesc>,
229}
230
231impl VideoInputsEvent {
232    pub fn find_device(&self, name:&str)->usize{
233        if let Some(position) = self.descs.iter().position(|v| v.name == name){
234            return position
235        }
236        return 0
237    }
238    
239    pub fn find_highest(&self, device_index:usize) -> Vec<(VideoInputId,VideoFormatId)> {
240        if let Some(device) = self.descs.get(device_index){
241            let mut max_pixels = 0;
242            let mut max_frame_rate = 0.0;
243            let mut max_quality = 0;
244            let mut format_id = None;
245            for format in &device.formats {
246                let pixels = format.width * format.height;
247                if pixels >= max_pixels{
248                    max_pixels = pixels
249                }
250            }
251            for format in &device.formats {
252                if let Some(frame_rate) = format.frame_rate{
253                    let pixels = format.width * format.height;
254                    if pixels == max_pixels && frame_rate >= max_frame_rate {
255                        max_frame_rate = frame_rate;
256                    }
257                }
258            }
259            for format in &device.formats {
260                let pixels = format.width * format.height;
261                let quality = format.pixel_format.quality_priority();
262                if pixels == max_pixels && format.frame_rate.unwrap_or(0.0) == max_frame_rate && quality >= max_quality{
263                    max_quality = quality;
264                    format_id = Some(format.format_id)
265                }
266            }
267            if let Some(format_id) = format_id{
268                return vec![(device.input_id, format_id)]
269            }
270        }
271        vec![]
272    }
273    
274    pub fn find_highest_at_res(&self, device_index:usize, width:usize, height:usize, max_fps:f64) -> Vec<(VideoInputId,VideoFormatId)> {
275        if let Some(device) = self.descs.get(device_index){
276            let mut max_frame_rate = 0.0;
277            let mut max_quality = 0;
278            let mut format_id = None;
279
280            for format in &device.formats {
281                if let Some(frame_rate) = format.frame_rate{
282                    if width == format.width && height == format.height && frame_rate >= max_frame_rate && frame_rate <= max_fps{
283                        max_frame_rate = frame_rate;
284                    }
285                }
286            }
287            for format in &device.formats {
288                let quality = format.pixel_format.quality_priority();
289                if width == format.width && height == format.height && format.frame_rate.unwrap_or(0.0) == max_frame_rate && quality >= max_quality{
290                    max_quality = quality;
291                    format_id = Some(format.format_id)
292                }
293            }
294            if let Some(format_id) = format_id{
295                return vec![(device.input_id, format_id)]
296            }
297        }
298        vec![]
299    }
300    
301    pub fn find_format(&self, device_index:usize, width:usize, height:usize, pixel_format: VideoPixelFormat) -> Vec<(VideoInputId,VideoFormatId)> {
302        if let Some(device) = self.descs.get(device_index){
303            let mut max_frame_rate = 0.0;
304            let mut format_id = None;
305
306            for format in &device.formats {
307                if let Some(frame_rate) = format.frame_rate{
308                    if format.pixel_format == pixel_format && width == format.width && height == format.height && frame_rate >= max_frame_rate {
309                        max_frame_rate = frame_rate;
310                    }
311                }
312            }
313            for format in &device.formats {
314                if format.pixel_format == pixel_format && width == format.width && height == format.height && format.frame_rate.unwrap_or(0.0) == max_frame_rate {
315                    format_id = Some(format.format_id)
316                }
317            }
318            if let Some(format_id) = format_id{
319                return vec![(device.input_id, format_id)]
320            }
321        }
322        vec![]
323    }
324}
325
326
327impl std::fmt::Debug for VideoInputsEvent {
328    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
329        for desc in &self.descs {
330            write!(f, "Capture Device: {}\n", desc.name).unwrap();
331            for format in &desc.formats {
332                write!(f, "    format: w:{} h:{} framerate:{:?} pixel:{:?} \n", format.width, format.height, format.frame_rate, format.pixel_format).unwrap();
333            }
334        }
335        Ok(())
336    }
337}