dvb_si/descriptors/extension/
video_depth_range.rs1use super::*;
3
4impl<'a> ExtensionBodyDef<'a> for VideoDepthRange<'a> {
5 const TAG_EXTENSION: u8 = 0x10;
6 const NAME: &'static str = "VIDEO_DEPTH_RANGE";
7}
8
9#[derive(Debug, Clone, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize))]
12#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
13pub struct DepthRange<'a> {
14 pub range_type: u8,
16 pub body: DepthRangeBody<'a>,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
24#[non_exhaustive]
25pub enum DepthRangeBody<'a> {
26 ProductionDisparityHint {
29 max: i16,
31 min: i16,
33 },
34 MultiRegionSei,
36 #[cfg_attr(feature = "serde", serde(borrow))]
38 Other(&'a [u8]),
39}
40
41#[derive(Debug, Clone, PartialEq, Eq)]
43#[cfg_attr(feature = "serde", derive(serde::Serialize))]
44#[cfg_attr(feature = "yoke", derive(yoke::Yokeable))]
45pub struct VideoDepthRange<'a> {
46 pub ranges: Vec<DepthRange<'a>>,
48}
49
50fn sext12(v: u16) -> i16 {
52 if v & 0x800 != 0 {
53 (v | 0xF000) as i16
54 } else {
55 v as i16
56 }
57}
58
59impl<'a> Parse<'a> for VideoDepthRange<'a> {
60 type Error = crate::error::Error;
61 fn parse(sel: &'a [u8]) -> Result<Self> {
62 let mut pos = 0;
63 let mut ranges = Vec::new();
64 loop {
65 if pos == sel.len() {
66 break;
67 }
68 if sel.len() - pos < VD_RANGE_HDR_LEN {
70 return Err(Error::BufferTooShort {
71 need: pos + VD_RANGE_HDR_LEN,
72 have: sel.len(),
73 what: "video_depth_range body",
74 });
75 }
76 let range_type = sel[pos];
77 let range_length = sel[pos + 1] as usize;
78 pos += VD_RANGE_HDR_LEN;
79 if sel.len() < pos + range_length {
80 return Err(Error::BufferTooShort {
81 need: pos + range_length,
82 have: sel.len(),
83 what: "video_depth_range body",
84 });
85 }
86 let body = match range_type {
87 0x00 => {
89 if range_length < VD_DISPARITY_LEN {
90 return Err(invalid(
91 "video_depth_range: production_disparity_hint requires 3+ bytes",
92 ));
93 }
94 let b0 = sel[pos];
96 let b1 = sel[pos + 1];
97 let b2 = sel[pos + 2];
98 let max = sext12((u16::from(b0) << 4) | (u16::from(b1) >> 4));
99 let min = sext12(((u16::from(b1) & 0x0F) << 8) | u16::from(b2));
100 DepthRangeBody::ProductionDisparityHint { max, min }
101 }
102 0x01 => DepthRangeBody::MultiRegionSei,
104 _ => DepthRangeBody::Other(&sel[pos..pos + range_length]),
106 };
107 ranges.push(DepthRange { range_type, body });
108 pos += range_length;
109 }
110 Ok(VideoDepthRange { ranges })
111 }
112}
113
114impl Serialize for VideoDepthRange<'_> {
115 type Error = crate::error::Error;
116 fn serialized_len(&self) -> usize {
117 self.ranges
118 .iter()
119 .map(|r| {
120 VD_RANGE_HDR_LEN
121 + match &r.body {
122 DepthRangeBody::ProductionDisparityHint { .. } => VD_DISPARITY_LEN,
123 DepthRangeBody::MultiRegionSei => 0,
124 DepthRangeBody::Other(s) => s.len(),
125 }
126 })
127 .sum()
128 }
129 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
130 let len = self.serialized_len();
131 if buf.len() < len {
132 return Err(Error::OutputBufferTooSmall {
133 need: len,
134 have: buf.len(),
135 });
136 }
137 let mut p = 0;
138 for r in &self.ranges {
139 buf[p] = r.range_type;
140 match &r.body {
141 DepthRangeBody::ProductionDisparityHint { max, min } => {
142 buf[p + 1] = VD_DISPARITY_LEN as u8;
144 let max_bits = *max as u16 & 0x0FFF;
145 let min_bits = *min as u16 & 0x0FFF;
146 buf[p + 2] = (max_bits >> 4) as u8;
147 buf[p + 3] = (((max_bits & 0x0F) << 4) | ((min_bits >> 8) & 0x0F)) as u8;
148 buf[p + 4] = min_bits as u8;
149 p += VD_RANGE_HDR_LEN + VD_DISPARITY_LEN;
150 }
151 DepthRangeBody::MultiRegionSei => {
152 buf[p + 1] = 0;
153 p += VD_RANGE_HDR_LEN;
154 }
155 DepthRangeBody::Other(s) => {
156 buf[p + 1] = s.len() as u8;
157 buf[p + 2..p + 2 + s.len()].copy_from_slice(s);
158 p += VD_RANGE_HDR_LEN + s.len();
159 }
160 }
161 }
162 Ok(len)
163 }
164}
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169 use crate::descriptors::extension::test_support::*;
170 use crate::descriptors::extension::{ExtensionBody, ExtensionDescriptor, ExtensionTag};
171
172 #[test]
173 fn parse_video_depth_range_two_entries_round_trip() {
174 let max_val: i16 = 100;
180 let min_val: i16 = -50;
181 let max_b = max_val as u16 & 0x0FFF; let min_b = min_val as u16 & 0x0FFF; let sel = [
184 0x00,
185 0x03,
186 (max_b >> 4) as u8,
187 (((max_b & 0x0F) << 4) | ((min_b >> 8) & 0x0F)) as u8,
188 min_b as u8,
189 0x05,
190 0x02,
191 0xAA,
192 0xBB,
193 ];
194 let bytes = wrap(0x10, &sel);
195 let d = ExtensionDescriptor::parse(&bytes).unwrap();
196 assert_eq!(d.kind(), Some(ExtensionTag::VideoDepthRange));
197 match &d.body {
198 ExtensionBody::VideoDepthRange(b) => {
199 assert_eq!(b.ranges.len(), 2);
200 assert_eq!(b.ranges[0].range_type, 0x00);
201 match &b.ranges[0].body {
202 DepthRangeBody::ProductionDisparityHint { max, min } => {
203 assert_eq!(*max, 100);
204 assert_eq!(*min, -50);
205 }
206 _ => panic!("expected ProductionDisparityHint"),
207 }
208 assert_eq!(b.ranges[1].range_type, 0x05);
209 match &b.ranges[1].body {
210 DepthRangeBody::Other(s) => assert_eq!(s, &[0xAA, 0xBB]),
211 _ => panic!("expected Other"),
212 }
213 }
214 other => panic!("expected VideoDepthRange, got {other:?}"),
215 }
216 round_trip(&d);
218 }
219
220 #[test]
221 fn parse_video_depth_range_negative_edge_round_trip() {
222 let max_val: i16 = -1;
224 let min_val: i16 = 0;
225 let max_b = max_val as u16 & 0x0FFF;
226 let min_b = min_val as u16 & 0x0FFF;
227 let sel = [
228 0x00,
229 0x03,
230 (max_b >> 4) as u8,
231 (((max_b & 0x0F) << 4) | ((min_b >> 8) & 0x0F)) as u8,
232 min_b as u8,
233 ];
234 let bytes = wrap(0x10, &sel);
235 let d = ExtensionDescriptor::parse(&bytes).unwrap();
236 match &d.body {
237 ExtensionBody::VideoDepthRange(b) => {
238 assert_eq!(b.ranges.len(), 1);
239 match &b.ranges[0].body {
240 DepthRangeBody::ProductionDisparityHint { max, min } => {
241 assert_eq!(*max, -1);
242 assert_eq!(*min, 0);
243 }
244 _ => panic!("expected ProductionDisparityHint"),
245 }
246 }
247 other => panic!("expected VideoDepthRange, got {other:?}"),
248 }
249 round_trip(&d);
250 }
251
252 #[test]
253 fn parse_video_depth_range_multi_region_sei_round_trip() {
254 let sel = [0x01, 0x00, 0x01, 0x00];
256 let bytes = wrap(0x10, &sel);
257 let d = ExtensionDescriptor::parse(&bytes).unwrap();
258 match &d.body {
259 ExtensionBody::VideoDepthRange(b) => {
260 assert_eq!(b.ranges.len(), 2);
261 assert!(matches!(b.ranges[0].body, DepthRangeBody::MultiRegionSei));
262 assert!(matches!(b.ranges[1].body, DepthRangeBody::MultiRegionSei));
263 }
264 other => panic!("expected VideoDepthRange, got {other:?}"),
265 }
266 round_trip(&d);
267 }
268
269 #[test]
270 fn parse_video_depth_range_empty_selector() {
271 let bytes = wrap(0x10, &[]);
272 let d = ExtensionDescriptor::parse(&bytes).unwrap();
273 match &d.body {
274 ExtensionBody::VideoDepthRange(b) => {
275 assert!(b.ranges.is_empty());
276 }
277 other => panic!("expected VideoDepthRange, got {other:?}"),
278 }
279 round_trip(&d);
280 }
281
282 #[test]
283 fn parse_video_depth_range_rejects_truncated() {
284 let sel = [0x00];
286 let bytes = wrap(0x10, &sel);
287 assert!(matches!(
288 ExtensionDescriptor::parse(&bytes).unwrap_err(),
289 crate::error::Error::BufferTooShort { .. }
290 ));
291 }
292
293 #[test]
294 fn parse_video_depth_range_rejects_overrun() {
295 let sel = [0x00, 0x05, 0xAA, 0xBB];
297 let bytes = wrap(0x10, &sel);
298 assert!(matches!(
299 ExtensionDescriptor::parse(&bytes).unwrap_err(),
300 crate::error::Error::BufferTooShort { .. }
301 ));
302 }
303}