use std::fmt::Display;
use std::fmt::Formatter;
use bitvec::field::BitField;
use bitvec::order::Msb0;
use bitvec::slice::BitSlice;
use bitvec::view::BitView;
#[cfg(feature = "tracing")]
use tracing::trace;
use crate::AdaptationFieldControl;
use crate::AdaptationFieldControl::AdaptationAndPayload;
use crate::AdaptationFieldControl::AdaptationField;
use crate::AdaptationFieldControl::Payload;
use crate::ErrorKind;
use crate::TransportScramblingControl;
use crate::TransportScramblingControl::EvenKey;
use crate::TransportScramblingControl::NoScrambling;
use crate::TransportScramblingControl::OddKey;
pub const SYNC_BYTE: u8 = 0x47;
#[derive(Clone, Copy, Debug)]
pub struct TsHeader {
tei: bool,
pusi: bool,
transport_priority: bool,
pid: u16,
tsc: TransportScramblingControl,
adaptation_field_control: AdaptationFieldControl,
continuity_counter: u8,
}
impl TsHeader {
pub fn new(
tei: bool,
pusi: bool,
transport_priority: bool,
pid: u16,
tsc: u8,
adaptation_field_control: u8,
continuity_counter: u8,
) -> Self {
#[cfg(feature = "tracing")]
{
trace!("pid: [{}]", pid);
trace!("adaptation_field_control: [{}]", adaptation_field_control);
trace!("continuity_counter: [{}]", continuity_counter);
}
TsHeader {
tei,
pusi,
transport_priority,
pid,
tsc: match tsc {
0 => NoScrambling,
1 => TransportScramblingControl::Reserved,
2 => EvenKey,
3 => OddKey,
_ => panic!("Invalid TSC value [{}]", tsc),
},
adaptation_field_control: match adaptation_field_control {
0 => AdaptationFieldControl::Reserved,
1 => Payload,
2 => AdaptationField,
3 => AdaptationAndPayload,
_ => panic!(
"Invalid adaptation field control value [{}]",
adaptation_field_control
),
},
continuity_counter,
}
}
pub fn from_bytes(buf: &[u8]) -> Result<TsHeader, ErrorKind> {
let bytes: &BitSlice<u8, Msb0> = buf.view_bits();
if bytes[0..8].load::<u8>() != SYNC_BYTE {
return Err(ErrorKind::InvalidFirstByte { byte: buf[0] });
}
#[cfg(feature = "tracing")]
trace!("header bytes: {:b}", bytes);
let header = TsHeader {
tei: bytes[8],
pusi: bytes[9],
transport_priority: bytes[10],
pid: bytes[11..24].to_bitvec().load_be(),
tsc: match bytes[24..26].to_bitvec().load_be() {
0 => NoScrambling,
1 => TransportScramblingControl::Reserved,
2 => EvenKey,
3 => OddKey,
default => panic!("Invalid TSC value [{}]", default),
},
adaptation_field_control: match bytes[26..28]
.to_bitvec()
.load_be::<u8>()
{
0 => AdaptationFieldControl::Reserved,
1 => Payload,
2 => AdaptationField,
3 => AdaptationAndPayload,
default => panic!(
"Invalid adaptation field control value [{}]",
default
),
},
continuity_counter: bytes[28..32].load_be(),
};
#[cfg(feature = "tracing")]
trace!("Header for TSPacket: {}", header);
Ok(header)
}
pub fn tei(&self) -> bool {
self.tei
}
pub fn pusi(&self) -> bool {
self.pusi
}
pub fn transport_priority(&self) -> bool {
self.transport_priority
}
pub fn pid(&self) -> u16 {
self.pid
}
pub fn tsc(&self) -> TransportScramblingControl {
self.tsc
}
pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
self.adaptation_field_control
}
pub fn has_adaptation_field(&self) -> bool {
matches!(
self.adaptation_field_control,
AdaptationField | AdaptationAndPayload
)
}
pub fn has_payload(&self) -> bool {
matches!(self.adaptation_field_control, Payload | AdaptationAndPayload)
}
pub fn continuity_counter(&self) -> u8 {
self.continuity_counter
}
}
impl Display for TsHeader {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let msg = format!(
"\n\
TEI: {}\n\
PUSI: {}\n\
Transport Priority: {}\n\
PID: {}\n\
Transport Scrambling Control: {:?}\n\
Adaptation Field Control: {:?}\n\
Continuity Counter: {}",
self.tei,
self.pusi,
self.transport_priority,
self.pid,
self.tsc,
self.adaptation_field_control,
self.continuity_counter,
);
write!(f, "{}", msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_bytes() {
let buf: Box<[u8]> = Box::new([0x47, 0x01, 0x00, 0x1A]);
let header = TsHeader::from_bytes(&buf).unwrap();
assert!(!header.tei(), "Transport Error Indicator is incorrect");
assert!(!header.pusi(), "Payload Unit Start Indicator is incorrect");
assert!(
!header.transport_priority(),
"Transport Priority is incorrect"
);
assert_eq!(header.pid(), 256, "Transport Priority is incorrect");
assert_eq!(
header.adaptation_field_control(),
Payload,
"Transport Priority is incorrect"
);
assert_eq!(
header.continuity_counter(),
10,
"Transport Priority is incorrect"
);
}
#[test]
fn from_bytes2() {
let buf: Box<[u8]> = Box::new([0x47, 0xE1, 0x00, 0x3B]);
let header = TsHeader::from_bytes(&buf).unwrap();
assert!(header.tei(), "Transport Error Indicator is incorrect");
assert!(header.pusi(), "Payload Unit Start Indicator is incorrect");
assert!(header.transport_priority(), "Transport Priority is incorrect");
assert_eq!(header.pid(), 256, "Transport Priority is incorrect");
assert_eq!(
header.adaptation_field_control(),
AdaptationAndPayload,
"Transport Priority is incorrect"
);
assert_eq!(
header.continuity_counter(),
11,
"Transport Priority is incorrect"
);
}
}