use std::fmt::Display;
use std::fmt::Formatter;
use bitvec::field::BitField;
use bitvec::order::Msb0;
use bitvec::vec::BitVec;
#[cfg(feature = "tracing")]
use tracing::trace;
pub const PCR_SIZE: u8 = 6;
pub const SPLICE_COUNTDOWN_SIZE: u8 = 1;
pub const TRANSPORT_PRIVATE_DATA_LENGTH_LENGTH: u8 = 1;
#[derive(Clone, Debug)]
pub enum AdaptationField {
Data(DataAdaptationField),
Stuffing(StuffingAdaptationField),
}
#[derive(Clone, Debug)]
pub struct DataAdaptationField {
adaptation_field_length: u8,
discontinuity_indicator: bool,
random_access_indicator: bool,
elementary_stream_priority_indicator: bool,
pcr_flag: bool,
opcr_flag: bool,
splicing_point_flag: bool,
transport_private_data_flag: bool,
adaptation_field_extension_flag: bool,
pcr: Option<u64>,
opcr: Option<u64>,
splice_countdown: Option<i8>,
transport_private_data_length: Option<u8>,
transport_private_data: Option<Box<[u8]>>,
}
impl DataAdaptationField {
pub fn new(
adaptation_field_length: u8,
discontinuity_indicator: bool,
random_access_indicator: bool,
elementary_stream_priority_indicator: bool,
pcr_flag: bool,
opcr_flag: bool,
splicing_point_flag: bool,
transport_private_data_flag: bool,
adaptation_field_extension_flag: bool,
pcr: Option<u64>,
opcr: Option<u64>,
splice_countdown: Option<i8>,
transport_private_data_length: Option<u8>,
transport_private_data: Option<Box<[u8]>>,
) -> Self {
Self {
adaptation_field_length,
discontinuity_indicator,
random_access_indicator,
elementary_stream_priority_indicator,
pcr_flag,
opcr_flag,
splicing_point_flag,
transport_private_data_flag,
adaptation_field_extension_flag,
pcr,
opcr,
splice_countdown,
transport_private_data_length,
transport_private_data,
}
}
pub fn from_bytes(buf: &mut [u8]) -> Self {
#[cfg(feature = "tracing")]
trace!("adaptation field bytes: {:02X?}", buf);
let mut read_idx = 0;
let adaptation_field_length: u8 =
BitVec::<u8, Msb0>::from_slice(&buf[read_idx..read_idx + 1])
.load_be();
read_idx += 1;
let adaptation_field_required: BitVec<u8, Msb0> =
BitVec::from_slice(&buf[read_idx..read_idx + 1]);
read_idx += 1;
let pcr_flag = adaptation_field_required[3];
let opcr_flag = adaptation_field_required[4];
let splicing_point_flag = adaptation_field_required[5];
let transport_private_data_flag = adaptation_field_required[6];
let adaptation_field_extension_flag = adaptation_field_required[7];
let pcr = Self::read_pcr_data(&pcr_flag, buf, &mut read_idx);
let opcr = Self::read_pcr_data(&opcr_flag, buf, &mut read_idx);
let splice_countdown = Self::read_data_conditionally(
&splicing_point_flag,
buf,
&mut read_idx,
SPLICE_COUNTDOWN_SIZE as usize,
)
.map(|bits| bits.load());
let transport_private_data: Option<Box<[u8]>>;
let transport_private_data_length = match Self::read_data_conditionally(
&transport_private_data_flag,
buf,
&mut read_idx,
TRANSPORT_PRIVATE_DATA_LENGTH_LENGTH as usize,
) {
Some(bits) => {
let length: u8 = bits.load();
transport_private_data = Some(Box::from(
Self::read_data(buf, &mut read_idx, length as usize)
.as_raw_slice(),
));
Some(length)
}
None => {
transport_private_data = None;
None
}
};
#[cfg(feature = "tracing")]
trace!(
"Packet has adaptation extension field {}",
adaptation_field_extension_flag
);
let af = DataAdaptationField {
adaptation_field_length,
discontinuity_indicator: adaptation_field_required[0],
random_access_indicator: adaptation_field_required[1],
elementary_stream_priority_indicator: adaptation_field_required[2],
pcr_flag,
opcr_flag,
splicing_point_flag,
transport_private_data_flag,
adaptation_field_extension_flag,
pcr,
opcr,
splice_countdown,
transport_private_data_length,
transport_private_data,
};
#[cfg(feature = "tracing")]
trace!("{}", af);
af
}
fn read_data_conditionally(
flag: &bool,
buf: &mut [u8],
read_idx: &mut usize,
read_size: usize,
) -> Option<BitVec<u8, Msb0>> {
if !flag {
return None;
}
Some(Self::read_data(buf, read_idx, read_size))
}
fn read_data(
buf: &mut [u8],
read_idx: &mut usize,
read_size: usize,
) -> BitVec<u8, Msb0> {
let bits: BitVec<u8, Msb0> =
BitVec::from_slice(&buf[*read_idx..*read_idx + read_size]);
*read_idx += read_size;
bits
}
fn read_pcr_data(
flag: &bool,
buf: &mut [u8],
read_idx: &mut usize,
) -> Option<u64> {
let pcr_bits = match Self::read_data_conditionally(
flag,
buf,
read_idx,
PCR_SIZE as usize,
) {
Some(bits) => bits,
None => {
return None;
}
};
let base: u64 = pcr_bits[0..34].load();
let extension: u64 = pcr_bits[39..48].load();
Some(base * 300 + extension)
}
pub fn adaptation_field_length(&self) -> u8 {
self.adaptation_field_length
}
pub fn has_adaptation_extension_field(&self) -> bool {
self.adaptation_field_extension_flag
}
}
pub const STUFFING_ADAPTATION_FIELD_LENGTH: u8 = 1;
#[derive(Clone, Debug)]
pub struct StuffingAdaptationField {
adaptation_field_length: u8,
}
impl Default for StuffingAdaptationField {
fn default() -> Self {
Self::new()
}
}
impl StuffingAdaptationField {
pub fn new() -> StuffingAdaptationField {
StuffingAdaptationField {
adaptation_field_length: STUFFING_ADAPTATION_FIELD_LENGTH,
}
}
pub fn adaptation_field_length(&self) -> u8 {
self.adaptation_field_length
}
}
impl Display for DataAdaptationField {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let msg = format!(
"\n\
Discontinuity: {}\n\
Random Access: {}\n\
Elementary Stream Priority: {}\n\
PCR Flag: {}\n\
OPCR Flag: {:?}\n\
Splicing Point Flag: {}\n\
Transport Private Data Flag: {}\n\
Adaptation Field Extension Flag: {}",
self.discontinuity_indicator,
self.random_access_indicator,
self.elementary_stream_priority_indicator,
self.pcr_flag,
self.opcr_flag,
self.splicing_point_flag,
self.transport_private_data_flag,
self.adaptation_field_extension_flag,
);
write!(f, "{}", msg)
}
}