use crate::error::{Error, Result};
use crate::ts::{
AdaptationField, AdaptationFieldControl, Pcr, ScramblingControl, TsHeader, ADAPTATION_FLAG,
AF_PCR_FLAG, CC_MASK, TS_PACKET_SIZE, TS_SYNC_BYTE,
};
const NULL_PID: u16 = 0x1FFF;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct OwnedTsPacket {
#[cfg_attr(feature = "serde", serde(serialize_with = "serialize_raw_bytes"))]
pub raw: [u8; TS_PACKET_SIZE],
pub pid: u16,
pub pusi: bool,
pub has_adaptation: bool,
pub has_payload: bool,
pub tei: bool,
pub scrambling: u8,
pub continuity_counter: u8,
pub discontinuity: bool,
}
#[cfg(feature = "serde")]
fn serialize_raw_bytes<S: serde::Serializer>(
bytes: &[u8; TS_PACKET_SIZE],
s: S,
) -> core::result::Result<S::Ok, S::Error> {
use serde::ser::SerializeSeq;
let mut seq = s.serialize_seq(Some(bytes.len()))?;
for b in bytes {
seq.serialize_element(b)?;
}
seq.end()
}
impl OwnedTsPacket {
pub fn parse(raw: [u8; TS_PACKET_SIZE]) -> Result<Self> {
if raw[0] != TS_SYNC_BYTE {
return Err(Error::InvalidSyncByte { found: raw[0] });
}
let hdr = TsHeader::parse(&raw[..4])?;
Ok(Self {
raw,
pid: hdr.pid,
pusi: hdr.pusi,
has_adaptation: hdr.has_adaptation,
has_payload: hdr.has_payload,
tei: hdr.tei,
scrambling: hdr.scrambling,
continuity_counter: hdr.continuity_counter,
discontinuity: false,
})
}
pub fn scrambling_control(&self) -> ScramblingControl {
ScramblingControl::from_bits(self.scrambling)
}
pub fn adaptation_field_control(&self) -> AdaptationFieldControl {
AdaptationFieldControl::from_flags(self.has_adaptation, self.has_payload)
}
pub fn payload(&self) -> Option<&[u8]> {
if !self.has_payload {
return None;
}
let offset = self.payload_offset();
if offset < TS_PACKET_SIZE {
Some(&self.raw[offset..])
} else {
None
}
}
pub fn payload_mut(&mut self) -> Option<&mut [u8]> {
if !self.has_payload {
return None;
}
let offset = self.payload_offset();
if offset < TS_PACKET_SIZE {
Some(&mut self.raw[offset..])
} else {
None
}
}
#[inline]
fn payload_offset(&self) -> usize {
let mut offset = 4;
if self.has_adaptation {
let af_len = self.raw[4] as usize;
offset += 1 + af_len;
}
offset
}
pub fn serialize_with_payload(
pid: u16,
pusi: bool,
cc: u8,
payload: &[u8],
) -> [u8; TS_PACKET_SIZE] {
let mut pkt = [0xFFu8; TS_PACKET_SIZE];
let hdr = TsHeader {
tei: false,
pusi,
pid,
scrambling: 0,
has_adaptation: false,
has_payload: true,
continuity_counter: cc & 0x0F,
};
hdr.serialize_into(&mut pkt)
.expect("serialize TsHeader into 188-byte buf");
let copy_len = payload.len().min(184);
pkt[4..4 + copy_len].copy_from_slice(&payload[..copy_len]);
pkt
}
#[must_use]
pub fn null_packet(cc: u8) -> [u8; TS_PACKET_SIZE] {
Self::serialize_with_payload(NULL_PID, false, cc, &[])
}
pub fn set_continuity_counter(packet: &mut [u8; TS_PACKET_SIZE], cc: u8) {
packet[3] = (packet[3] & !CC_MASK) | (cc & CC_MASK);
}
pub fn set_pcr(packet: &mut [u8; TS_PACKET_SIZE], pcr: Pcr) -> Result<()> {
if packet[3] & ADAPTATION_FLAG == 0 {
return Err(Error::BufferTooShort {
need: 6,
have: 0,
what: "set_pcr: no adaptation field",
});
}
let af_len = packet[4] as usize;
if af_len < 1 {
return Err(Error::BufferTooShort {
need: 1,
have: 0,
what: "set_pcr: adaptation field length is 0 (no flags byte)",
});
}
if packet[5] & AF_PCR_FLAG == 0 {
return Err(Error::BufferTooShort {
need: 6,
have: 0,
what: "set_pcr: PCR flag not set in adaptation field",
});
}
let pcr_start = 6usize;
let pcr_end = pcr_start + 6;
if packet.len() < pcr_end {
return Err(Error::BufferTooShort {
need: pcr_end,
have: packet.len(),
what: "set_pcr: packet too short for PCR field",
});
}
packet[pcr_start..pcr_end].copy_from_slice(&pcr.to_field_bytes());
Ok(())
}
pub fn adaptation_field(&self) -> Option<crate::Result<AdaptationField<'_>>> {
if self.raw[3] & ADAPTATION_FLAG == 0 {
return None;
}
let af_len = self.raw[4] as usize;
if af_len == 0 || 5 + af_len > TS_PACKET_SIZE {
return None;
}
Some(AdaptationField::parse(&self.raw[5..5 + af_len]))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn owned_round_trip_and_payload_mut() {
let payload = [0xAAu8; 184];
let mut pkt = OwnedTsPacket::parse(OwnedTsPacket::serialize_with_payload(
0x0100, true, 7, &payload,
))
.unwrap();
assert_eq!(pkt.pid, 0x0100);
assert!(pkt.pusi);
assert_eq!(pkt.continuity_counter, 7);
assert_eq!(pkt.payload().unwrap()[..184], payload[..]);
pkt.payload_mut().unwrap()[0] = 0x55;
assert_eq!(pkt.payload().unwrap()[0], 0x55);
assert!(!pkt.discontinuity);
}
#[test]
fn owned_scrambling_control_accessor() {
let make = |scrambling_bits: u8| -> OwnedTsPacket {
let mut raw = OwnedTsPacket::serialize_with_payload(0x0100, false, 0, &[]);
raw[3] = (raw[3] & 0x3F) | (scrambling_bits << 6);
OwnedTsPacket::parse(raw).unwrap()
};
assert_eq!(
make(0b00).scrambling_control(),
ScramblingControl::NotScrambled
);
assert_eq!(make(0b01).scrambling_control(), ScramblingControl::Reserved);
assert_eq!(make(0b10).scrambling_control(), ScramblingControl::EvenKey);
assert_eq!(make(0b11).scrambling_control(), ScramblingControl::OddKey);
}
#[test]
fn owned_adaptation_field_control_accessor() {
let make = |afc_bits: u8| -> OwnedTsPacket {
let mut raw = [0xFFu8; TS_PACKET_SIZE];
raw[0] = TS_SYNC_BYTE;
raw[1] = 0x00;
raw[2] = 0x00;
raw[3] = (afc_bits << 4) & 0x30;
if afc_bits & 0b10 != 0 {
raw[4] = 0; }
OwnedTsPacket::parse(raw).unwrap()
};
assert_eq!(
make(0b00).adaptation_field_control(),
AdaptationFieldControl::Reserved
);
assert_eq!(
make(0b01).adaptation_field_control(),
AdaptationFieldControl::PayloadOnly
);
assert_eq!(
make(0b10).adaptation_field_control(),
AdaptationFieldControl::AdaptationOnly
);
assert_eq!(
make(0b11).adaptation_field_control(),
AdaptationFieldControl::AdaptationAndPayload
);
}
}