1use crate::error::{Error, Result};
4use broadcast_common::{Parse, Serialize};
5
6pub const SEGMENT_TYPE: u8 = 0x12;
8pub const HEADER_LEN: usize = 6;
10pub const FIXED_LEN: usize = 2;
12pub const ENTRY_HEADER_LEN: usize = 2;
14pub const ENTRY_FULL_LEN: usize = 4;
16pub const ENTRY_REDUCED_LEN: usize = 2;
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22pub struct ClutEntry {
23 pub clut_entry_id: u8,
25 pub flag_2bit: bool,
27 pub flag_4bit: bool,
29 pub flag_8bit: bool,
31 pub reserved_flags: u8,
33 pub full_range_flag: bool,
35 pub y_value: u8,
37 pub cr_value: u8,
39 pub cb_value: u8,
41 pub t_value: u8,
43}
44
45impl ClutEntry {
46 fn serialized_len(&self) -> usize {
47 ENTRY_HEADER_LEN
48 + if self.full_range_flag {
49 ENTRY_FULL_LEN
50 } else {
51 ENTRY_REDUCED_LEN
52 }
53 }
54
55 fn serialize_into(&self, buf: &mut [u8]) {
56 buf[0] = self.clut_entry_id;
57 let mut flags: u8 = self.reserved_flags;
58 if self.flag_2bit {
59 flags |= 0x80;
60 }
61 if self.flag_4bit {
62 flags |= 0x40;
63 }
64 if self.flag_8bit {
65 flags |= 0x20;
66 }
67 if self.full_range_flag {
68 flags |= 0x01;
69 }
70 buf[1] = flags;
71 if self.full_range_flag {
72 buf[2] = self.y_value;
73 buf[3] = self.cr_value;
74 buf[4] = self.cb_value;
75 buf[5] = self.t_value;
76 } else {
77 buf[2] = (self.y_value << 2) | (self.cr_value >> 2);
78 buf[3] = (self.cr_value << 6) | (self.cb_value << 2) | self.t_value;
79 }
80 }
81
82 fn parse(bytes: &[u8]) -> Result<(Self, usize)> {
83 if bytes.len() < ENTRY_HEADER_LEN {
84 return Err(Error::BufferTooShort {
85 need: ENTRY_HEADER_LEN,
86 have: bytes.len(),
87 what: "CLUT_entry header",
88 });
89 }
90 let clut_entry_id = bytes[0];
91 let flag_2bit = (bytes[1] & 0x80) != 0;
92 let flag_4bit = (bytes[1] & 0x40) != 0;
93 let flag_8bit = (bytes[1] & 0x20) != 0;
94 let reserved_flags = bytes[1] & 0x1E;
95 let full_range_flag = (bytes[1] & 0x01) != 0;
96
97 let total = ENTRY_HEADER_LEN
98 + if full_range_flag {
99 ENTRY_FULL_LEN
100 } else {
101 ENTRY_REDUCED_LEN
102 };
103 if bytes.len() < total {
104 return Err(Error::BufferTooShort {
105 need: total,
106 have: bytes.len(),
107 what: "CLUT_entry data",
108 });
109 }
110 let (y, cr, cb, t) = if full_range_flag {
111 (bytes[2], bytes[3], bytes[4], bytes[5])
112 } else {
113 let y = bytes[2] >> 2;
114 let cr = ((bytes[2] & 0x03) << 2) | (bytes[3] >> 6);
115 let cb = (bytes[3] >> 2) & 0x0F;
116 let t = bytes[3] & 0x03;
117 (y, cr, cb, t)
118 };
119 Ok((
120 ClutEntry {
121 clut_entry_id,
122 flag_2bit,
123 flag_4bit,
124 flag_8bit,
125 reserved_flags,
126 full_range_flag,
127 y_value: y,
128 cr_value: cr,
129 cb_value: cb,
130 t_value: t,
131 },
132 total,
133 ))
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq)]
139#[cfg_attr(feature = "serde", derive(serde::Serialize))]
140pub struct ClutDefinitionSegment {
141 pub page_id: u16,
143 pub clut_id: u8,
145 pub clut_version_number: u8,
147 pub reserved: u8,
149 pub entries: alloc::vec::Vec<ClutEntry>,
151 #[cfg_attr(feature = "serde", serde(skip))]
153 pub(crate) suffix: alloc::vec::Vec<u8>,
154}
155
156impl<'a> Parse<'a> for ClutDefinitionSegment {
157 type Error = Error;
158
159 fn parse(bytes: &'a [u8]) -> Result<Self> {
160 if bytes.len() < HEADER_LEN + FIXED_LEN {
161 return Err(Error::BufferTooShort {
162 need: HEADER_LEN + FIXED_LEN,
163 have: bytes.len(),
164 what: "CLUT_definition_segment",
165 });
166 }
167 if bytes[0] != crate::pes_data_field::SYNC_BYTE {
168 return Err(Error::BadSyncByte(bytes[0]));
169 }
170 if bytes[1] != SEGMENT_TYPE {
171 return Err(Error::UnknownSegmentType(bytes[1]));
172 }
173 let page_id = u16::from_be_bytes([bytes[2], bytes[3]]);
174 let segment_length = u16::from_be_bytes([bytes[4], bytes[5]]) as usize;
175 let total = HEADER_LEN + segment_length;
176 if bytes.len() < total {
177 return Err(Error::BufferTooShort {
178 need: total,
179 have: bytes.len(),
180 what: "CLUT_definition_segment data",
181 });
182 }
183 let body = &bytes[HEADER_LEN..HEADER_LEN + segment_length];
184 if body.len() < FIXED_LEN {
185 return Err(Error::BufferTooShort {
186 need: FIXED_LEN,
187 have: body.len(),
188 what: "CLUT_definition_segment body",
189 });
190 }
191 let clut_id = body[0];
192 let clut_version_number = body[1] >> 4;
193 let reserved = body[1] & 0x0F;
194
195 let rest = &body[FIXED_LEN..];
196 let mut entries = alloc::vec::Vec::new();
197 let mut pos: usize = 0;
198 let mut suffix = alloc::vec::Vec::new();
199 while pos < rest.len() {
200 match ClutEntry::parse(&rest[pos..]) {
201 Ok((entry, entry_len)) => {
202 entries.push(entry);
203 pos += entry_len;
204 }
205 Err(_) => {
206 suffix.extend_from_slice(&rest[pos..]);
208 break;
209 }
210 }
211 }
212
213 Ok(ClutDefinitionSegment {
214 page_id,
215 clut_id,
216 clut_version_number,
217 reserved,
218 entries,
219 suffix,
220 })
221 }
222}
223
224impl Serialize for ClutDefinitionSegment {
225 type Error = Error;
226
227 fn serialized_len(&self) -> usize {
228 HEADER_LEN
229 + FIXED_LEN
230 + self
231 .entries
232 .iter()
233 .map(|e| e.serialized_len())
234 .sum::<usize>()
235 + self.suffix.len()
236 }
237
238 fn serialize_into(&self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
239 let len = self.serialized_len();
240 if buf.len() < len {
241 return Err(Error::BufferTooShort {
242 need: len,
243 have: buf.len(),
244 what: "CLUT_definition_segment serialize",
245 });
246 }
247 buf[0] = 0x0F;
248 buf[1] = SEGMENT_TYPE;
249 buf[2..4].copy_from_slice(&self.page_id.to_be_bytes());
250 let seg_len = crate::segments::check_segment_length(len - HEADER_LEN)?;
251 buf[4..6].copy_from_slice(&seg_len.to_be_bytes());
252
253 buf[6] = self.clut_id;
254 buf[7] = (self.clut_version_number << 4) | (self.reserved & 0x0F);
255
256 let mut off = HEADER_LEN + FIXED_LEN;
257 for entry in &self.entries {
258 entry.serialize_into(&mut buf[off..]);
259 off += entry.serialized_len();
260 }
261 buf[off..off + self.suffix.len()].copy_from_slice(&self.suffix);
262 Ok(len)
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269 use broadcast_common::{Parse, Serialize};
270
271 #[test]
272 fn round_trip_full_range() {
273 let bytes = [
274 0x0F, 0x12, 0x00, 0x01, 0x00, 0x0E, 0x03, 0x10, 0x00, 0xA1, 0x80, 0x80, 0x80, 0x80,
275 0x01, 0x61, 0xFF, 0xFF, 0xFF, 0x00,
276 ];
277 let seg = ClutDefinitionSegment::parse(&bytes).unwrap();
278 assert_eq!(seg.clut_id, 3);
279 assert_eq!(seg.entries.len(), 2);
280 assert_eq!(seg.entries[0].clut_entry_id, 0);
281 assert!(seg.entries[0].flag_8bit);
282 assert!(seg.entries[0].full_range_flag);
283 assert_eq!(seg.entries[0].y_value, 128);
284 assert_eq!(seg.entries[1].clut_entry_id, 1);
285 assert!(seg.entries[1].flag_4bit);
286 let out = seg.to_bytes();
287 assert_eq!(out, bytes);
288
289 let mut seg2 = seg.clone();
291 seg2.clut_id = 5;
292 let out2 = seg2.to_bytes();
293 assert_ne!(out2, bytes);
294 let reparse = ClutDefinitionSegment::parse(&out2).unwrap();
295 assert_eq!(reparse.clut_id, 5);
296 }
297
298 #[test]
300 fn rejects_bad_sync_byte() {
301 let bytes = [
302 0x00, 0x12, 0x00, 0x01, 0x00, 0x0E, 0x03, 0x10, 0x00, 0xA1, 0x80, 0x80, 0x80, 0x80,
303 0x01, 0x61, 0xFF, 0xFF, 0xFF, 0x00,
304 ];
305 assert!(matches!(
306 ClutDefinitionSegment::parse(&bytes),
307 Err(Error::BadSyncByte(0x00))
308 ));
309 }
310
311 #[test]
312 fn round_trip_reduced_range() {
313 let bytes = [
314 0x0F, 0x12, 0x00, 0x01, 0x00, 0x0A, 0x03, 0x10, 0x00, 0x80, 0x00, 0x00, 0x01, 0x40,
315 0xFD, 0xFC,
316 ];
317 let seg = ClutDefinitionSegment::parse(&bytes).unwrap();
318 assert_eq!(seg.entries.len(), 2);
319 assert!(seg.entries[0].flag_2bit);
320 assert!(!seg.entries[0].full_range_flag);
321 assert_eq!(seg.entries[0].y_value, 0);
322 let out = seg.to_bytes();
323 assert_eq!(out, bytes);
324
325 let mut seg2 = seg.clone();
327 seg2.entries[0].flag_2bit = false;
328 seg2.entries[0].flag_8bit = true;
329 let out2 = seg2.to_bytes();
330 assert_ne!(out2, bytes);
331 let reparse = ClutDefinitionSegment::parse(&out2).unwrap();
332 assert!(reparse.entries[0].flag_8bit);
333 }
334
335 #[test]
336 fn tolerates_nonzero_reserved_bits() {
337 let bytes = [
338 0x0F, 0x12, 0x00, 0x01, 0x00,
339 0x06, 0x03, 0x1A, 0x00, 0x8A, 0x00,
342 0x00, ];
344 let seg = ClutDefinitionSegment::parse(&bytes).unwrap();
345 assert_eq!(seg.reserved, 0x0A);
346 assert_eq!(seg.entries.len(), 1);
347 assert_eq!(seg.entries[0].reserved_flags, 0x0A);
348 assert!(seg.entries[0].flag_2bit);
349 let out = seg.to_bytes();
350 assert_eq!(out, bytes);
351 let seg2 = ClutDefinitionSegment::parse(&out).unwrap();
352 assert_eq!(seg2.reserved, 0x0A);
353 assert_eq!(seg2.entries[0].reserved_flags, 0x0A);
354 }
355}