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}