Skip to main content

ts_analyzer/
packet.rs

1//! Holds all the information regarding a given packet from the transport
2//! stream.
3pub mod adaptation_field;
4pub mod header;
5pub mod payload;
6
7use adaptation_field::AdaptationField;
8use adaptation_field::StuffingAdaptationField;
9#[cfg(feature = "tracing")]
10use tracing::trace;
11
12use crate::ErrorKind;
13use crate::packet::adaptation_field::DataAdaptationField;
14use crate::packet::header::TsHeader;
15use crate::packet::payload::TsPayload;
16
17pub(crate) const PACKET_SIZE: usize = 188;
18
19/// The length of a transport stream packet is 4 bytes in size.
20pub const HEADER_SIZE: u8 = 4;
21
22/// All of this information is shamelessly stolen from wikipedia, my lord and
23/// savior. This [article](https://en.wikipedia.org/wiki/MPEG_transport_stream) in particular. Please donate
24/// to wikipedia if you have the means.
25pub struct TsPacket {
26    /// Header object which tracks header attributes of the packet
27    header: TsHeader,
28    /// Adaptation field data. This field will be `None` when the adaptation
29    /// field control field has a `0` in the MSB place.
30    adaptation_field: Option<AdaptationField>,
31    /// Payload field data. This field will be `None` when the adaptation field
32    /// control field has a `0` in the LSB place.
33    payload: Option<TsPayload>,
34}
35
36impl TsPacket {
37    /// Create a TSPacket from a byte array.
38    pub fn from_bytes(buf: &mut [u8]) -> Result<TsPacket, ErrorKind> {
39        let buffer_length = buf.len();
40        let header_bytes = Box::from(buf[0..HEADER_SIZE as usize].to_vec());
41
42        #[cfg(feature = "tracing")]
43        trace!("Parsing TSPacket from raw bytes: {:02X?}", buf);
44
45        let header = TsHeader::from_bytes(&header_bytes)?;
46
47        // This number comes from the fact that the TS header is always 4 bytes
48        // wide and the adaptation field always comes directly after the
49        // header if it is present.
50        let mut read_idx: usize = HEADER_SIZE as usize;
51
52        // If the adaptation field is present we need to determine it's size as
53        // we want to ignore it entirely.
54        let adaptation_field = if header.has_adaptation_field() {
55            #[cfg(feature = "tracing")]
56            trace!("Adaptation field exists for TSPacket");
57
58            // Get the length of the adaptation field. If it's `0` then this is
59            // a stuffing adaptation field.
60            let length = buf[read_idx];
61
62            if length != 0 {
63                let af = DataAdaptationField::from_bytes(
64                    &mut buf[read_idx..buffer_length],
65                );
66
67                // Add 1 because the adaptation field length is 1 byte long
68                read_idx += af.adaptation_field_length() as usize + 1;
69
70                Some(AdaptationField::Data(af))
71            } else {
72                let af = StuffingAdaptationField::new();
73
74                read_idx += af.adaptation_field_length() as usize;
75
76                Some(AdaptationField::Stuffing(af))
77            }
78        } else {
79            None
80        };
81
82        let payload = if header.has_payload() {
83            #[cfg(feature = "tracing")]
84            trace!("Payload exists for TSPacket");
85
86            let payload_bytes = &buf[read_idx..buf.len()];
87
88            let remainder = (PACKET_SIZE - read_idx) as u8;
89            if header.pusi() && payload_bytes[0] > remainder {
90                return Err(ErrorKind::InvalidPayloadPointer {
91                    pointer: payload_bytes[0],
92                    remainder,
93                });
94            }
95
96            Some(TsPayload::from_bytes(
97                header.pusi(),
98                header.continuity_counter(),
99                payload_bytes,
100            ))
101        } else {
102            None
103        };
104
105        // Payload data should now start at the read_idx.
106        let packet = TsPacket { header, adaptation_field, payload };
107
108        Ok(packet)
109    }
110
111    /// Returns the header object of this packet
112    pub fn header(&self) -> TsHeader {
113        self.header
114    }
115
116    /// Returns if the packet has adaptation field data.
117    pub fn has_adaptation_field(&self) -> bool {
118        self.header.has_adaptation_field()
119    }
120
121    /// Returns if the packet has payload field data.
122    pub fn has_payload(&self) -> bool {
123        self.header.has_payload()
124    }
125
126    /// Return the adaptation field data.
127    pub fn adaptation_field(&self) -> Option<AdaptationField> {
128        self.adaptation_field.clone()
129    }
130
131    /// Return the payload data
132    pub fn payload(&self) -> &Option<TsPayload> {
133        &self.payload
134    }
135
136    /// Move payload data
137    pub fn to_payload(self) -> Option<TsPayload> {
138        self.payload
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use test_case::test_case;
145
146    use super::*;
147    use crate::AdaptationFieldControl;
148
149    // The original error I got from this packet was: `range end index 224 out
150    // of range for slice of length 24`. Want to keep it as a historical
151    // test case.
152    fn packet_1() -> (Box<[u8]>, AdaptationFieldControl, Box<[u8]>) {
153        let packet = [
154            0x47, 0x41, 0x02, 0x10, // Header
155            0x00, // Payload start indicator
156            0x00, 0x01, 0xFC, 0x01, 0x10, 0x84, 0x80, 0x05, 0x21, 0x02, 0x95,
157            0x32, 0x6F, 0x00, 0x00, 0xDF, 0x01, 0x03, 0x06, 0x0E, 0x2B, 0x34,
158            0x02, 0x0B, 0x01, 0x01, 0x0E, 0x01, 0x03, 0x01, 0x01, 0x00, 0x00,
159            0x00, 0x81, 0xF1, 0x02, 0x08, 0x00, 0x04, 0xCA, 0x14, 0x28, 0x06,
160            0x0E, 0xEA, 0x03, 0x15, 0x45, 0x53, 0x52, 0x49, 0x5F, 0x4D, 0x65,
161            0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5F, 0x43, 0x6F, 0x6C, 0x6C,
162            0x65, 0x63, 0x74, 0x04, 0x06, 0x4E, 0x39, 0x37, 0x38, 0x32, 0x36,
163            0x05, 0x02, 0x70, 0x12, 0x06, 0x02, 0x15, 0xB3, 0x07, 0x02, 0xEF,
164            0x62, 0x0A, 0x05, 0x43, 0x32, 0x30, 0x38, 0x42, 0x0B, 0x00, 0x0C,
165            0x00, 0x0D, 0x04, 0x3A, 0x72, 0x80, 0x98, 0x0E, 0x04, 0xB5, 0x6C,
166            0xF5, 0xB9, 0x0F, 0x02, 0x31, 0x4F, 0x10, 0x02, 0x04, 0x5C, 0x11,
167            0x02, 0x02, 0x73, 0x12, 0x04, 0xB4, 0xCC, 0xCC, 0xCE, 0x13, 0x04,
168            0xF1, 0x81, 0x6C, 0x17, 0x14, 0x04, 0x00, 0x00, 0x00, 0x00, 0x15,
169            0x04, 0x00, 0x1E, 0x0A, 0x4F, 0x16, 0x02, 0x00, 0x00, 0x17, 0x04,
170            0x3A, 0x76, 0x87, 0xAF, 0x18, 0x04, 0xB5, 0x70, 0x74, 0xF2, 0x19,
171            0x02, 0x23, 0x99, 0x1A, 0x02, 0x01, 0x7B, 0x1B, 0x02, 0x00, 0x75,
172            0x1C, 0x02, 0xFF, 0xF1, 0x1D, 0x02, 0x02, // Payload
173        ];
174        (
175            Box::new(packet),
176            crate::AdaptationFieldControl::Payload,
177            Box::new([0x00, 0x01, 0xFC, 0x01]),
178        )
179    }
180
181    fn packet_2() -> (Box<[u8]>, AdaptationFieldControl, Box<[u8]>) {
182        let packet = [
183            0x47, 0x01, 0x02, 0x31, // Header
184            0x59, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
185            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
186            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
187            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
188            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
189            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
190            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
191            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
192            0xFF, 0xFF, // Adaptation field
193            0x03, 0x1E, 0x02, 0xFE, 0x9B, 0x1F, 0x02, 0xFF, 0x93, 0x20, 0x02,
194            0x00, 0x0F, 0x21, 0x02, 0xFE, 0x1B, 0x2F, 0x01, 0x00, 0x30, 0x2A,
195            0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, 0x04, 0x2F, 0x2F, 0x43,
196            0x41, 0x04, 0x00, 0x05, 0x00, 0x06, 0x02, 0x43, 0x41, 0x15, 0x10,
197            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198            0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x02, 0x00, 0x05, 0x38, 0x01,
199            0x00, 0x3B, 0x08, 0x46, 0x69, 0x72, 0x65, 0x62, 0x69, 0x72, 0x64,
200            0x41, 0x01, 0x01, 0x48, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
201            0x00, 0x00, 0x01, 0x02, 0xF9, 0x05, // Payload
202        ];
203
204        (
205            Box::new(packet),
206            crate::AdaptationFieldControl::AdaptationAndPayload,
207            Box::new([0x03, 0x1E, 0x02, 0xFE]),
208        )
209    }
210
211    #[test_case(packet_2)]
212    #[test_case(packet_1)]
213    fn from_bytes(
214        packet: fn() -> (Box<[u8]>, AdaptationFieldControl, Box<[u8]>),
215    ) {
216        let (mut buf, adaptation_field_control, first_packet_bytes) = packet();
217        let packet = TsPacket::from_bytes(&mut buf).unwrap();
218
219        assert_eq!(
220            packet.header().adaptation_field_control(),
221            adaptation_field_control,
222            "Transport Error Indicator is incorrect"
223        );
224
225        match packet.payload().clone().unwrap().get_payload_data() {
226            payload::TsPayloadData::StartData(start, _end) => assert!(
227                start.iter().eq(first_packet_bytes.iter()),
228                "First payload bytes are incorrect: {:02X?}",
229                start
230            ),
231            _ => panic!(),
232        };
233    }
234}