va_ts/section/
sdt.rs

1use std::fmt;
2
3use crate::descriptor::Descriptor;
4use crate::result::Result;
5use crate::subtable_id::{SubtableID, SubtableIDer};
6
7use super::traits::*;
8
9/// ETSI EN 300 468 V1.15.1
10///
11/// Service Description Table
12pub struct SDT<'buf> {
13    buf: &'buf [u8],
14}
15
16impl<'buf> SDT<'buf> {
17    const HEADER_SPECIFIC_SZ: usize = 3;
18    const HEADER_FULL_SZ: usize = HEADER_SZ + SYNTAX_SECTION_SZ + Self::HEADER_SPECIFIC_SZ;
19
20    #[inline(always)]
21    pub fn new(buf: &'buf [u8]) -> SDT<'buf> {
22        SDT { buf }
23    }
24
25    #[inline(always)]
26    pub fn try_new(buf: &'buf [u8]) -> Result<SDT<'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        Ok(())
35    }
36
37    /// seek
38    #[inline(always)]
39    fn buf_streams(&self) -> &'buf [u8] {
40        let lft = Self::HEADER_FULL_SZ;
41        let mut rght = HEADER_SZ + (self.section_length() as usize);
42
43        if rght >= self.buf.len() {
44            rght = self.buf.len();
45        }
46
47        rght -= CRC32_SZ;
48
49        &self.buf[lft..rght]
50    }
51
52    #[inline(always)]
53    pub fn streams(&self) -> Cursor<'buf, Stream> {
54        Cursor::new(self.buf_streams())
55    }
56
57    #[inline(always)]
58    pub fn transport_stream_id(&self) -> u16 {
59        self.table_id_extension()
60    }
61}
62
63trait WithSDTHeaderSpecific<'buf>: Bufer<'buf> {
64    /// buffer seeked
65    #[inline(always)]
66    fn b(&self) -> &'buf [u8] {
67        &self.buf()[HEADER_SZ + SYNTAX_SECTION_SZ..]
68    }
69
70    #[inline(always)]
71    fn original_network_id(&self) -> u16 {
72        u16::from(self.b()[0]) | u16::from(self.b()[1])
73    }
74}
75
76impl<'buf> Bufer<'buf> for SDT<'buf> {
77    fn buf(&self) -> &'buf [u8] {
78        self.buf
79    }
80}
81
82impl<'buf> WithHeader<'buf> for SDT<'buf> {}
83impl<'buf> WithTableIDExtension<'buf> for SDT<'buf> {}
84impl<'buf> WithSyntaxSection<'buf> for SDT<'buf> {}
85impl<'buf> WithSDTHeaderSpecific<'buf> for SDT<'buf> {}
86impl<'buf> WithCRC32<'buf> for SDT<'buf> {}
87
88impl<'buf> fmt::Debug for SDT<'buf> {
89    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90        write!(
91            f,
92            ":SDT (:id {:?} :transport-stream-id {} :section-length {} :section {}/{})",
93            self.subtable_id(),
94            self.transport_stream_id(),
95            self.section_length(),
96            self.section_number(),
97            self.last_section_number(),
98        )?;
99
100        write!(f, "\n  :streams")?;
101        for p in self.streams().filter_map(Result::ok) {
102            write!(f, "\n    ")?;
103            p.fmt(f)?;
104        }
105
106        Ok(())
107    }
108}
109
110impl<'buf> SubtableIDer for SDT<'buf> {
111    #[inline(always)]
112    fn subtable_id(&self) -> SubtableID {
113        SubtableID::SDT(
114            self.table_id(),
115            self.transport_stream_id(),
116            self.original_network_id(),
117            self.version_number(),
118        )
119    }
120}
121
122pub struct Stream<'buf> {
123    buf: &'buf [u8],
124}
125
126impl<'buf> Stream<'buf> {
127    const HEADER_SZ: usize = 5;
128
129    #[inline(always)]
130    pub fn new(buf: &'buf [u8]) -> Stream<'buf> {
131        Stream { buf }
132    }
133
134    #[inline(always)]
135    pub fn service_id(&self) -> u16 {
136        u16::from(self.buf[0]) | u16::from(self.buf[1])
137    }
138
139    #[inline(always)]
140    pub fn eit_schedule_flag(&self) -> bool {
141        ((self.buf[2] & 0b0000_0010) >> 1) != 0
142    }
143
144    #[inline(always)]
145    pub fn eit_present_following_flag(&self) -> bool {
146        (self.buf[2] & 0b0000_0001) != 0
147    }
148
149    // TODO: add enum
150    #[inline(always)]
151    pub fn running_status(&self) -> u8 {
152        (self.buf[3] & 0b1110_0000) >> 5
153    }
154
155    #[inline(always)]
156    pub fn free_ca_mode(&self) -> bool {
157        (self.buf[3] & 0b0001_0000) != 0
158    }
159
160    #[inline(always)]
161    pub fn descriptors_loop_length(&self) -> u16 {
162        (u16::from(self.buf[3] & 0b0000_1111) << 8) | u16::from(self.buf[4])
163    }
164
165    /// seek
166    #[inline(always)]
167    fn buf_descriptors(&self) -> &'buf [u8] {
168        let lft = Self::HEADER_SZ;
169        let mut rght = lft + (self.descriptors_loop_length() as usize);
170
171        if rght >= self.buf.len() {
172            rght = self.buf.len();
173        }
174
175        &self.buf[lft..rght]
176    }
177
178    #[inline(always)]
179    pub fn descriptors(&self) -> Option<Cursor<'buf, Descriptor>> {
180        if self.descriptors_loop_length() != 0 {
181            Some(Cursor::new(self.buf_descriptors()))
182        } else {
183            None
184        }
185    }
186}
187
188impl<'buf> Szer for Stream<'buf> {
189    #[inline(always)]
190    fn sz(&self) -> usize {
191        Self::HEADER_SZ + (self.descriptors_loop_length() as usize)
192    }
193}
194
195impl<'buf> TryNewer<'buf> for Stream<'buf> {
196    #[inline(always)]
197    fn try_new(buf: &'buf [u8]) -> Result<Stream<'buf>> {
198        let s = Stream::new(buf);
199        Ok(s)
200    }
201}
202
203impl<'buf> fmt::Debug for Stream<'buf> {
204    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205        write!(
206            f,
207            ":stream (:service-id {:?} :running-status {:?})",
208            self.service_id(),
209            self.running_status(),
210        )?;
211
212        write!(f, "\n      :descriptors")?;
213        match self.descriptors() {
214            Some(descs) => {
215                for d in descs.filter_map(Result::ok) {
216                    write!(f, "\n        ")?;
217                    d.fmt(f)?;
218                }
219            }
220            None => write!(f, " ~")?,
221        }
222
223        Ok(())
224    }
225}