ts_analyzer/packet/
header.rs

1//! This module keeps track of all the information stored in the header of a
2//! transport stream packet.
3
4use crate::errors::invalid_first_byte::InvalidFirstByte;
5use crate::AdaptationFieldControl::{AdaptationAndPayload, AdaptationField, Payload};
6use crate::TransportScramblingControl::{EvenKey, NoScrambling, OddKey};
7use crate::{AdaptationFieldControl, TransportScramblingControl};
8use std::error::Error;
9use std::fmt::{Display, Formatter};
10use bitvec::macros::internal::funty::Fundamental;
11use bitvec::field::BitField;
12use bitvec::order::Msb0;
13use bitvec::vec::BitVec;
14#[cfg(feature = "log")]
15use log::trace;
16
17/// All transport stream packets start with a SYNC byte.
18pub const SYNC_BYTE: u8 = 0x47;
19
20/// All of this information is shamelessly stolen from wikipedia, my lord and savior.
21/// This [article](https://en.wikipedia.org/wiki/MPEG_transport_stream) in particular. Please donate
22/// to wikipedia if you have the means.
23#[derive(Clone, Copy, Debug)]
24pub struct TSHeader {
25    /// TEI: Transport error indicator is true when a packet is set when a demodulator cannot
26    /// correct invalid_first_byte and indicates that the packet is corrupt.
27    tei: bool,
28    /// PUSI: Payload unit start indicator indicates if this packet contains the first byte of a
29    /// payload since they can be spread across multiple packets.
30    pusi: bool,
31    /// Transport priority, set when the current packet is higher priority than other packets of the
32    /// same PID
33    transport_priority: bool,
34    /// PID: Packet identifier of the transport stream packet. Describes what the payload data is.
35    pid: u16,
36    /// TSC: Transport scrambling control indicates whether the payload is encrypted and with what
37    /// key. Valid values are:
38    /// - `0` for no scrambling.
39    /// - `1` is reserved.
40    /// - `2` Scrambled with even key.
41    /// - `3` Scrambled with odd key.
42    tsc: TransportScramblingControl,
43    /// Adaptation field control describes if this packet contains adaptation field data,
44    /// payload data, or both. Valid values are:
45    /// - `0` is reserved.
46    /// - `1` for payload only.
47    /// - `2` for adaptation field only.
48    /// - `3` for adaptation field followed by payload.
49    adaptation_field_control: AdaptationFieldControl,
50    /// Continuity counter is used for determining the sequence of data in each PID.
51    continuity_counter: u8,
52}
53
54impl TSHeader {
55    /// Create a new header
56    pub fn new(
57        tei: bool,
58        pusi: bool,
59        transport_priority: bool,
60        pid: u16,
61        tsc: u8,
62        adaptation_field_control: u8,
63        continuity_counter: u8,
64    ) -> Self {
65        #[cfg(feature = "log")]
66        {
67            trace!("pid: [{}]", pid);
68            trace!("adaptation_field_control: [{}]", adaptation_field_control);
69            trace!("continuity_counter: [{}]", continuity_counter);
70        }
71
72        TSHeader {
73            tei,
74            pusi,
75            transport_priority,
76            pid,
77            tsc: match tsc {
78                0 => NoScrambling,
79                1 => TransportScramblingControl::Reserved,
80                2 => EvenKey,
81                3 => OddKey,
82                _ => panic!("Invalid TSC value [{}]", tsc),
83            },
84            adaptation_field_control: match adaptation_field_control {
85                0 => AdaptationFieldControl::Reserved,
86                1 => Payload,
87                2 => AdaptationField,
88                3 => AdaptationAndPayload,
89                _ => panic!(
90                    "Invalid adaptation field control value [{}]",
91                    adaptation_field_control
92                ),
93            },
94            continuity_counter,
95        }
96    }
97
98    /// Get the packet header from raw bytes.
99    pub fn from_bytes(buf: &Box<[u8]>) -> Result<TSHeader, Box<dyn Error>> {
100        let bytes: BitVec<u8, Msb0> = BitVec::from_slice(buf).to_bitvec();
101
102        // Check if the first byte is SYNC byte.
103        if bytes[0..8].load::<u8>() != SYNC_BYTE {
104            return Err(Box::new(InvalidFirstByte { byte: buf[0] }));
105        }
106
107        #[cfg(feature = "log")]
108        trace!("header bytes: {:b}", bytes);
109
110        // Get the header information from the header bytes
111        let header = TSHeader {
112            tei: bytes[8],
113            pusi: bytes[9],
114            transport_priority: bytes[10],
115            pid: bytes[11..24].to_bitvec().load_be(),
116            tsc: match bytes[24..26].to_bitvec().load_be() {
117                0 => NoScrambling,
118                1 => TransportScramblingControl::Reserved,
119                2 => EvenKey,
120                3 => OddKey,
121                default => panic!("Invalid TSC value [{}]", default),
122            },
123            adaptation_field_control: match bytes[26..28].to_bitvec().load_be::<u8>() {
124                0 => AdaptationFieldControl::Reserved,
125                1 => Payload,
126                2 => AdaptationField,
127                3 => AdaptationAndPayload,
128                default => panic!(
129                    "Invalid adaptation field control value [{}]",
130                    default
131                ),
132            },
133            continuity_counter: bytes[28..32].load_be(),
134        };
135
136        #[cfg(feature = "log")]
137        trace!("Header for TSPacket: {}", header);
138        
139        Ok(header)
140    }
141
142    /// Return if the transport error indicator is set.
143    pub fn tei(&self) -> bool {
144        self.tei
145    }
146
147    /// Return if the payload unit start indicator is set.
148    pub fn pusi(&self) -> bool {
149        self.pusi
150    }
151
152    /// Return if the transport priority is set.
153    pub fn transport_priority(&self) -> bool {
154        self.transport_priority
155    }
156
157    /// Returns the packet identifier.
158    pub fn pid(&self) -> u16 {
159        self.pid
160    }
161
162    /// Return's the transport scrambling control of this packet.
163    pub fn tsc(&self) -> TransportScramblingControl {
164        self.tsc
165    }
166
167    /// Adaptation field control value.
168    pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
169        self.adaptation_field_control
170    }
171
172    /// Return whether this packet has an adaptation field or not
173    pub fn has_adaptation_field(&self) -> bool {
174        match self.adaptation_field_control {
175            AdaptationField | AdaptationAndPayload => true,
176            _ => false
177        }
178    }
179
180    /// Return whether this packet has a payload or not
181    pub fn has_payload(&self) -> bool {
182        match self.adaptation_field_control {
183            Payload | AdaptationAndPayload => true,
184            _ => false
185        }
186    }
187
188    /// Returns the continuity counter.
189    pub fn continuity_counter(&self) -> u8 {
190        self.continuity_counter
191    }
192
193    
194}
195
196impl Display for TSHeader {
197    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
198        let msg = format!("\n\
199            TEI: {}\n\
200            PUSI: {}\n\
201            Transport Priority: {}\n\
202            PID: {}\n\
203            Transport Scrambling Control: {:?}\n\
204            Adaptation Field Control: {:?}\n\
205            Continuity Counter: {}",
206            self.tei,
207            self.pusi,
208            self.transport_priority,
209            self.pid,
210            self.tsc,
211            self.adaptation_field_control,
212            self.continuity_counter,
213        );
214        write!(f, "{}", msg)
215    }
216}
217
218#[cfg(test)]
219mod tests {
220    use super::*;
221    use test_case::test_case;
222
223    #[test]
224    fn from_bytes() {
225        let buf: Box<[u8]> = Box::new([0x47, 0x01, 0x00, 0x1A]);
226        let header = TSHeader::from_bytes(&buf).unwrap();
227        assert_eq!(header.tei(), false, "Transport Error Indicator is incorrect");
228        assert_eq!(header.pusi(), false, "Payload Unit Start Indicator is incorrect");
229        assert_eq!(header.transport_priority(), false, "Transport Priority is incorrect");
230        assert_eq!(header.pid(), 256, "Transport Priority is incorrect");
231        assert_eq!(header.adaptation_field_control(), Payload, "Transport Priority is incorrect");
232        assert_eq!(header.continuity_counter(), 10, "Transport Priority is incorrect");
233    }
234
235    #[test]
236    fn from_bytes2() {
237        let buf: Box<[u8]> = Box::new([0x47, 0xE1, 0x00, 0x3B]);
238        let header = TSHeader::from_bytes(&buf).unwrap();
239        assert_eq!(header.tei(), true, "Transport Error Indicator is incorrect");
240        assert_eq!(header.pusi(), true, "Payload Unit Start Indicator is incorrect");
241        assert_eq!(header.transport_priority(), true, "Transport Priority is incorrect");
242        assert_eq!(header.pid(), 256, "Transport Priority is incorrect");
243        assert_eq!(header.adaptation_field_control(), AdaptationAndPayload, "Transport Priority is incorrect");
244        assert_eq!(header.continuity_counter(), 11, "Transport Priority is incorrect");
245    }
246}