va_ts/section/
pat.rs

1use std::fmt;
2
3use crate::error::{Error, Kind as ErrorKind};
4use crate::pid::PID as TsPID;
5use crate::result::Result;
6use crate::subtable_id::{SubtableID, SubtableIDer};
7
8use super::traits::*;
9
10/// ISO/IEC 13818-1
11///
12/// Program association Table
13pub struct PAT<'buf> {
14    buf: &'buf [u8],
15}
16
17impl<'buf> PAT<'buf> {
18    const HEADER_FULL_SZ: usize = HEADER_SZ + SYNTAX_SECTION_SZ;
19
20    #[inline(always)]
21    pub fn new(buf: &'buf [u8]) -> PAT<'buf> {
22        PAT { buf }
23    }
24
25    #[inline(always)]
26    pub fn try_new(buf: &'buf [u8]) -> Result<PAT<'buf>> {
27        let s = Self::new(buf);
28        s.validate()?;
29        Ok(s)
30    }
31
32    #[inline(always)]
33    pub fn validate(&self) -> Result<()> {
34        if self.buf.len() < Self::HEADER_FULL_SZ {
35            Err(Error::new(ErrorKind::Buf(
36                self.buf.len(),
37                Self::HEADER_FULL_SZ,
38            )))
39        } else {
40            Ok(())
41        }
42    }
43
44    /// slice buf
45    #[inline(always)]
46    fn buf_programs(&self) -> &'buf [u8] {
47        let lft = Self::HEADER_FULL_SZ;
48        let mut rght = HEADER_SZ + (self.section_length() as usize);
49
50        if rght >= self.buf.len() {
51            rght = self.buf.len();
52        }
53
54        rght -= CRC32_SZ;
55
56        &self.buf[lft..rght]
57    }
58
59    #[inline(always)]
60    pub fn programs(&self) -> Cursor<'buf, Program> {
61        Cursor::new(self.buf_programs())
62    }
63
64    pub fn first_program_map_pid(&self) -> Option<u16> {
65        self.programs().next().and_then(|res| match res {
66            Ok(p) => match p.pid() {
67                PID::ProgramMap(v) => Some(v),
68                _ => None,
69            },
70            _ => None,
71        })
72    }
73
74    #[inline(always)]
75    pub fn transport_stream_id(&self) -> u16 {
76        self.table_id_extension()
77    }
78}
79
80impl<'buf> Bufer<'buf> for PAT<'buf> {
81    fn buf(&self) -> &'buf [u8] {
82        self.buf
83    }
84}
85
86impl<'buf> WithHeader<'buf> for PAT<'buf> {}
87impl<'buf> WithTableIDExtension<'buf> for PAT<'buf> {}
88impl<'buf> WithSyntaxSection<'buf> for PAT<'buf> {}
89impl<'buf> WithCRC32<'buf> for PAT<'buf> {}
90
91impl<'buf> fmt::Debug for PAT<'buf> {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        write!(
94            f,
95            ":PAT (:id {:?} :transport-stream-id {})",
96            self.subtable_id(),
97            self.transport_stream_id(),
98        )?;
99
100        write!(f, "\n  :programs")?;
101        for p in self.programs().filter_map(Result::ok) {
102            write!(f, "\n    ")?;
103            p.fmt(f)?;
104        }
105
106        Ok(())
107    }
108}
109
110impl<'buf> SubtableIDer for PAT<'buf> {
111    #[inline(always)]
112    fn subtable_id(&self) -> SubtableID {
113        SubtableID::PAT(
114            self.table_id(),
115            self.transport_stream_id(),
116            self.version_number(),
117        )
118    }
119}
120
121#[derive(Debug)]
122pub enum PID {
123    Network(u16),
124
125    ProgramMap(u16),
126}
127
128impl PID {
129    #[inline(always)]
130    pub fn is_program_map(&self) -> bool {
131        match self {
132            PID::ProgramMap(..) => true,
133            _ => false,
134        }
135    }
136}
137
138impl From<PID> for TsPID {
139    fn from(id: PID) -> TsPID {
140        match id {
141            PID::Network(v) => TsPID::Other(v),
142            PID::ProgramMap(v) => TsPID::Other(v),
143        }
144    }
145}
146
147pub struct Program<'buf> {
148    buf: &'buf [u8],
149}
150
151impl<'buf> Program<'buf> {
152    const SZ: usize = 4;
153
154    #[inline(always)]
155    pub fn new(buf: &'buf [u8]) -> Program<'buf> {
156        Program { buf }
157    }
158
159    #[inline(always)]
160    pub fn number(&self) -> u16 {
161        (u16::from(self.buf[0]) << 8) | u16::from(self.buf[1])
162    }
163
164    #[inline(always)]
165    pub fn pid_raw(&self) -> u16 {
166        (u16::from(self.buf[2] & 0b0001_1111) << 8) | u16::from(self.buf[3])
167    }
168
169    #[inline(always)]
170    pub fn pid(&self) -> PID {
171        match self.number() {
172            0 => PID::Network(self.pid_raw()),
173            _ => PID::ProgramMap(self.pid_raw()),
174        }
175    }
176}
177
178impl<'buf> Szer for Program<'buf> {
179    #[inline(always)]
180    fn sz(&self) -> usize {
181        Program::SZ
182    }
183}
184
185impl<'buf> TryNewer<'buf> for Program<'buf> {
186    #[inline(always)]
187    fn try_new(buf: &'buf [u8]) -> Result<Program<'buf>> {
188        let p = Program::new(buf);
189        Ok(p)
190    }
191}
192
193impl<'buf> fmt::Debug for Program<'buf> {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        write!(
196            f,
197            ":program (:number {:?} :pid {:?}/0x{:02X})",
198            self.number(),
199            self.pid(),
200            self.pid_raw(),
201        )
202    }
203}