use crate::error::{Error, Kind as ErrorKind};
use crate::header::{Adaptation, Header};
use crate::pcr::PCR;
use crate::pid::PID;
use crate::result::Result;
pub struct Packet<'buf> {
buf: &'buf [u8],
}
impl<'buf> Packet<'buf> {
pub const SZ: usize = 188;
const SYNC_BYTE: u8 = 0x47;
#[inline(always)]
pub fn new(buf: &'buf [u8]) -> Result<Packet<'buf>> {
let pkt = Packet { buf };
pkt.validate()?;
Ok(pkt)
}
#[inline(always)]
fn validate(&self) -> Result<()> {
if self.buf.len() != Self::SZ {
Err(Error::new(ErrorKind::Buf(self.buf.len(), Self::SZ)))
} else if self.buf[0] != Self::SYNC_BYTE {
Err(Error::new(ErrorKind::SyncByte(self.buf[0])))
} else {
Ok(())
}
}
#[inline(always)]
fn buf_pos_adaptation() -> usize {
Header::SZ
}
#[inline(always)]
fn buf_pos_payload(&self, is_section: bool) -> usize {
let mut pos = Self::buf_pos_adaptation();
let header = self.header();
if header.got_adaptation() {
let adapt = Adaptation::new(self.buf_seek(pos));
pos += adapt.sz();
}
if header.pusi() && is_section {
pos += (self.buf[pos] as usize) + 1;
}
pos
}
#[inline(always)]
fn buf_seek(&self, offset: usize) -> &'buf [u8] {
&self.buf[offset..]
}
#[inline(always)]
fn buf_try_seek(&self, offset: usize) -> Result<&'buf [u8]> {
if self.buf.len() <= offset {
Err(Error::new(ErrorKind::Buf(self.buf.len(), Self::SZ)))
} else {
Ok(self.buf_seek(offset))
}
}
#[inline(always)]
fn buf_adaptation(&self) -> Result<&'buf [u8]> {
self.buf_try_seek(Self::buf_pos_adaptation())
}
#[inline(always)]
fn buf_payload(&self, is_section: bool) -> Result<&'buf [u8]> {
self.buf_try_seek(self.buf_pos_payload(is_section))
}
#[inline(always)]
pub fn buf_payload_section(&self) -> Result<&'buf [u8]> {
self.buf_payload(true)
}
#[inline(always)]
pub fn buf_payload_pes(&self) -> Result<&'buf [u8]> {
self.buf_payload(false)
}
#[inline(always)]
fn header(&self) -> Header<'buf> {
Header::new(self.buf)
}
#[inline(always)]
fn adaptation(&self) -> Option<Result<Adaptation<'buf>>> {
let header = self.header();
if header.got_adaptation() {
match self.buf_adaptation() {
Ok(buf) => Some(Adaptation::try_new(buf)),
Err(e) => Some(Err(e)),
}
} else {
None
}
}
#[inline(always)]
pub fn pid(&self) -> PID {
self.header().pid()
}
#[inline(always)]
pub fn cc(&self) -> u8 {
self.header().cc()
}
#[inline(always)]
pub fn pusi(&self) -> bool {
self.header().pusi()
}
#[inline(always)]
pub fn pcr(&self) -> Result<Option<PCR<'buf>>> {
self.adaptation()
.and_then(|res| match res {
Ok(adapt) => adapt.pcr().map(Ok),
Err(e) => Some(Err(e)),
})
.transpose()
}
#[inline(always)]
pub fn pat(&self) -> Result<Option<&'buf [u8]>> {
let header = self.header();
if !header.got_payload() {
return Ok(None);
}
let res = if self.pid() == PID::PAT {
match self.buf_payload_section() {
Ok(buf) => Some(Ok(buf)),
Err(e) => Some(Err(e)),
}
} else {
None
};
res.transpose()
}
#[inline(always)]
pub fn pmt(&self, pid: u16) -> Result<Option<&'buf [u8]>> {
let header = self.header();
if !header.got_payload() {
return Ok(None);
}
let res = if u16::from(self.pid()) == pid {
match self.buf_payload_section() {
Ok(buf) => Some(Ok(buf)),
Err(e) => Some(Err(e)),
}
} else {
None
};
res.transpose()
}
#[inline(always)]
pub fn eit(&self) -> Result<Option<&'buf [u8]>> {
let header = self.header();
if !header.got_payload() {
return Ok(None);
}
let res = if self.pid() == PID::EIT {
match self.buf_payload_section() {
Ok(buf) => Some(Ok(buf)),
Err(e) => Some(Err(e)),
}
} else {
None
};
res.transpose()
}
}