linux_video_core/impls/
frmsizes.rs1use crate::{calls, types::*, Internal, Result};
2use core::mem::MaybeUninit;
3use std::os::unix::io::RawFd;
4
5impl FrmSizeEnum {
6 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 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, }
59 }
60}
61
62impl<'i> core::iter::FusedIterator for FrmSizeIter<'i> {}
63
64impl FrmSizeStepwise {
65 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}