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 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}