1use std::fmt::Display;
5use std::fmt::Formatter;
6
7use bitvec::field::BitField;
8use bitvec::order::Msb0;
9use bitvec::slice::BitSlice;
10use bitvec::view::BitView;
11#[cfg(feature = "tracing")]
12use tracing::trace;
13
14use crate::AdaptationFieldControl;
15use crate::AdaptationFieldControl::AdaptationAndPayload;
16use crate::AdaptationFieldControl::AdaptationField;
17use crate::AdaptationFieldControl::Payload;
18use crate::ErrorKind;
19use crate::TransportScramblingControl;
20use crate::TransportScramblingControl::EvenKey;
21use crate::TransportScramblingControl::NoScrambling;
22use crate::TransportScramblingControl::OddKey;
23
24pub const SYNC_BYTE: u8 = 0x47;
26
27#[derive(Clone, Copy, Debug)]
31pub struct TsHeader {
32 tei: bool,
36 pusi: bool,
40 transport_priority: bool,
43 pid: u16,
46 tsc: TransportScramblingControl,
53 adaptation_field_control: AdaptationFieldControl,
60 continuity_counter: u8,
63}
64
65impl TsHeader {
66 pub fn new(
68 tei: bool,
69 pusi: bool,
70 transport_priority: bool,
71 pid: u16,
72 tsc: u8,
73 adaptation_field_control: u8,
74 continuity_counter: u8,
75 ) -> Self {
76 #[cfg(feature = "tracing")]
77 {
78 trace!("pid: [{}]", pid);
79 trace!("adaptation_field_control: [{}]", adaptation_field_control);
80 trace!("continuity_counter: [{}]", continuity_counter);
81 }
82
83 TsHeader {
84 tei,
85 pusi,
86 transport_priority,
87 pid,
88 tsc: match tsc {
89 0 => NoScrambling,
90 1 => TransportScramblingControl::Reserved,
91 2 => EvenKey,
92 3 => OddKey,
93 _ => panic!("Invalid TSC value [{}]", tsc),
94 },
95 adaptation_field_control: match adaptation_field_control {
96 0 => AdaptationFieldControl::Reserved,
97 1 => Payload,
98 2 => AdaptationField,
99 3 => AdaptationAndPayload,
100 _ => panic!(
101 "Invalid adaptation field control value [{}]",
102 adaptation_field_control
103 ),
104 },
105 continuity_counter,
106 }
107 }
108
109 pub fn from_bytes(buf: &[u8]) -> Result<TsHeader, ErrorKind> {
111 let bytes: &BitSlice<u8, Msb0> = buf.view_bits();
112
113 if bytes[0..8].load::<u8>() != SYNC_BYTE {
115 return Err(ErrorKind::InvalidFirstByte { byte: buf[0] });
116 }
117
118 #[cfg(feature = "tracing")]
119 trace!("header bytes: {:b}", bytes);
120
121 let header = TsHeader {
123 tei: bytes[8],
124 pusi: bytes[9],
125 transport_priority: bytes[10],
126 pid: bytes[11..24].to_bitvec().load_be(),
127 tsc: match bytes[24..26].to_bitvec().load_be() {
128 0 => NoScrambling,
129 1 => TransportScramblingControl::Reserved,
130 2 => EvenKey,
131 3 => OddKey,
132 default => panic!("Invalid TSC value [{}]", default),
133 },
134 adaptation_field_control: match bytes[26..28]
135 .to_bitvec()
136 .load_be::<u8>()
137 {
138 0 => AdaptationFieldControl::Reserved,
139 1 => Payload,
140 2 => AdaptationField,
141 3 => AdaptationAndPayload,
142 default => panic!(
143 "Invalid adaptation field control value [{}]",
144 default
145 ),
146 },
147 continuity_counter: bytes[28..32].load_be(),
148 };
149
150 #[cfg(feature = "tracing")]
151 trace!("Header for TSPacket: {}", header);
152
153 Ok(header)
154 }
155
156 pub fn tei(&self) -> bool {
158 self.tei
159 }
160
161 pub fn pusi(&self) -> bool {
163 self.pusi
164 }
165
166 pub fn transport_priority(&self) -> bool {
168 self.transport_priority
169 }
170
171 pub fn pid(&self) -> u16 {
173 self.pid
174 }
175
176 pub fn tsc(&self) -> TransportScramblingControl {
178 self.tsc
179 }
180
181 pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
183 self.adaptation_field_control
184 }
185
186 pub fn has_adaptation_field(&self) -> bool {
188 matches!(
189 self.adaptation_field_control,
190 AdaptationField | AdaptationAndPayload
191 )
192 }
193
194 pub fn has_payload(&self) -> bool {
196 matches!(self.adaptation_field_control, Payload | AdaptationAndPayload)
197 }
198
199 pub fn continuity_counter(&self) -> u8 {
201 self.continuity_counter
202 }
203}
204
205impl Display for TsHeader {
206 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
207 let msg = format!(
208 "\n\
209 TEI: {}\n\
210 PUSI: {}\n\
211 Transport Priority: {}\n\
212 PID: {}\n\
213 Transport Scrambling Control: {:?}\n\
214 Adaptation Field Control: {:?}\n\
215 Continuity Counter: {}",
216 self.tei,
217 self.pusi,
218 self.transport_priority,
219 self.pid,
220 self.tsc,
221 self.adaptation_field_control,
222 self.continuity_counter,
223 );
224 write!(f, "{}", msg)
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn from_bytes() {
234 let buf: Box<[u8]> = Box::new([0x47, 0x01, 0x00, 0x1A]);
235 let header = TsHeader::from_bytes(&buf).unwrap();
236 assert!(!header.tei(), "Transport Error Indicator is incorrect");
237 assert!(!header.pusi(), "Payload Unit Start Indicator is incorrect");
238 assert!(
239 !header.transport_priority(),
240 "Transport Priority is incorrect"
241 );
242 assert_eq!(header.pid(), 256, "Transport Priority is incorrect");
243 assert_eq!(
244 header.adaptation_field_control(),
245 Payload,
246 "Transport Priority is incorrect"
247 );
248 assert_eq!(
249 header.continuity_counter(),
250 10,
251 "Transport Priority is incorrect"
252 );
253 }
254
255 #[test]
256 fn from_bytes2() {
257 let buf: Box<[u8]> = Box::new([0x47, 0xE1, 0x00, 0x3B]);
258 let header = TsHeader::from_bytes(&buf).unwrap();
259 assert!(header.tei(), "Transport Error Indicator is incorrect");
260 assert!(header.pusi(), "Payload Unit Start Indicator is incorrect");
261 assert!(header.transport_priority(), "Transport Priority is incorrect");
262 assert_eq!(header.pid(), 256, "Transport Priority is incorrect");
263 assert_eq!(
264 header.adaptation_field_control(),
265 AdaptationAndPayload,
266 "Transport Priority is incorrect"
267 );
268 assert_eq!(
269 header.continuity_counter(),
270 11,
271 "Transport Priority is incorrect"
272 );
273 }
274}