use std::fmt;
use std::time::Duration;
use crate::duration_fmt::DurationFmt;
use crate::error::{Error, Kind as ErrorKind};
use crate::rational;
use crate::rational::Rational;
use crate::result::Result;
pub struct Timestamp<'buf> {
buf: &'buf [u8],
}
impl<'buf> Timestamp<'buf> {
const SZ: usize = 5;
const TB: Rational = rational::TB_90KHZ;
#[inline(always)]
fn new(buf: &'buf [u8]) -> Timestamp<'buf> {
Timestamp { buf }
}
pub fn value(&self) -> u64 {
((u64::from(self.buf[0]) & 0b0000_1110) << 29) | (u64::from(self.buf[1]) << 22)
| (u64::from(self.buf[2] & 0b1111_1110) << 14) | (u64::from(self.buf[3]) << 7)
| u64::from((self.buf[4] & 0b1111_1110) >> 1)
}
pub fn ns(&self) -> u64 {
rational::rescale(self.value(), Self::TB, rational::TB_1NS)
}
}
impl<'buf> From<&Timestamp<'buf>> for Duration {
fn from(t: &Timestamp) -> Self {
Duration::from_nanos(t.ns())
}
}
impl<'buf> From<Timestamp<'buf>> for Duration {
fn from(t: Timestamp) -> Self {
Duration::from(&t)
}
}
impl<'buf> From<&Timestamp<'buf>> for DurationFmt {
fn from(t: &Timestamp) -> Self {
DurationFmt::from_nanos(t.ns())
}
}
impl<'buf> fmt::Debug for Timestamp<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
":v(90kHz) {} :v(ns) {} :duration {}",
self.value(),
self.ns(),
DurationFmt::from(self)
)
}
}
impl<'buf> fmt::Display for Timestamp<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
DurationFmt::from(self).fmt(f)
}
}
#[derive(Debug, PartialEq)]
pub enum StreamID {
ProgramStreamMap,
PrivateStream1,
PaddingStream,
PrivateStream2,
AudioStreamNumber(u8),
VideoStreamNumber(u8),
ECMStream,
EMMStream,
DSMCCStream,
ISOIEC13522Stream,
TypeA,
TypeB,
TypeC,
TypeD,
TypeE,
AncillaryStream,
SLPacketizedStream,
FlexMuxStream,
MetadataStream,
ExtendedStreamId,
ReservedDataStream,
ProgramStreamDirectory,
Other(u8),
}
impl StreamID {
#[inline(always)]
pub fn is1(self) -> bool {
self != StreamID::ProgramStreamMap
&& self != StreamID::PaddingStream
&& self != StreamID::PrivateStream2
&& self != StreamID::ECMStream
&& self != StreamID::EMMStream
&& self != StreamID::ProgramStreamDirectory
&& self != StreamID::DSMCCStream
&& self != StreamID::TypeE
}
#[inline(always)]
pub fn is2(self) -> bool {
self == StreamID::ProgramStreamMap
|| self == StreamID::PrivateStream2
|| self == StreamID::ECMStream
|| self == StreamID::EMMStream
|| self == StreamID::ProgramStreamDirectory
|| self == StreamID::DSMCCStream
|| self == StreamID::TypeE
}
#[inline(always)]
pub fn is3(self) -> bool {
self == StreamID::PaddingStream
}
}
impl From<u8> for StreamID {
fn from(d: u8) -> Self {
match d {
0b1011_1100 => StreamID::ProgramStreamMap,
0b1011_1101 => StreamID::PrivateStream1,
0b1011_1110 => StreamID::PaddingStream,
0b1011_1111 => StreamID::PrivateStream2,
0b1100_0000..=0b1101_1111 => StreamID::AudioStreamNumber(d),
0b1110_0000..=0b1110_1111 => StreamID::VideoStreamNumber(d),
0b1111_0000 => StreamID::ECMStream,
0b1111_0001 => StreamID::EMMStream,
0b1111_0010 => StreamID::DSMCCStream,
0b1111_0011 => StreamID::ISOIEC13522Stream,
0b1111_0100 => StreamID::TypeA,
0b1111_0101 => StreamID::TypeB,
0b1111_0110 => StreamID::TypeC,
0b1111_0111 => StreamID::TypeD,
0b1111_1000 => StreamID::TypeE,
0b1111_1001 => StreamID::AncillaryStream,
0b1111_1010 => StreamID::SLPacketizedStream,
0b1111_1011 => StreamID::FlexMuxStream,
0b1111_1100 => StreamID::MetadataStream,
0b1111_1101 => StreamID::ExtendedStreamId,
0b1111_1110 => StreamID::ReservedDataStream,
0b1111_1111 => StreamID::ProgramStreamDirectory,
_ => StreamID::Other(d),
}
}
}
impl From<StreamID> for u8 {
fn from(sid: StreamID) -> u8 {
match sid {
StreamID::ProgramStreamMap => 0b1011_1100,
StreamID::PrivateStream1 => 0b1011_1101,
StreamID::PaddingStream => 0b1011_1110,
StreamID::PrivateStream2 => 0b1011_1111,
StreamID::AudioStreamNumber(d) => d,
StreamID::VideoStreamNumber(d) => d,
StreamID::ECMStream => 0b1111_0000,
StreamID::EMMStream => 0b1111_0001,
StreamID::DSMCCStream => 0b1111_0010,
StreamID::ISOIEC13522Stream => 0b1111_0011,
StreamID::TypeA => 0b1111_0100,
StreamID::TypeB => 0b1111_0101,
StreamID::TypeC => 0b1111_0110,
StreamID::TypeD => 0b1111_0111,
StreamID::TypeE => 0b1111_1000,
StreamID::AncillaryStream => 0b1111_1001,
StreamID::SLPacketizedStream => 0b1111_1010,
StreamID::FlexMuxStream => 0b1111_1011,
StreamID::MetadataStream => 0b1111_1100,
StreamID::ExtendedStreamId => 0b1111_1101,
StreamID::ReservedDataStream => 0b1111_1110,
StreamID::ProgramStreamDirectory => 0b1111_1111,
StreamID::Other(d) => d,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ScramblingControl {
NotScrabled,
UserDefined(u8),
}
impl From<u8> for ScramblingControl {
#[inline(always)]
fn from(d: u8) -> Self {
match d {
0b00 => ScramblingControl::NotScrabled,
_ => ScramblingControl::UserDefined(d),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PtsDtsFlag {
No,
Pts,
PtsDts,
Forbidden,
}
impl From<u8> for PtsDtsFlag {
#[inline(always)]
fn from(d: u8) -> Self {
match d {
0b00 => PtsDtsFlag::No,
0b10 => PtsDtsFlag::Pts,
0b11 => PtsDtsFlag::PtsDts,
_ => PtsDtsFlag::Forbidden,
}
}
}
pub struct PES<'buf> {
buf: &'buf [u8],
}
impl<'buf> PES<'buf> {
const HEADER_SZ: usize = 6;
const HEADER_SZ_1: usize = 3;
const START_CODE: u32 = 0x0000_0001;
const PTS_OFFSET_LFT: usize = 9;
const PTS_OFFSET_RGHT: usize = Self::PTS_OFFSET_LFT + Timestamp::SZ;
const DTS_OFFSET_LFT: usize = Self::PTS_OFFSET_RGHT;
const DTS_OFFSET_RGHT: usize = Self::DTS_OFFSET_LFT + Timestamp::SZ;
#[inline(always)]
pub fn new(buf: &'buf [u8]) -> PES<'buf> {
PES { buf }
}
#[inline(always)]
pub fn try_new(buf: &'buf [u8]) -> Result<PES<'buf>> {
let p = PES::new(buf);
p.validate()?;
Ok(p)
}
#[inline(always)]
pub fn validate(&self) -> Result<()> {
let sz1 = || PES::HEADER_SZ + PES::HEADER_SZ_1 + (self.pes_header_data_length() as usize);
if self.buf.len() < Self::HEADER_SZ {
Err(Error::new(ErrorKind::Buf(self.buf.len(), Self::HEADER_SZ)))
} else if self.start_code() != Self::START_CODE {
Err(Error::new(ErrorKind::PESStartCode(self.start_code())))
} else if self.stream_id().is1() && self.buf.len() < sz1() {
Err(Error::new(ErrorKind::Buf(self.buf.len(), sz1())))
} else {
Ok(())
}
}
#[inline(always)]
fn start_code(&self) -> u32 {
(u32::from(self.buf[0]) << 16) | (u32::from(self.buf[1]) << 8) | u32::from(self.buf[2])
}
#[inline(always)]
fn stream_id(&self) -> StreamID {
StreamID::from(self.buf[3])
}
#[inline(always)]
#[allow(dead_code)]
fn packet_length(&self) -> u16 {
u16::from(self.buf[4]) << 8 | u16::from(self.buf[5])
}
#[inline(always)]
fn pts_dts_flag(&self) -> Option<PtsDtsFlag> {
if self.stream_id().is1() {
Some(PtsDtsFlag::from((self.buf[7] & 0b1100_0000) >> 6))
} else {
None
}
}
#[inline(always)]
fn pes_header_data_length(&self) -> usize {
usize::from(self.buf[8])
}
#[inline(always)]
pub fn pts(&self) -> Option<Timestamp> {
self.pts_dts_flag().and_then(|flag| match flag {
PtsDtsFlag::Pts | PtsDtsFlag::PtsDts => Some(Timestamp::new(
&self.buf[Self::PTS_OFFSET_LFT..Self::PTS_OFFSET_RGHT],
)),
_ => None,
})
}
#[inline(always)]
pub fn dts(&self) -> Option<Timestamp> {
self.pts_dts_flag().and_then(|flag| match flag {
PtsDtsFlag::PtsDts => Some(Timestamp::new(
&self.buf[Self::DTS_OFFSET_LFT..Self::DTS_OFFSET_RGHT],
)),
_ => None,
})
}
#[inline(always)]
pub fn buf_seek_payload(&self) -> &'buf [u8] {
if self.stream_id().is1() {
&self.buf[(Self::HEADER_SZ + Self::HEADER_SZ_1)..]
} else {
&self.buf[Self::HEADER_SZ..]
}
}
}
impl<'buf> fmt::Debug for PES<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, ":PES (")?;
if let Some(pts) = self.pts() {
write!(f, ":pts {}", pts)?;
}
if let Some(dts) = self.dts() {
write!(f, " :dts {}", dts)?;
}
write!(f, ")")
}
}