Skip to main content

ts_analyzer/packet/
adaptation_field.rs

1//! This module keep track of all the information stored in the adaptation field
2//! of the transport stream packet header.
3
4use std::fmt::Display;
5use std::fmt::Formatter;
6
7use bitvec::field::BitField;
8use bitvec::order::Msb0;
9use bitvec::vec::BitVec;
10#[cfg(feature = "tracing")]
11use tracing::trace;
12
13/// The PCR field and OPCR field are 6 bytes in size.
14pub const PCR_SIZE: u8 = 6;
15
16/// The splice countdown field is 1 byte in size.
17pub const SPLICE_COUNTDOWN_SIZE: u8 = 1;
18
19/// The length of the transport private data length field is 1 byte in size.
20pub const TRANSPORT_PRIVATE_DATA_LENGTH_LENGTH: u8 = 1;
21
22/// This is created because an adaptation field can either be full of metadata
23/// as expected ***OR*** it can be a single stuffing byte. I don't want
24/// operations that work on a real adaptation field to work on a stuffing
25/// adaptation field but I don't want to make the adaptation field `None` either
26/// because the the `adaptation_control_field` still says the adaptation field
27/// is present.
28
29#[derive(Clone, Debug)]
30pub enum AdaptationField {
31    /// Data adaptation fields are what you think of when looking at an
32    /// adaptation field and contain actual data
33    Data(DataAdaptationField),
34    /// Stuffing adaptation fields contain 1 byte of stuffing.
35    Stuffing(StuffingAdaptationField),
36}
37
38/// All of this information is shamelessly stolen from wikipedia, my lord and
39/// savior. This [article](https://en.wikipedia.org/wiki/MPEG_transport_stream) in particular. Please donate
40/// to wikipedia if you have the means.
41#[derive(Clone, Debug)]
42pub struct DataAdaptationField {
43    /// Number of bytes that make up the adaptation field.
44    ///
45    /// This includes all the dynamic data such as the PCR fields as well as
46    /// the transport private data.
47    adaptation_field_length: u8,
48    /// Set if current TS packet is in a discontinuity state with respect to
49    /// either the continuity counter or the program clock reference
50    discontinuity_indicator: bool,
51    /// Set when the stream may be decoded without errors from this point
52    random_access_indicator: bool,
53    /// Set when this stream should be considered "high priority"
54    elementary_stream_priority_indicator: bool,
55    /// Set when PCR (Program Clock Reference) field is present
56    pcr_flag: bool,
57    /// Set when OPCR (Original Program Clock Reference) field is present
58    opcr_flag: bool,
59    /// Set when splice countdown field is present
60    splicing_point_flag: bool,
61    /// Set when transport private data is present
62    transport_private_data_flag: bool,
63    /// Set when adaptation extension data is present
64    adaptation_field_extension_flag: bool,
65    /// Program clock reference. The PCR indicates the intended time of arrival
66    /// of the byte containing the last bit of the
67    /// program_clock_reference_base at the input of the system
68    /// target decoder
69    ///
70    /// Is `None` if the PCR Flag is `false`.
71    pcr: Option<u64>,
72    /// Original Program clock reference. Helps when one TS is copied into
73    /// another
74    ///
75    /// Is `None` if the OPCR Flag is `false`.
76    opcr: Option<u64>,
77    /// Indicates how many TS packets from this one a splicing point occurs.
78    /// May be negative.
79    ///
80    /// Is `None` if the Splicing Point Flag is `false`.
81    splice_countdown: Option<i8>,
82    /// Length of the Transport Private Data field.
83    ///
84    /// Is `None` if the Transport Private Data Flag is `false`.
85    transport_private_data_length: Option<u8>,
86    /// Transport private data. I tried to look into what this is and couldn't
87    /// fina any documentation.
88    ///
89    /// Is `None` if the Transport Private Data Flag is `false`.
90    transport_private_data: Option<Box<[u8]>>,
91}
92
93impl DataAdaptationField {
94    /// Create a new adaptation field.
95    pub fn new(
96        adaptation_field_length: u8,
97        discontinuity_indicator: bool,
98        random_access_indicator: bool,
99        elementary_stream_priority_indicator: bool,
100        pcr_flag: bool,
101        opcr_flag: bool,
102        splicing_point_flag: bool,
103        transport_private_data_flag: bool,
104        adaptation_field_extension_flag: bool,
105        pcr: Option<u64>,
106        opcr: Option<u64>,
107        splice_countdown: Option<i8>,
108        transport_private_data_length: Option<u8>,
109        transport_private_data: Option<Box<[u8]>>,
110    ) -> Self {
111        Self {
112            adaptation_field_length,
113            discontinuity_indicator,
114            random_access_indicator,
115            elementary_stream_priority_indicator,
116            pcr_flag,
117            opcr_flag,
118            splicing_point_flag,
119            transport_private_data_flag,
120            adaptation_field_extension_flag,
121            pcr,
122            opcr,
123            splice_countdown,
124            transport_private_data_length,
125            transport_private_data,
126        }
127    }
128
129    /// Parse the adaptation field from the passed in buffer
130    pub fn from_bytes(buf: &mut [u8]) -> Self {
131        #[cfg(feature = "tracing")]
132        trace!("adaptation field bytes: {:02X?}", buf);
133
134        // This is just used to track where we are reading each portion of the
135        // field.
136        let mut read_idx = 0;
137
138        // Get the length of the adaptation field.
139        //
140        // TODO: Determine if this takes into account the `Transport private
141        // data length` field or not. If it doesn't then that field will
142        // need to be parsed as well. For the current moment
143        // I'm assuming it takes it into account
144        let adaptation_field_length: u8 =
145            BitVec::<u8, Msb0>::from_slice(&buf[read_idx..read_idx + 1])
146                .load_be();
147
148        // Increment the read index since we just read a byte
149        read_idx += 1;
150
151        // Check if any of the dynamic fields are set. If these pop during
152        // testing I'll have to implement them, but otherwise I'll leave
153        // them until necessary.
154        let adaptation_field_required: BitVec<u8, Msb0> =
155            BitVec::from_slice(&buf[read_idx..read_idx + 1]);
156
157        // Increment the read index since we just read a byte
158        read_idx += 1;
159
160        let pcr_flag = adaptation_field_required[3];
161        let opcr_flag = adaptation_field_required[4];
162        let splicing_point_flag = adaptation_field_required[5];
163        let transport_private_data_flag = adaptation_field_required[6];
164        let adaptation_field_extension_flag = adaptation_field_required[7];
165
166        let pcr = Self::read_pcr_data(&pcr_flag, buf, &mut read_idx);
167        let opcr = Self::read_pcr_data(&opcr_flag, buf, &mut read_idx);
168
169        let splice_countdown = Self::read_data_conditionally(
170            &splicing_point_flag,
171            buf,
172            &mut read_idx,
173            SPLICE_COUNTDOWN_SIZE as usize,
174        )
175        .map(|bits| bits.load());
176
177        // Putting this in the outer scope, so we can use the value in the
178        // TSAdapterField constructor below.
179        let transport_private_data: Option<Box<[u8]>>;
180
181        let transport_private_data_length = match Self::read_data_conditionally(
182            &transport_private_data_flag,
183            buf,
184            &mut read_idx,
185            TRANSPORT_PRIVATE_DATA_LENGTH_LENGTH as usize,
186        ) {
187            Some(bits) => {
188                let length: u8 = bits.load();
189
190                transport_private_data = Some(Box::from(
191                    Self::read_data(buf, &mut read_idx, length as usize)
192                        .as_raw_slice(),
193                ));
194
195                Some(length)
196            }
197            None => {
198                transport_private_data = None;
199
200                None
201            }
202        };
203
204        // We currently do nothing with the adaptation extension field.
205        // TODO: Add support for adaptation extension field.
206        #[cfg(feature = "tracing")]
207        trace!(
208            "Packet has adaptation extension field {}",
209            adaptation_field_extension_flag
210        );
211
212        let af = DataAdaptationField {
213            adaptation_field_length,
214            discontinuity_indicator: adaptation_field_required[0],
215            random_access_indicator: adaptation_field_required[1],
216            elementary_stream_priority_indicator: adaptation_field_required[2],
217            pcr_flag,
218            opcr_flag,
219            splicing_point_flag,
220            transport_private_data_flag,
221            adaptation_field_extension_flag,
222            pcr,
223            opcr,
224            splice_countdown,
225            transport_private_data_length,
226            transport_private_data,
227        };
228
229        #[cfg(feature = "tracing")]
230        trace!("{}", af);
231
232        af
233    }
234
235    fn read_data_conditionally(
236        flag: &bool,
237        buf: &mut [u8],
238        read_idx: &mut usize,
239        read_size: usize,
240    ) -> Option<BitVec<u8, Msb0>> {
241        if !flag {
242            return None;
243        }
244
245        Some(Self::read_data(buf, read_idx, read_size))
246    }
247
248    fn read_data(
249        buf: &mut [u8],
250        read_idx: &mut usize,
251        read_size: usize,
252    ) -> BitVec<u8, Msb0> {
253        // Read the  data from the given buffer location
254        let bits: BitVec<u8, Msb0> =
255            BitVec::from_slice(&buf[*read_idx..*read_idx + read_size]);
256
257        // Increment the read index since we just read a `PCR_SIZE` amount of
258        // bytes.
259        *read_idx += read_size;
260
261        bits
262    }
263
264    /// Read the PCR (or OPCR) data from a starting index
265    fn read_pcr_data(
266        flag: &bool,
267        buf: &mut [u8],
268        read_idx: &mut usize,
269    ) -> Option<u64> {
270        let pcr_bits = match Self::read_data_conditionally(
271            flag,
272            buf,
273            read_idx,
274            PCR_SIZE as usize,
275        ) {
276            Some(bits) => bits,
277            None => {
278                // Return early if there is no field to be read, as seen by
279                // reading the flag.
280                return None;
281            }
282        };
283
284        // The first 33 bits are the "base" value which gets multiplied by
285        // `300`. This is defined in the MPEG/TS standard.
286        let base: u64 = pcr_bits[0..34].load();
287        // The next 6 bits are reserved, so we will ignore them and the last 9
288        // bits are the "extension" which get added to the multiplied
289        // base.
290        let extension: u64 = pcr_bits[39..48].load();
291
292        Some(base * 300 + extension)
293    }
294
295    /// Returns the number of bytes that make up the adaptation field length
296    pub fn adaptation_field_length(&self) -> u8 {
297        self.adaptation_field_length
298    }
299
300    /// Return if the header indicates that this packet contains an adaptation
301    /// extension field.
302    pub fn has_adaptation_extension_field(&self) -> bool {
303        self.adaptation_field_extension_flag
304    }
305}
306
307/// How many stuffing bytes exist in an adaptation field with a length field of
308/// `0`
309pub const STUFFING_ADAPTATION_FIELD_LENGTH: u8 = 1;
310
311#[derive(Clone, Debug)]
312/// An adaptation field with a length of `0` is a StuffingAdaptationField. It
313/// contains 1 byte of stuffing per the standard.
314pub struct StuffingAdaptationField {
315    /// This value will always be 1. This object gets created when the
316    /// adaptation_field_length field is `0`. This really means that the
317    /// the `adaptation_field` is really just 1 stuffing byte.
318    adaptation_field_length: u8,
319}
320
321impl Default for StuffingAdaptationField {
322    fn default() -> Self {
323        Self::new()
324    }
325}
326
327impl StuffingAdaptationField {
328    /// Create a new stuffing adaptation field.
329    pub fn new() -> StuffingAdaptationField {
330        StuffingAdaptationField {
331            adaptation_field_length: STUFFING_ADAPTATION_FIELD_LENGTH,
332        }
333    }
334
335    /// Return the number of stuffing bytes in the stuffing adaptation field.
336    ///
337    /// # Hint
338    /// It's `1`.
339    pub fn adaptation_field_length(&self) -> u8 {
340        self.adaptation_field_length
341    }
342}
343
344impl Display for DataAdaptationField {
345    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
346        let msg = format!(
347            "\n\
348            Discontinuity: {}\n\
349            Random Access: {}\n\
350            Elementary Stream Priority: {}\n\
351            PCR Flag: {}\n\
352            OPCR Flag: {:?}\n\
353            Splicing Point Flag: {}\n\
354            Transport Private Data Flag: {}\n\
355            Adaptation Field Extension Flag: {}",
356            self.discontinuity_indicator,
357            self.random_access_indicator,
358            self.elementary_stream_priority_indicator,
359            self.pcr_flag,
360            self.opcr_flag,
361            self.splicing_point_flag,
362            self.transport_private_data_flag,
363            self.adaptation_field_extension_flag,
364        );
365        write!(f, "{}", msg)
366    }
367}
368