1use crate::descriptors::DescriptorLoop;
8use crate::error::{Error, Result};
9use crate::traits::Table;
10use dvb_common::{Parse, Serialize};
11
12pub const TABLE_ID: u8 = 0x02;
14pub const PID: u16 = 0x0000;
17
18const MIN_HEADER_LEN: usize = 3;
19const EXTENSION_HEADER_LEN: usize = 5;
20const PCR_PID_LEN: usize = 2;
21const PROG_INFO_LEN_BYTES: usize = 2;
22const CRC_LEN: usize = 4;
23const STREAM_HEADER_LEN: usize = 5;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(serde::Serialize))]
28pub struct PmtStream<'a> {
29 pub stream_type: u8,
31 pub elementary_pid: u16,
33 pub es_info: DescriptorLoop<'a>,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
41#[cfg_attr(feature = "serde", derive(serde::Serialize))]
42pub struct Pmt<'a> {
43 pub program_number: u16,
45 pub version_number: u8,
47 pub current_next_indicator: bool,
49 pub pcr_pid: u16,
51 pub program_info: DescriptorLoop<'a>,
55 pub streams: Vec<PmtStream<'a>>,
57}
58
59impl<'a> Parse<'a> for Pmt<'a> {
60 type Error = crate::error::Error;
61 fn parse(bytes: &'a [u8]) -> Result<Self> {
62 let min_len =
63 MIN_HEADER_LEN + EXTENSION_HEADER_LEN + PCR_PID_LEN + PROG_INFO_LEN_BYTES + CRC_LEN;
64 if bytes.len() < min_len {
65 return Err(Error::BufferTooShort {
66 need: min_len,
67 have: bytes.len(),
68 what: "Pmt",
69 });
70 }
71 if bytes[0] != TABLE_ID {
72 return Err(Error::UnexpectedTableId {
73 table_id: bytes[0],
74 what: "Pmt",
75 expected: &[TABLE_ID],
76 });
77 }
78
79 let section_length = ((bytes[1] & 0x0F) as u16) << 8 | bytes[2] as u16;
80 let total = MIN_HEADER_LEN + section_length as usize;
81 if bytes.len() < total {
82 return Err(Error::SectionLengthOverflow {
83 declared: section_length as usize,
84 available: bytes.len() - MIN_HEADER_LEN,
85 });
86 }
87
88 let program_number = u16::from_be_bytes([bytes[3], bytes[4]]);
89 let version_number = (bytes[5] >> 1) & 0x1F;
90 let current_next_indicator = (bytes[5] & 0x01) != 0;
91
92 let pcr_pid = (((bytes[8] & 0x1F) as u16) << 8) | bytes[9] as u16;
93 let program_info_length = (((bytes[10] & 0x0F) as usize) << 8) | bytes[11] as usize;
94
95 let prog_info_start =
96 MIN_HEADER_LEN + EXTENSION_HEADER_LEN + PCR_PID_LEN + PROG_INFO_LEN_BYTES;
97 let prog_info_end = prog_info_start + program_info_length;
98 let stream_loop_end = total - CRC_LEN;
99 if prog_info_end > stream_loop_end {
100 return Err(Error::SectionLengthOverflow {
101 declared: program_info_length,
102 available: stream_loop_end - prog_info_start,
103 });
104 }
105 let program_info = DescriptorLoop::new(&bytes[prog_info_start..prog_info_end]);
106
107 let mut streams = Vec::new();
108 let mut pos = prog_info_end;
109 while pos + STREAM_HEADER_LEN <= stream_loop_end {
110 let stream_type = bytes[pos];
111 let elementary_pid = (((bytes[pos + 1] & 0x1F) as u16) << 8) | bytes[pos + 2] as u16;
112 let es_info_length =
113 (((bytes[pos + 3] & 0x0F) as usize) << 8) | bytes[pos + 4] as usize;
114 let es_start = pos + STREAM_HEADER_LEN;
115 let es_end = es_start + es_info_length;
116 if es_end > stream_loop_end {
117 return Err(Error::SectionLengthOverflow {
118 declared: es_info_length,
119 available: stream_loop_end - es_start,
120 });
121 }
122 streams.push(PmtStream {
123 stream_type,
124 elementary_pid,
125 es_info: DescriptorLoop::new(&bytes[es_start..es_end]),
126 });
127 pos = es_end;
128 }
129
130 Ok(Pmt {
131 program_number,
132 version_number,
133 current_next_indicator,
134 pcr_pid,
135 program_info,
136 streams,
137 })
138 }
139}
140
141impl Serialize for Pmt<'_> {
142 type Error = crate::error::Error;
143 fn serialized_len(&self) -> usize {
144 let streams_bytes: usize = self
145 .streams
146 .iter()
147 .map(|s| STREAM_HEADER_LEN + s.es_info.len())
148 .sum();
149 MIN_HEADER_LEN
150 + EXTENSION_HEADER_LEN
151 + PCR_PID_LEN
152 + PROG_INFO_LEN_BYTES
153 + self.program_info.len()
154 + streams_bytes
155 + CRC_LEN
156 }
157
158 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
159 let len = self.serialized_len();
160 if buf.len() < len {
161 return Err(Error::OutputBufferTooSmall {
162 need: len,
163 have: buf.len(),
164 });
165 }
166
167 let section_length: u16 = (len - MIN_HEADER_LEN) as u16;
168 buf[0] = TABLE_ID;
169 buf[1] = 0xB0 | ((section_length >> 8) as u8 & 0x0F);
170 buf[2] = (section_length & 0xFF) as u8;
171 buf[3..5].copy_from_slice(&self.program_number.to_be_bytes());
172 buf[5] = 0xC0 | ((self.version_number & 0x1F) << 1) | u8::from(self.current_next_indicator);
173 buf[6] = 0;
174 buf[7] = 0;
175 buf[8] = 0xE0 | ((self.pcr_pid >> 8) as u8 & 0x1F);
176 buf[9] = (self.pcr_pid & 0xFF) as u8;
177 let pil = self.program_info.len() as u16;
178 buf[10] = 0xF0 | ((pil >> 8) as u8 & 0x0F);
179 buf[11] = (pil & 0xFF) as u8;
180
181 let prog_info_start =
182 MIN_HEADER_LEN + EXTENSION_HEADER_LEN + PCR_PID_LEN + PROG_INFO_LEN_BYTES;
183 buf[prog_info_start..prog_info_start + self.program_info.len()]
184 .copy_from_slice(self.program_info.raw());
185
186 let mut pos = prog_info_start + self.program_info.len();
187 for stream in &self.streams {
188 buf[pos] = stream.stream_type;
189 buf[pos + 1] = 0xE0 | ((stream.elementary_pid >> 8) as u8 & 0x1F);
190 buf[pos + 2] = (stream.elementary_pid & 0xFF) as u8;
191 let esl = stream.es_info.len() as u16;
192 buf[pos + 3] = 0xF0 | ((esl >> 8) as u8 & 0x0F);
193 buf[pos + 4] = (esl & 0xFF) as u8;
194 let es_start = pos + STREAM_HEADER_LEN;
195 buf[es_start..es_start + stream.es_info.len()].copy_from_slice(stream.es_info.raw());
196 pos = es_start + stream.es_info.len();
197 }
198
199 let crc_pos = len - CRC_LEN;
200 let crc = dvb_common::crc32_mpeg2::compute(&buf[..crc_pos]);
201 buf[crc_pos..len].copy_from_slice(&crc.to_be_bytes());
202 Ok(len)
203 }
204}
205
206impl<'a> Table<'a> for Pmt<'a> {
207 const TABLE_ID: u8 = TABLE_ID;
208 const PID: u16 = PID;
209}
210
211impl<'a> crate::traits::TableDef<'a> for Pmt<'a> {
212 const TABLE_ID_RANGES: &'static [(u8, u8)] = &[(TABLE_ID, TABLE_ID)];
213 const NAME: &'static str = "PROGRAM_MAP";
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 fn build_pmt(
222 program_number: u16,
223 version: u8,
224 pcr_pid: u16,
225 program_info: &[u8],
226 streams: &[(u8, u16, Vec<u8>)],
227 ) -> Vec<u8> {
228 let streams_bytes: usize = streams
229 .iter()
230 .map(|(_, _, es)| STREAM_HEADER_LEN + es.len())
231 .sum();
232 let section_length: u16 = (EXTENSION_HEADER_LEN
233 + PCR_PID_LEN
234 + PROG_INFO_LEN_BYTES
235 + program_info.len()
236 + streams_bytes
237 + CRC_LEN) as u16;
238 let mut v = Vec::new();
239 v.push(TABLE_ID);
240 v.push(0xB0 | ((section_length >> 8) as u8 & 0x0F));
241 v.push((section_length & 0xFF) as u8);
242 v.extend_from_slice(&program_number.to_be_bytes());
243 v.push(0xC0 | ((version & 0x1F) << 1) | 0x01);
244 v.push(0);
245 v.push(0);
246 v.push(0xE0 | ((pcr_pid >> 8) as u8 & 0x1F));
247 v.push((pcr_pid & 0xFF) as u8);
248 v.push(0xF0 | ((program_info.len() >> 8) as u8 & 0x0F));
249 v.push((program_info.len() & 0xFF) as u8);
250 v.extend_from_slice(program_info);
251 for (stype, pid, es) in streams {
252 v.push(*stype);
253 v.push(0xE0 | ((pid >> 8) as u8 & 0x1F));
254 v.push((pid & 0xFF) as u8);
255 v.push(0xF0 | ((es.len() >> 8) as u8 & 0x0F));
256 v.push((es.len() & 0xFF) as u8);
257 v.extend_from_slice(es);
258 }
259 v.extend_from_slice(&[0, 0, 0, 0]);
260 v
261 }
262
263 #[test]
264 fn parse_extracts_pcr_pid_and_program_info() {
265 let bytes = build_pmt(42, 5, 0x0100, &[0xAA, 0xBB], &[]);
266 let pmt = Pmt::parse(&bytes).unwrap();
267 assert_eq!(pmt.program_number, 42);
268 assert_eq!(pmt.version_number, 5);
269 assert!(pmt.current_next_indicator);
270 assert_eq!(pmt.pcr_pid, 0x0100);
271 assert_eq!(pmt.program_info.raw(), &[0xAA, 0xBB]);
272 assert_eq!(pmt.streams.len(), 0);
273 }
274
275 #[test]
276 fn parse_elementary_streams_and_es_info_slices() {
277 let bytes = build_pmt(
278 1,
279 0,
280 0x101,
281 &[],
282 &[(0x02, 0x102, vec![0x11, 0x22]), (0x1B, 0x103, vec![0x33])],
283 );
284 let pmt = Pmt::parse(&bytes).unwrap();
285 assert_eq!(pmt.streams.len(), 2);
286 assert_eq!(pmt.streams[0].stream_type, 0x02);
287 assert_eq!(pmt.streams[0].elementary_pid, 0x102);
288 assert_eq!(pmt.streams[0].es_info.raw(), &[0x11, 0x22]);
289 assert_eq!(pmt.streams[1].stream_type, 0x1B);
290 assert_eq!(pmt.streams[1].elementary_pid, 0x103);
291 assert_eq!(pmt.streams[1].es_info.raw(), &[0x33]);
292 }
293
294 #[test]
295 fn parse_rejects_wrong_table_id() {
296 let mut bytes = build_pmt(1, 0, 0x100, &[], &[]);
297 bytes[0] = 0x00;
298 let err = Pmt::parse(&bytes).unwrap_err();
299 assert!(matches!(
300 err,
301 Error::UnexpectedTableId { table_id: 0x00, .. }
302 ));
303 }
304
305 #[test]
306 fn parse_rejects_short_buffer() {
307 let err = Pmt::parse(&[0x02, 0x00]).unwrap_err();
308 assert!(matches!(err, Error::BufferTooShort { .. }));
309 }
310
311 #[test]
312 fn serialize_round_trip_empty_program() {
313 let pmt = Pmt {
314 program_number: 1,
315 version_number: 0,
316 current_next_indicator: true,
317 pcr_pid: 0x100,
318 program_info: DescriptorLoop::new(&[]),
319 streams: vec![],
320 };
321 let mut buf = vec![0u8; pmt.serialized_len()];
322 pmt.serialize_into(&mut buf).unwrap();
323 let re = Pmt::parse(&buf).unwrap();
324 assert_eq!(pmt, re);
325 }
326
327 #[test]
328 fn serialize_round_trip_with_streams_and_descriptors() {
329 let prog_info: [u8; 3] = [0x09, 0x01, 0xFF];
330 let es1: [u8; 4] = [0x52, 0x02, 0xAA, 0xBB];
331 let es2: [u8; 2] = [0x0A, 0x00];
332 let pmt = Pmt {
333 program_number: 0xABCD,
334 version_number: 7,
335 current_next_indicator: true,
336 pcr_pid: 0x1F0,
337 program_info: DescriptorLoop::new(&prog_info),
338 streams: vec![
339 PmtStream {
340 stream_type: 0x02,
341 elementary_pid: 0x100,
342 es_info: DescriptorLoop::new(&es1),
343 },
344 PmtStream {
345 stream_type: 0x03,
346 elementary_pid: 0x101,
347 es_info: DescriptorLoop::new(&es2),
348 },
349 PmtStream {
350 stream_type: 0x1B,
351 elementary_pid: 0x102,
352 es_info: DescriptorLoop::new(&[]),
353 },
354 ],
355 };
356 let mut buf = vec![0u8; pmt.serialized_len()];
357 pmt.serialize_into(&mut buf).unwrap();
358 let re = Pmt::parse(&buf).unwrap();
359 assert_eq!(pmt, re);
360 }
361
362 #[test]
363 fn zero_elementary_streams_is_valid() {
364 let bytes = build_pmt(99, 0, 0x0100, &[], &[]);
365 let pmt = Pmt::parse(&bytes).unwrap();
366 assert_eq!(pmt.streams.len(), 0);
367 }
368
369 #[test]
370 fn parse_preserves_raw_program_info_bytes() {
371 let pi = vec![0x09, 0x04, 0x01, 0x02, 0x03, 0x04];
372 let bytes = build_pmt(1, 0, 0x100, &pi, &[]);
373 let pmt = Pmt::parse(&bytes).unwrap();
374 assert_eq!(pmt.program_info.raw(), &pi[..]);
375 }
376}