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