1use crate::error::{Error, Result};
7use broadcast_common::{Parse, Serialize};
8
9pub const SEGMENT_TYPE: u8 = 0x15;
11pub const HEADER_LEN: usize = 6;
13pub const FIXED_LEN: usize = 2;
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize))]
19pub struct DisparityShiftUpdateSequence {
20 pub interval_duration: u32,
22 pub division_period_count: u8,
24 pub intervals: alloc::vec::Vec<DisparityShiftInterval>,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize))]
31pub struct DisparityShiftInterval {
32 pub interval_count: u8,
34 pub disparity_shift_integer: i8,
36}
37
38impl DisparityShiftUpdateSequence {
39 fn serialized_len(&self) -> usize {
40 1 + 3 + 1 + self.intervals.len() * 2
41 }
42
43 fn serialize_into(&self, buf: &mut [u8]) {
44 let body_len = 3 + 1 + self.intervals.len() * 2;
45 buf[0] = body_len as u8;
46 buf[1] = (self.interval_duration >> 16) as u8;
47 buf[2] = (self.interval_duration >> 8) as u8;
48 buf[3] = self.interval_duration as u8;
49 buf[4] = self.division_period_count;
50 for (i, interval) in self.intervals.iter().enumerate() {
51 let off = 5 + i * 2;
52 buf[off] = interval.interval_count;
53 buf[off + 1] = interval.disparity_shift_integer as u8;
54 }
55 }
56
57 fn parse(bytes: &[u8]) -> Result<(Self, usize)> {
58 if bytes.len() < 5 {
59 return Err(Error::BufferTooShort {
60 need: 5,
61 have: bytes.len(),
62 what: "disparity_shift_update_sequence",
63 });
64 }
65 let seq_len = bytes[0] as usize;
66 if bytes.len() < 1 + seq_len {
67 return Err(Error::BufferTooShort {
68 need: 1 + seq_len,
69 have: bytes.len(),
70 what: "disparity_shift_update_sequence data",
71 });
72 }
73 let dur = ((bytes[1] as u32) << 16) | ((bytes[2] as u32) << 8) | (bytes[3] as u32);
74 let count = bytes[4];
75 let total = 1 + seq_len;
76 let mut intervals = alloc::vec::Vec::new();
77 let mut ipos = 5;
78 for _ in 0..count {
79 if ipos + 2 > total {
80 return Err(Error::BufferTooShort {
81 need: ipos + 2,
82 have: total,
83 what: "disparity_shift_update_sequence interval",
84 });
85 }
86 intervals.push(DisparityShiftInterval {
87 interval_count: bytes[ipos],
88 disparity_shift_integer: bytes[ipos + 1] as i8,
89 });
90 ipos += 2;
91 }
92 Ok((
93 DisparityShiftUpdateSequence {
94 interval_duration: dur,
95 division_period_count: count,
96 intervals,
97 },
98 total,
99 ))
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Eq)]
105#[cfg_attr(feature = "serde", derive(serde::Serialize))]
106pub struct Subregion {
107 pub subregion_horizontal_position: Option<u16>,
109 pub subregion_width: Option<u16>,
111 pub subregion_disparity_shift_integer: i8,
113 pub subregion_disparity_shift_fractional: u8,
115 pub reserved: u8,
117 pub update_sequence: Option<DisparityShiftUpdateSequence>,
119}
120
121impl Subregion {
122 fn serialized_len(&self) -> usize {
123 let base = if self.subregion_horizontal_position.is_some() {
124 4 + 2
125 } else {
126 2
127 };
128 base + self
129 .update_sequence
130 .as_ref()
131 .map_or(0, |u| u.serialized_len())
132 }
133
134 fn serialize_into(&self, buf: &mut [u8]) {
135 let mut off = 0;
136 if let (Some(h), Some(w)) = (self.subregion_horizontal_position, self.subregion_width) {
137 buf[0..2].copy_from_slice(&h.to_be_bytes());
138 buf[2..4].copy_from_slice(&w.to_be_bytes());
139 off = 4;
140 }
141 buf[off] = self.subregion_disparity_shift_integer as u8;
142 buf[off + 1] = (self.subregion_disparity_shift_fractional << 4) | (self.reserved & 0x0F);
143 off += 2;
144 if let Some(ref seq) = self.update_sequence {
145 seq.serialize_into(&mut buf[off..]);
146 }
147 }
148}
149
150#[derive(Debug, Clone, PartialEq, Eq)]
152#[cfg_attr(feature = "serde", derive(serde::Serialize))]
153pub struct DisparityRegion {
154 pub region_id: u8,
156 pub update_sequence_region_flag: bool,
158 pub reserved_flags: u8,
160 pub subregions: alloc::vec::Vec<Subregion>,
162}
163
164impl DisparityRegion {
165 fn serialized_len(&self) -> usize {
166 2 + self
167 .subregions
168 .iter()
169 .map(|s| s.serialized_len())
170 .sum::<usize>()
171 }
172
173 fn serialize_into(&self, buf: &mut [u8]) {
174 let num = self.subregions.len().saturating_sub(1) as u8;
175 buf[0] = self.region_id;
176 buf[1] = (u8::from(self.update_sequence_region_flag) << 7)
177 | (self.reserved_flags & 0x7C)
178 | (num & 0x03);
179 let mut off = 2;
180 for sub in &self.subregions {
181 sub.serialize_into(&mut buf[off..]);
182 off += sub.serialized_len();
183 }
184 }
185}
186
187#[derive(Debug, Clone, PartialEq, Eq)]
189#[cfg_attr(feature = "serde", derive(serde::Serialize))]
190pub struct DisparitySignallingSegment {
191 pub page_id: u16,
193 pub dss_version_number: u8,
195 pub update_sequence_page_flag: bool,
197 pub reserved: u8,
199 pub page_default_disparity_shift: i8,
201 pub page_update_sequence: Option<DisparityShiftUpdateSequence>,
203 pub regions: alloc::vec::Vec<DisparityRegion>,
205}
206
207impl<'a> Parse<'a> for DisparitySignallingSegment {
208 type Error = Error;
209
210 fn parse(bytes: &'a [u8]) -> Result<Self> {
211 if bytes.len() < HEADER_LEN + FIXED_LEN {
212 return Err(Error::BufferTooShort {
213 need: HEADER_LEN + FIXED_LEN,
214 have: bytes.len(),
215 what: "disparity_signalling_segment",
216 });
217 }
218 if bytes[1] != SEGMENT_TYPE {
219 return Err(Error::UnknownSegmentType(bytes[1]));
220 }
221 let page_id = u16::from_be_bytes([bytes[2], bytes[3]]);
222 let segment_length = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
223 let total = HEADER_LEN + segment_length;
224 if bytes.len() < total {
225 return Err(Error::BufferTooShort {
226 need: total,
227 have: bytes.len(),
228 what: "disparity_signalling_segment data",
229 });
230 }
231 let body = &bytes[HEADER_LEN..HEADER_LEN + segment_length];
232 if body.len() < FIXED_LEN {
233 return Err(Error::BufferTooShort {
234 need: FIXED_LEN,
235 have: body.len(),
236 what: "disparity_signalling_segment body",
237 });
238 }
239 let dss_version_number = body[0] >> 4;
240 let update_sequence_page_flag = (body[0] & 0x08) != 0;
241 let reserved = body[0] & 0x07;
242 let page_default_disparity_shift = body[1] as i8;
243
244 let mut pos = FIXED_LEN;
245 let page_update_sequence = if update_sequence_page_flag {
246 let (seq, seq_len) = DisparityShiftUpdateSequence::parse(&body[pos..])?;
247 pos += seq_len;
248 Some(seq)
249 } else {
250 None
251 };
252
253 let mut regions = alloc::vec::Vec::new();
254 while pos < body.len() {
255 if pos + 2 > body.len() {
256 break;
257 }
258 let region_id = body[pos];
259 pos += 1;
260 let update_flag = (body[pos] & 0x80) != 0;
261 let reserved_flags = body[pos] & 0x7C;
262 let num_subregions_minus_1 = body[pos] & 0x03;
263 pos += 1;
264
265 let mut subregions = alloc::vec::Vec::new();
266 for _n in 0..=num_subregions_minus_1 {
267 let has_pos = num_subregions_minus_1 > 0;
268 let entry_len = if has_pos { 4 + 2 } else { 2 };
269 if pos + entry_len > body.len() {
270 return Err(Error::BufferTooShort {
271 need: pos + entry_len,
272 have: body.len(),
273 what: "subregion entry",
274 });
275 }
276
277 let (hpos, width) = if has_pos {
278 let h = u16::from_be_bytes([body[pos], body[pos + 1]]);
279 let w = u16::from_be_bytes([body[pos + 2], body[pos + 3]]);
280 pos += 4;
281 (Some(h), Some(w))
282 } else {
283 (None, None)
284 };
285
286 let shift_int = body[pos] as i8;
287 let shift_frac = body[pos + 1] >> 4;
288 let reserved = body[pos + 1] & 0x0F;
289 pos += 2;
290
291 let sub_update = if update_flag {
292 let (seq, seq_len) = DisparityShiftUpdateSequence::parse(&body[pos..])?;
293 pos += seq_len;
294 Some(seq)
295 } else {
296 None
297 };
298
299 subregions.push(Subregion {
300 subregion_horizontal_position: hpos,
301 subregion_width: width,
302 subregion_disparity_shift_integer: shift_int,
303 subregion_disparity_shift_fractional: shift_frac,
304 reserved,
305 update_sequence: sub_update,
306 });
307 }
308
309 regions.push(DisparityRegion {
310 region_id,
311 update_sequence_region_flag: update_flag,
312 reserved_flags,
313 subregions,
314 });
315 }
316
317 Ok(DisparitySignallingSegment {
318 page_id,
319 dss_version_number,
320 update_sequence_page_flag,
321 reserved,
322 page_default_disparity_shift,
323 page_update_sequence,
324 regions,
325 })
326 }
327}
328
329impl Serialize for DisparitySignallingSegment {
330 type Error = Error;
331
332 fn serialized_len(&self) -> usize {
333 HEADER_LEN
334 + FIXED_LEN
335 + self
336 .page_update_sequence
337 .as_ref()
338 .map_or(0, |s| s.serialized_len())
339 + self
340 .regions
341 .iter()
342 .map(|r| r.serialized_len())
343 .sum::<usize>()
344 }
345
346 fn serialize_into(&self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
347 let len = self.serialized_len();
348 if buf.len() < len {
349 return Err(Error::BufferTooShort {
350 need: len,
351 have: buf.len(),
352 what: "disparity_signalling_segment serialize",
353 });
354 }
355 buf[0] = 0x0F;
356 buf[1] = SEGMENT_TYPE;
357 buf[2..4].copy_from_slice(&self.page_id.to_be_bytes());
358 let seg_len = (len - HEADER_LEN) as u16;
359 buf[4..6].copy_from_slice(&seg_len.to_be_bytes());
360
361 buf[6] = (self.dss_version_number << 4)
362 | (u8::from(self.update_sequence_page_flag) << 3)
363 | (self.reserved & 0x07);
364 buf[7] = self.page_default_disparity_shift as u8;
365
366 let mut off = HEADER_LEN + FIXED_LEN;
367 if let Some(ref seq) = self.page_update_sequence {
368 seq.serialize_into(&mut buf[off..]);
369 off += seq.serialized_len();
370 }
371 for region in &self.regions {
372 region.serialize_into(&mut buf[off..]);
373 off += region.serialized_len();
374 }
375 Ok(len)
376 }
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382 use broadcast_common::{Parse, Serialize};
383
384 #[test]
385 fn round_trip_simple() {
386 let bytes = [
387 0x0F, 0x15, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
388 ];
389 let seg = DisparitySignallingSegment::parse(&bytes).unwrap();
390 assert_eq!(seg.dss_version_number, 0);
391 assert!(!seg.update_sequence_page_flag);
392 assert_eq!(seg.regions.len(), 1);
393 assert_eq!(seg.regions[0].region_id, 1);
394 assert_eq!(seg.regions[0].subregions.len(), 1);
395 let out = seg.to_bytes();
396 assert_eq!(out, bytes);
397
398 let mut seg2 = seg.clone();
400 seg2.regions[0].region_id = 5;
401 let out2 = seg2.to_bytes();
402 assert_ne!(out2, bytes);
403 let reparse = DisparitySignallingSegment::parse(&out2).unwrap();
404 assert_eq!(reparse.regions[0].region_id, 5);
405 }
406
407 #[test]
408 fn round_trip_with_page_update_seq() {
409 let bytes = [
410 0x0F, 0x15, 0x00, 0x01, 0x00, 0x0B, 0x88, 0x05, 0x08, 0x00, 0x00, 0x0A, 0x02, 0x01,
411 0x10, 0x03, 0x20,
412 ];
413 let seg = DisparitySignallingSegment::parse(&bytes).unwrap();
414 assert_eq!(seg.dss_version_number, 8);
415 assert!(seg.update_sequence_page_flag);
416 assert_eq!(seg.regions.len(), 0);
417 let out = seg.to_bytes();
418 assert_eq!(out, bytes);
419
420 let mut seg2 = seg.clone();
422 seg2.page_default_disparity_shift = 10;
423 let out2 = seg2.to_bytes();
424 assert_ne!(out2, bytes);
425 let reparse = DisparitySignallingSegment::parse(&out2).unwrap();
426 assert_eq!(reparse.page_default_disparity_shift, 10);
427 }
428
429 #[test]
430 fn round_trip_with_update_sequence() {
431 let bytes = [
432 0x0F, 0x15, 0x00, 0x01, 0x00, 0x16, 0x88, 0x05, 0x08, 0x00, 0x00, 0x0A, 0x02, 0x01,
433 0x10, 0x03, 0x20, 0x01, 0x80, 0x10, 0x00, 0x06, 0x00, 0x00, 0x14, 0x01, 0x01, 0x08,
434 ];
435 let seg = DisparitySignallingSegment::parse(&bytes).unwrap();
436 assert_eq!(seg.dss_version_number, 8);
437 assert!(seg.update_sequence_page_flag);
438 assert_eq!(seg.page_default_disparity_shift, 5);
439 let seq = seg.page_update_sequence.as_ref().unwrap();
440 assert_eq!(seq.division_period_count, 2);
441 assert_eq!(seg.regions.len(), 1);
442 assert_eq!(seg.regions[0].region_id, 1);
443 assert!(seg.regions[0].update_sequence_region_flag);
444 assert_eq!(seg.regions[0].subregions.len(), 1);
445 let out = seg.to_bytes();
446 assert_eq!(out, bytes);
447
448 let mut seg2 = seg.clone();
450 seg2.dss_version_number = 3;
451 let out2 = seg2.to_bytes();
452 assert_ne!(out2, bytes);
453 let reparse = DisparitySignallingSegment::parse(&out2).unwrap();
454 assert_eq!(reparse.dss_version_number, 3);
455 }
456}