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
42pub enum VideoBufferRefData<'a>{
43    U8(&'a [u8]),
44    U32(&'a [u32])
45}
46
47pub struct VideoBufferRef<'a>{
48    pub format: VideoFormat,
49    pub data: VideoBufferRefData<'a>
50}
51
52
53impl<'a> VideoBufferRef<'a>{
54    pub fn to_buffer(&self)->VideoBuffer{
55        VideoBuffer{
56            format: self.format.clone(),
57            data: match self.data{
58                VideoBufferRefData::U8(data)=>VideoBufferData::U8(data.to_vec()),
59                VideoBufferRefData::U32(data)=>VideoBufferData::U32(data.to_vec()),
60            }
61        }
62    }
63
64    pub fn as_slice_u32(&mut self)->Option<&[u32]>{
65        match &mut self.data{
66            VideoBufferRefData::U32(v)=>return Some(v),
67            _=>return None
68        }
69    }
70    pub fn as_slice_u8(&mut self)->Option<&[u8]>{
71        match &mut self.data{
72            VideoBufferRefData::U8(v)=>return Some(v),
73            _=>return None
74        }
75    }
76}
77
78pub enum VideoBufferData{
79    U8(Vec<u8>),
80    U32(Vec<u32>)
81}
82
83pub struct VideoBuffer{
84    pub format:VideoFormat,
85    pub data: VideoBufferData
86}
87
88impl VideoBuffer{
89    pub fn as_vec_u32(&mut self)->Option<&mut Vec<u32>>{
90        match &mut self.data{
91            VideoBufferData::U32(v)=>return Some(v),
92            _=>return None
93        }
94    }
95    pub fn as_vec_u8(&mut self)->Option<&mut Vec<u8>>{
96        match &mut self.data{
97            VideoBufferData::U8(v)=>return Some(v),
98            _=>return None
99        }
100    }
101}
102
103impl VideoBuffer{
104    pub fn into_vec_u32(self)->Option<Vec<u32>>{
105        match self.data{
106            VideoBufferData::U32(v)=>return Some(v),
107            _=>return None
108        }
109    }
110    pub fn into_vec_u8(self)->Option<Vec<u8>>{
111        match self.data{
112            VideoBufferData::U8(v)=>return Some(v),
113            _=>return None
114        }
115    }
116}
117
118
119#[derive(Clone, Copy, Debug)]
120pub struct VideoFormat {
121    pub format_id: VideoFormatId,
122    pub width: usize,
123    pub height: usize,
124    pub frame_rate: Option<f64>,
125    pub pixel_format: VideoPixelFormat
126}
127
128#[derive(Clone, Debug)]
129pub struct VideoInputDesc {
130    pub input_id: VideoInputId,
131    pub name: String,
132    pub formats: Vec<VideoFormat>
133}
134
135#[derive(Clone)]
136pub struct VideoInputsEvent {
137    pub descs: Vec<VideoInputDesc>,
138}
139
140impl VideoInputsEvent {
141    pub fn find_device(&self, name:&str)->usize{
142        if let Some(position) = self.descs.iter().position(|v| v.name == name){
143            return position
144        }
145        return 0
146    }
147    
148    pub fn find_highest(&self, device_index:usize) -> Vec<(VideoInputId,VideoFormatId)> {
149        if let Some(device) = self.descs.get(device_index){
150            let mut max_pixels = 0;
151            let mut max_frame_rate = 0.0;
152            let mut max_quality = 0;
153            let mut format_id = None;
154            for format in &device.formats {
155                let pixels = format.width * format.height;
156                if pixels >= max_pixels{
157                    max_pixels = pixels
158                }
159            }
160            for format in &device.formats {
161                if let Some(frame_rate) = format.frame_rate{
162                    let pixels = format.width * format.height;
163                    if pixels == max_pixels && frame_rate >= max_frame_rate {
164                        max_frame_rate = frame_rate;
165                    }
166                }
167            }
168            for format in &device.formats {
169                let pixels = format.width * format.height;
170                let quality = format.pixel_format.quality_priority();
171                if pixels == max_pixels && format.frame_rate.unwrap_or(0.0) == max_frame_rate && quality >= max_quality{
172                    max_quality = quality;
173                    format_id = Some(format.format_id)
174                }
175            }
176            if let Some(format_id) = format_id{
177                return vec![(device.input_id, format_id)]
178            }
179        }
180        vec![]
181    }
182    
183    pub fn find_highest_at_res(&self, device_index:usize, width:usize, height:usize, max_fps:f64) -> Vec<(VideoInputId,VideoFormatId)> {
184        if let Some(device) = self.descs.get(device_index){
185            let mut max_frame_rate = 0.0;
186            let mut max_quality = 0;
187            let mut format_id = None;
188
189            for format in &device.formats {
190                if let Some(frame_rate) = format.frame_rate{
191                    if width == format.width && height == format.height && frame_rate >= max_frame_rate && frame_rate <= max_fps{
192                        max_frame_rate = frame_rate;
193                    }
194                }
195            }
196            for format in &device.formats {
197                let quality = format.pixel_format.quality_priority();
198                if width == format.width && height == format.height && format.frame_rate.unwrap_or(0.0) == max_frame_rate && quality >= max_quality{
199                    max_quality = quality;
200                    format_id = Some(format.format_id)
201                }
202            }
203            if let Some(format_id) = format_id{
204                return vec![(device.input_id, format_id)]
205            }
206        }
207        vec![]
208    }
209    
210    pub fn find_format(&self, device_index:usize, width:usize, height:usize, pixel_format: VideoPixelFormat) -> Vec<(VideoInputId,VideoFormatId)> {
211        if let Some(device) = self.descs.get(device_index){
212            let mut max_frame_rate = 0.0;
213            let mut format_id = None;
214
215            for format in &device.formats {
216                if let Some(frame_rate) = format.frame_rate{
217                    if format.pixel_format == pixel_format && width == format.width && height == format.height && frame_rate >= max_frame_rate {
218                        max_frame_rate = frame_rate;
219                    }
220                }
221            }
222            for format in &device.formats {
223                if format.pixel_format == pixel_format && width == format.width && height == format.height && format.frame_rate.unwrap_or(0.0) == max_frame_rate {
224                    format_id = Some(format.format_id)
225                }
226            }
227            if let Some(format_id) = format_id{
228                return vec![(device.input_id, format_id)]
229            }
230        }
231        vec![]
232    }
233}
234
235
236impl std::fmt::Debug for VideoInputsEvent {
237    fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
238        for desc in &self.descs {
239            write!(f, "Capture Device: {}\n", desc.name).unwrap();
240            for format in &desc.formats {
241                write!(f, "    format: w:{} h:{} framerate:{:?} pixel:{:?} \n", format.width, format.height, format.frame_rate, format.pixel_format).unwrap();
242            }
243        }
244        Ok(())
245    }
246}