mod timestamp;
pub use timestamp::{
PtsDts,
Timestamp,
};
use crate::ts::{
PACKET_SIZE,
TsPacketMut,
};
pub const STREAM_ID_VIDEO: u8 = 0xE0; pub const STREAM_ID_AUDIO: u8 = 0xC0; pub const STREAM_ID_PRIVATE_1: u8 = 0xBD; pub const STREAM_ID_PRIVATE_2: u8 = 0xBF;
#[derive(Debug, Clone)]
pub struct PesHeader {
stream_id: u8,
pts_dts: Option<PtsDts>,
data_alignment: bool,
}
impl PesHeader {
pub fn new(stream_id: u8) -> Self {
Self {
stream_id,
pts_dts: None,
data_alignment: false,
}
}
pub fn with_pts_dts(mut self, pts_dts: impl Into<PtsDts>) -> Self {
self.pts_dts = Some(pts_dts.into());
self
}
pub fn with_data_alignment(mut self, value: bool) -> Self {
self.data_alignment = value;
self
}
pub fn write(&self, buf: &mut [u8]) -> usize {
debug_assert!(buf.len() >= 32, "buffer too small for PES header");
buf[0] = 0x00;
buf[1] = 0x00;
buf[2] = 0x01;
buf[3] = self.stream_id;
buf[4] = 0x00;
buf[5] = 0x00;
let flags_1 = 0x80 | if self.data_alignment { 0x04 } else { 0x00 };
buf[6] = flags_1;
buf[7] = 0x00;
buf[8] = 0x00;
let mut offset = 9;
if let Some(pts_dts) = self.pts_dts {
let pts = pts_dts.pts;
if let Some(dts) = pts_dts.dts {
buf[7] |= 0b1100_0000; buf[8] += 10;
offset += pts.write(&mut buf[offset ..], 0b0011);
offset += dts.write(&mut buf[offset ..], 0b0001);
} else {
buf[7] |= 0b1000_0000; buf[8] += 5;
offset += pts.write(&mut buf[offset ..], 0b0010);
}
}
offset
}
}
pub struct EsFrame {
pub header: PesHeader,
pub payload: Vec<u8>,
pub rai: bool,
}
pub struct PesPacketizer {
pid: u16,
cc: u8,
pes_header: [u8; 32],
pes_header_len: usize,
offset: usize,
frame: Option<EsFrame>,
}
impl PesPacketizer {
pub fn new(pid: u16) -> Self {
Self {
pid,
cc: 0,
pes_header: [0u8; 32],
pes_header_len: 0,
offset: 0,
frame: None,
}
}
pub fn set_frame(&mut self, frame: EsFrame) {
self.pes_header_len = frame.header.write(&mut self.pes_header);
self.offset = 0;
self.frame = Some(frame);
}
pub fn build_pcr_packet(&mut self, packet: &mut [u8; PACKET_SIZE], pcr: u64) {
let mut ts = TsPacketMut::from(packet);
ts.init(self.pid, self.cc);
ts.set_adaptation_field(PACKET_SIZE - 4);
ts.set_pcr(pcr);
}
pub fn next(&mut self, packet: &mut [u8; PACKET_SIZE]) -> bool {
let Some(frame) = &self.frame else {
return false;
};
let is_first = self.offset == 0;
let total = self.pes_header_len + frame.payload.len();
let remaining = total - self.offset;
let mut af_size: usize = 0;
let max_payload = PACKET_SIZE - 4;
if is_first && frame.rai {
af_size = 2; }
let capacity = max_payload - af_size;
if remaining < capacity {
let stuffing = capacity - remaining;
af_size += stuffing;
}
let mut ts = TsPacketMut::from(&mut *packet);
ts.init(self.pid, self.cc);
ts.set_payload();
self.cc = (self.cc + 1) & 0x0F;
if af_size > 0 {
ts.set_adaptation_field(af_size);
}
if is_first {
ts.set_pusi();
if frame.rai {
ts.set_rai();
}
}
let ts_payload = ts.payload_mut().unwrap();
let mut pos = 0;
if self.offset < self.pes_header_len {
let n = (self.pes_header_len - self.offset).min(ts_payload.len());
ts_payload[.. n].copy_from_slice(&self.pes_header[self.offset .. self.offset + n]);
self.offset += n;
pos = n;
}
if self.offset >= self.pes_header_len {
let data_offset = self.offset - self.pes_header_len;
let space = ts_payload.len() - pos;
let n = (frame.payload.len() - data_offset).min(space);
if n > 0 {
ts_payload[pos .. pos + n]
.copy_from_slice(&frame.payload[data_offset .. data_offset + n]);
self.offset += n;
}
}
if self.offset >= total {
self.frame = None;
}
true
}
}