linux_video_core/impls/
frmsizes.rs

1use crate::{calls, types::*, Internal, Result};
2use core::mem::MaybeUninit;
3use std::os::unix::io::RawFd;
4
5impl FrmSizeEnum {
6    /// Get reference to size description
7    pub fn try_ref<T: IsFrmSizeData>(&self) -> Option<&T> {
8        if T::TYPES.contains(&self.type_()) {
9            Some(unsafe { &*(&self.union_ as *const _ as *const T) })
10        } else {
11            None
12        }
13    }
14
15    /// Get iterator over all supported sizes
16    pub fn sizes(&self) -> FrmSizeIter<'_> {
17        FrmSizeIter {
18            sizes: self,
19            index: 0,
20        }
21    }
22}
23
24pub struct FrmSizeIter<'i> {
25    sizes: &'i FrmSizeEnum,
26    index: u32,
27}
28
29impl<'i> Iterator for FrmSizeIter<'i> {
30    type Item = Area;
31
32    fn next(&mut self) -> Option<Self::Item> {
33        if self.index == u32::MAX {
34            return None;
35        }
36
37        match self.sizes.type_ {
38            FrmSizeType::Discrete => {
39                self.index = u32::MAX;
40                Some(*self.sizes.try_ref::<FrmSizeDiscrete>().unwrap())
41            }
42            FrmSizeType::Stepwise => {
43                let size = self
44                    .sizes
45                    .try_ref::<FrmSizeStepwise>()
46                    .unwrap()
47                    .try_get(self.index);
48
49                if size.is_some() {
50                    self.index += 1;
51                } else {
52                    self.index = u32::MAX;
53                }
54
55                size
56            }
57            FrmSizeType::Continuous => None, // FIXME:
58        }
59    }
60}
61
62impl<'i> core::iter::FusedIterator for FrmSizeIter<'i> {}
63
64impl FrmSizeStepwise {
65    /// Try get discrete frame size by index
66    pub fn try_get(&self, index: u32) -> Option<FrmSizeDiscrete> {
67        let width = self.min_width + self.step_width * index;
68        let height = self.min_height + self.step_height * index;
69
70        if width <= self.max_width && height <= self.max_height {
71            Some(FrmSizeDiscrete { width, height })
72        } else {
73            None
74        }
75    }
76}
77
78impl Internal<FrmSizeEnum> {
79    pub fn query(fd: RawFd, index: u32, pixel_format: FourCc) -> Result<Option<Self>> {
80        let frm_size = MaybeUninit::<FrmSizeEnum>::zeroed();
81
82        unsafe_call!({
83            let mut frm_size = frm_size.assume_init();
84            frm_size.index = index;
85            frm_size.pixel_format = pixel_format;
86            calls::enum_frame_sizes(fd, &mut frm_size).map(|_| frm_size)
87        })
88        .map(|frm_size| Some(frm_size.into()))
89        .or_else(|error| {
90            if error.kind() == std::io::ErrorKind::InvalidInput {
91                Ok(None)
92            } else {
93                Err(error)
94            }
95        })
96    }
97}
98
99pub trait IsFrmSizeData {
100    const TYPES: &'static [FrmSizeType];
101}
102
103macro_rules! frmsize_impl {
104    ($($type:ty: $($buf_type:ident)*,)*) => {
105        $(
106            impl IsFrmSizeData for $type {
107                const TYPES: &'static [FrmSizeType] = &[ $(FrmSizeType::$buf_type,)* ];
108            }
109        )*
110
111        impl core::fmt::Display for FrmSizeEnum {
112            fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
113                '#'.fmt(f)?;
114                self.index.fmt(f)?;
115                ' '.fmt(f)?;
116                self.pixel_format.fmt(f)?;
117                ' '.fmt(f)?;
118                self.type_.fmt(f)?;
119                ' '.fmt(f)?;
120                match self.type_ {
121                    $(
122                        $(FrmSizeType::$buf_type)|* => self.try_ref::<$type>()
123                            .ok_or_else(Default::default)?.fmt(f),
124                    )*
125                    _ => Ok(()),
126                }
127            }
128        }
129    };
130}
131
132frmsize_impl! {
133    FrmSizeDiscrete: Discrete,
134    FrmSizeStepwise: Stepwise,
135}
136
137impl core::fmt::Display for FrmSizeStepwise {
138    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
139        self.min_width.fmt(f)?;
140        'x'.fmt(f)?;
141        self.min_height.fmt(f)?;
142
143        "..=".fmt(f)?;
144
145        self.max_width.fmt(f)?;
146        'x'.fmt(f)?;
147        self.max_height.fmt(f)?;
148
149        '+'.fmt(f)?;
150
151        self.step_width.fmt(f)?;
152        'x'.fmt(f)?;
153        self.step_height.fmt(f)
154    }
155}