mpeg2ts_reader/psi/pat.rs
1//! Types related to the _Program Association Table_
2
3use crate::packet;
4use log::warn;
5
6/// The identifier of TS Packets containing Program Association Table sections, with value `0`.
7pub const PAT_PID: packet::Pid = packet::Pid::new(0);
8
9/// Identifiers related to a specific program within the Transport Stream
10#[derive(Clone, Debug)]
11pub enum ProgramDescriptor {
12 // TODO: consider renaming 'ProgramAssociationEntry', so as not to cause confusion with types
13 // actually implementing the Descriptor trait (which this type should not do)
14 /// this PAT section entry describes where the Network Information Table will be found
15 Network {
16 /// The PID of NIT section packets
17 pid: packet::Pid,
18 },
19 /// this PAT section entry gives the PID and Program Number of a program within this Transport
20 /// Stream
21 Program {
22 /// The program number might represent the 'channel' of the program
23 program_number: u16,
24 /// The PID where PMT sections for this program can be found
25 pid: packet::Pid,
26 },
27}
28
29impl ProgramDescriptor {
30 /// panics if fewer than 4 bytes are provided
31 pub fn from_bytes(data: &[u8]) -> ProgramDescriptor {
32 let program_number = (u16::from(data[0]) << 8) | u16::from(data[1]);
33 let pid = packet::Pid::new((u16::from(data[2]) & 0b0001_1111) << 8 | u16::from(data[3]));
34 if program_number == 0 {
35 ProgramDescriptor::Network { pid }
36 } else {
37 ProgramDescriptor::Program {
38 program_number,
39 pid,
40 }
41 }
42 }
43
44 /// produces the Pid of either the NIT or PMT, depending on which type of `ProgramDescriptor`
45 /// this is
46 pub fn pid(&self) -> packet::Pid {
47 match *self {
48 ProgramDescriptor::Network { pid } => pid,
49 ProgramDescriptor::Program { pid, .. } => pid,
50 }
51 }
52}
53
54/// Sections of the _Program Association Table_ give details of the programs within a transport
55/// stream. There may be only one program, or in the case of a broadcast multiplex, there may
56/// be many.
57#[derive(Clone, Debug)]
58pub struct PatSection<'buf> {
59 data: &'buf [u8],
60}
61impl<'buf> PatSection<'buf> {
62 /// Create a `PatSection`, wrapping the given slice, whose methods can parse the section's
63 /// fields
64 pub fn new(data: &'buf [u8]) -> PatSection<'buf> {
65 PatSection { data }
66 }
67 /// Returns an iterator over the entries in this program association table section.
68 pub fn programs(&self) -> impl Iterator<Item = ProgramDescriptor> + 'buf {
69 ProgramIter { buf: self.data }
70 }
71}
72
73/// Iterate over the list of programs in a `PatSection`.
74struct ProgramIter<'buf> {
75 buf: &'buf [u8],
76}
77impl<'buf> Iterator for ProgramIter<'buf> {
78 type Item = ProgramDescriptor;
79
80 fn next(&mut self) -> Option<Self::Item> {
81 if self.buf.is_empty() {
82 return None;
83 }
84 if self.buf.len() < 4 {
85 warn!(
86 "too few bytes remaining for PAT descriptor: {}",
87 self.buf.len()
88 );
89 return None;
90 }
91 let (head, tail) = self.buf.split_at(4);
92 self.buf = tail;
93 Some(ProgramDescriptor::from_bytes(head))
94 }
95}