1use alloc::vec::Vec;
8
9use crate::error::{Error, Result};
10use broadcast_common::{Parse, Serialize, crc32_mpeg2};
11
12pub const PACKET_START_CODE_PREFIX: u32 = 0x00_0001;
14pub const MAP_STREAM_ID: u8 = 0xBC;
16#[allow(dead_code)]
18pub const PSM_START_CODE: u32 = (PACKET_START_CODE_PREFIX << 8) | MAP_STREAM_ID as u32;
19
20const PREFIX_LEN: usize = 6;
22#[allow(dead_code)]
24const HEADER_LEN: usize = 13;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize))]
29pub struct EsMapEntry<'a> {
30 pub stream_type: u8,
32 pub elementary_stream_id: u8,
34 pub stream_id_extension: Option<u8>,
37 #[cfg_attr(feature = "serde", serde(skip))]
39 pub descriptors: &'a [u8],
40}
41
42#[derive(Debug, Clone, PartialEq, Eq)]
44struct OwnedEsMapEntry {
45 pub stream_type: u8,
46 pub elementary_stream_id: u8,
47 pub stream_id_extension: Option<u8>,
48 pub descriptors: Vec<u8>,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize))]
54pub struct ProgramStreamMap<'a> {
55 pub current_next_indicator: bool,
57 pub single_extension_stream_flag: bool,
59 pub version: u8,
61 #[cfg_attr(feature = "serde", serde(skip))]
63 pub program_stream_info: &'a [u8],
64 pub elementary_stream_map: Vec<EsMapEntry<'a>>,
66 pub crc: u32,
68}
69
70impl<'a> Parse<'a> for ProgramStreamMap<'a> {
71 type Error = Error;
72
73 fn parse(b: &'a [u8]) -> Result<Self> {
74 if b.len() < PREFIX_LEN + 2 + 4 {
75 return Err(Error::BufferTooShort {
77 need: PREFIX_LEN + 2 + 4,
78 have: b.len(),
79 what: "program_stream_map",
80 });
81 }
82
83 let start = u32::from_be_bytes([0, b[0], b[1], b[2]]);
85 if start != PACKET_START_CODE_PREFIX {
86 return Err(Error::BadMapStreamId(b[3]));
87 }
88 if b[3] != MAP_STREAM_ID {
89 return Err(Error::BadMapStreamId(b[3]));
90 }
91
92 let map_length = u16::from_be_bytes([b[4], b[5]]) as usize;
93 let crc_end = PREFIX_LEN + map_length + 4;
94 if b.len() < crc_end {
95 return Err(Error::MapLengthOverflow {
96 map_length,
97 available: b.len().saturating_sub(PREFIX_LEN),
98 });
99 }
100
101 let crc_data_end = crc_end - 4;
103 let crc_data = &b[0..crc_data_end];
104 let stored_crc = u32::from_be_bytes([
105 b[crc_data_end],
106 b[crc_data_end + 1],
107 b[crc_data_end + 2],
108 b[crc_data_end + 3],
109 ]);
110 let computed_crc = crc32_mpeg2::compute(crc_data);
111 if computed_crc != stored_crc {
112 return Err(Error::BadCrc {
113 computed: computed_crc,
114 stored: stored_crc,
115 });
116 }
117
118 let flags = b[6];
120 let current_next_indicator = flags & 0x80 != 0;
121 let single_extension_stream_flag = flags & 0x40 != 0;
122 let version = flags & 0x1F;
123
124 if b[7] & 0x01 == 0 {
126 return Err(Error::BadMarker("program_stream_map marker_bit"));
127 }
128
129 let program_stream_info_length = u16::from_be_bytes([b[8], b[9]]) as usize;
130 let elementary_stream_map_length = u16::from_be_bytes([b[10], b[11]]) as usize;
131
132 let info_start = PREFIX_LEN + 4; let info_end = info_start + program_stream_info_length;
134 let es_start = info_end + 2; let es_end = es_start + elementary_stream_map_length;
137
138 if crc_data_end < es_end {
139 return Err(Error::MapLengthOverflow {
140 map_length,
141 available: b.len().saturating_sub(PREFIX_LEN),
142 });
143 }
144
145 let program_stream_info = &b[info_start..info_end];
146
147 let es_data = &b[es_start..es_end];
149 let elementary_stream_map = parse_es_loop(es_data, single_extension_stream_flag)?;
150
151 Ok(ProgramStreamMap {
152 current_next_indicator,
153 single_extension_stream_flag,
154 version,
155 program_stream_info,
156 elementary_stream_map,
157 crc: stored_crc,
158 })
159 }
160}
161
162fn parse_es_loop(data: &[u8], single_flag: bool) -> Result<Vec<EsMapEntry<'_>>> {
163 let mut entries = Vec::new();
164 let mut pos = 0;
165 while pos + 4 <= data.len() {
166 let stream_type = data[pos];
167 let elementary_stream_id = data[pos + 1];
168 let es_info_length = u16::from_be_bytes([data[pos + 2], data[pos + 3]]) as usize;
169 let entry_hdr_end = pos + 4;
170 let entry_end = entry_hdr_end + es_info_length;
171 if entry_end > data.len() {
172 return Err(Error::BufferTooShort {
173 need: entry_end,
174 have: data.len(),
175 what: "elementary_stream_map entry descriptors",
176 });
177 }
178
179 let (stream_id_extension, descriptors) = if elementary_stream_id == 0xFD && !single_flag {
180 if es_info_length < 3 {
182 return Err(Error::BufferTooShort {
183 need: 3,
184 have: es_info_length,
185 what: "pseudo descriptor for stream_id_extension",
186 });
187 }
188 if data[entry_hdr_end + 2] & 0x80 == 0 {
190 return Err(Error::BadMarker("elementary_stream_id_extension marker"));
191 }
192 let ext = data[entry_hdr_end + 2] & 0x7F;
193 let desc = &data[entry_hdr_end + 3..entry_end];
194 (Some(ext), desc)
195 } else {
196 let desc = &data[entry_hdr_end..entry_end];
197 (None, desc)
198 };
199
200 entries.push(EsMapEntry {
201 stream_type,
202 elementary_stream_id,
203 stream_id_extension,
204 descriptors,
205 });
206
207 pos = entry_end;
208 }
209 Ok(entries)
210}
211
212fn serialize_es_loop(entries: &[OwnedEsMapEntry]) -> Vec<u8> {
213 let mut buf = Vec::new();
214 for e in entries {
215 buf.push(e.stream_type);
216 buf.push(e.elementary_stream_id);
217
218 let desc_len = if e.stream_id_extension.is_some() {
219 3 + e.descriptors.len()
221 } else {
222 e.descriptors.len()
223 };
224
225 buf.extend_from_slice(&(desc_len as u16).to_be_bytes());
226
227 if let Some(ext) = e.stream_id_extension {
228 buf.push(0x00); buf.push(1 + e.descriptors.len() as u8); buf.push(0x80 | (ext & 0x7F)); }
232
233 buf.extend_from_slice(&e.descriptors);
234 }
235 buf
236}
237
238impl Serialize for ProgramStreamMap<'_> {
239 type Error = Error;
240
241 fn serialized_len(&self) -> usize {
242 let prog_info_len = self.program_stream_info.len();
243 let es_loop_len: usize = self
244 .elementary_stream_map
245 .iter()
246 .map(|e| {
247 4 + if e.stream_id_extension.is_some() {
248 3 + e.descriptors.len()
249 } else {
250 e.descriptors.len()
251 }
252 })
253 .sum();
254 6 + 6 + prog_info_len + es_loop_len + 4
256 }
257
258 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
259 let total = self.serialized_len();
260 if buf.len() < total {
261 return Err(Error::BufferTooShort {
262 need: total,
263 have: buf.len(),
264 what: "program_stream_map serialize output",
265 });
266 }
267
268 buf[0..3].copy_from_slice(&PACKET_START_CODE_PREFIX.to_be_bytes()[1..]);
270 buf[3] = MAP_STREAM_ID;
272
273 let prog_info_len = self.program_stream_info.len();
274 let es_loop_data: Vec<u8> = serialize_es_loop(
275 &self
276 .elementary_stream_map
277 .iter()
278 .map(|e| OwnedEsMapEntry {
279 stream_type: e.stream_type,
280 elementary_stream_id: e.elementary_stream_id,
281 stream_id_extension: e.stream_id_extension,
282 descriptors: e.descriptors.to_vec(),
283 })
284 .collect::<Vec<_>>(),
285 );
286 let es_loop_len = es_loop_data.len();
287
288 let map_length = 6 + prog_info_len + es_loop_len;
290 buf[4..6].copy_from_slice(&(map_length as u16).to_be_bytes());
291
292 buf[6] = (u8::from(self.current_next_indicator) << 7)
294 | (u8::from(self.single_extension_stream_flag) << 6)
295 | (self.version & 0x1F);
296
297 buf[7] = 0x7F | 0x01;
299
300 buf[8..10].copy_from_slice(&(prog_info_len as u16).to_be_bytes());
302 buf[10..12].copy_from_slice(&(es_loop_len as u16).to_be_bytes());
304
305 buf[12..12 + prog_info_len].copy_from_slice(self.program_stream_info);
307
308 let es_start = 12 + prog_info_len;
310 buf[es_start..es_start + es_loop_len].copy_from_slice(&es_loop_data);
311
312 let crc_offset = es_start + es_loop_len;
314 let crc = crc32_mpeg2::compute(&buf[0..crc_offset]);
315 buf[crc_offset..crc_offset + 4].copy_from_slice(&crc.to_be_bytes());
316
317 Ok(total)
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use super::*;
324 use alloc::vec;
325
326 #[test]
328 fn psm_build_and_round_trip() {
329 let entries = vec![EsMapEntry {
330 stream_type: 0x02, elementary_stream_id: 0xE0,
332 stream_id_extension: None,
333 descriptors: &[0x0A, 0x04, b'H', b'E', b'L', b'L'], }];
335
336 let psm = ProgramStreamMap {
337 current_next_indicator: true,
338 single_extension_stream_flag: false,
339 version: 3,
340 program_stream_info: &[],
341 elementary_stream_map: entries,
342 crc: 0, };
344
345 let mut buf = vec![0u8; psm.serialized_len()];
346 psm.serialize_into(&mut buf).unwrap();
347
348 let parsed = ProgramStreamMap::parse(&buf).unwrap();
350 assert!(parsed.current_next_indicator);
351 assert!(!parsed.single_extension_stream_flag);
352 assert_eq!(parsed.version, 3);
353 assert!(parsed.program_stream_info.is_empty());
354 assert_eq!(parsed.elementary_stream_map.len(), 1);
355 assert_eq!(parsed.elementary_stream_map[0].stream_type, 0x02);
356 assert_eq!(parsed.elementary_stream_map[0].elementary_stream_id, 0xE0);
357 assert!(
358 parsed.elementary_stream_map[0]
359 .stream_id_extension
360 .is_none()
361 );
362 assert_eq!(
363 parsed.elementary_stream_map[0].descriptors,
364 &[0x0A, 0x04, b'H', b'E', b'L', b'L']
365 );
366
367 let mut out2 = vec![0u8; parsed.serialized_len()];
369 parsed.serialize_into(&mut out2).unwrap();
370 assert_eq!(&out2[..], &buf[..], "byte-exact round-trip mismatch");
371
372 let psm_mut = ProgramStreamMap {
374 current_next_indicator: true,
375 single_extension_stream_flag: false,
376 version: 7,
377 program_stream_info: &[],
378 elementary_stream_map: vec![EsMapEntry {
379 stream_type: 0x02,
380 elementary_stream_id: 0xE0,
381 stream_id_extension: None,
382 descriptors: &[0x0A, 0x04, b'H', b'E', b'L', b'L'],
383 }],
384 crc: 0,
385 };
386 let mut out3 = vec![0u8; psm_mut.serialized_len()];
387 psm_mut.serialize_into(&mut out3).unwrap();
388 assert_ne!(&buf[..], &out3[..]);
389 }
390
391 #[test]
392 fn psm_with_stream_id_extension() {
393 let entries = vec![EsMapEntry {
394 stream_type: 0x06, elementary_stream_id: 0xFD,
396 stream_id_extension: Some(0x0F),
397 descriptors: &[0x59, 0x02, 0x01, 0x02], }];
399
400 let psm = ProgramStreamMap {
401 current_next_indicator: true,
402 single_extension_stream_flag: false,
403 version: 1,
404 program_stream_info: &[],
405 elementary_stream_map: entries,
406 crc: 0,
407 };
408
409 let mut buf = vec![0u8; psm.serialized_len()];
410 psm.serialize_into(&mut buf).unwrap();
411
412 let parsed = ProgramStreamMap::parse(&buf).unwrap();
413 assert_eq!(parsed.elementary_stream_map.len(), 1);
414 assert_eq!(
415 parsed.elementary_stream_map[0].stream_id_extension,
416 Some(0x0F)
417 );
418 assert_eq!(
419 parsed.elementary_stream_map[0].descriptors,
420 &[0x59, 0x02, 0x01, 0x02]
421 );
422
423 let mut out2 = vec![0u8; parsed.serialized_len()];
425 parsed.serialize_into(&mut out2).unwrap();
426 assert_eq!(&out2[..], &buf[..]);
427 }
428
429 #[test]
430 fn psm_bad_crc_rejected() {
431 let psm = ProgramStreamMap {
432 current_next_indicator: true,
433 single_extension_stream_flag: false,
434 version: 0,
435 program_stream_info: &[],
436 elementary_stream_map: vec![],
437 crc: 0,
438 };
439 let mut buf = vec![0u8; psm.serialized_len()];
440 psm.serialize_into(&mut buf).unwrap();
441 let crc_off = buf.len() - 4;
443 buf[crc_off] ^= 0xFF;
444 assert!(matches!(
445 ProgramStreamMap::parse(&buf),
446 Err(Error::BadCrc { .. })
447 ));
448 }
449}