use log::{debug, trace, warn};
use nom::{
bits::{
bits,
complete::{tag as tag_bits, take as take_bits},
},
bytes::complete::tag as tag_bytes,
IResult, Parser as _,
};
use std::fmt;
use super::{
clock::{clock_and_ext, Clock},
pes,
};
use crate::vobsub::{NomError, VobSubError};
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
pub scr: Clock,
pub bit_rate: u32,
}
impl fmt::Display for Header {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"[PS packet @ {}, {} kbps]",
self.scr,
(self.bit_rate * 50 * 8) / 1024
)
}
}
pub fn header(input: &[u8]) -> IResult<&[u8], Header> {
const PS_HEADER_TAG: &[u8] = &[0x00, 0x00, 0x01, 0xba];
let tag1 = tag_bytes(PS_HEADER_TAG);
let header_parse = bits(|input| {
let tag_mpeg2 = tag_bits(0b01, 2u8);
let bit_rate = take_bits(22u32);
let marker_bits = tag_bits(0b11, 2u8);
let reserved = take_bits::<_, u8, u8, nom::error::Error<(&[u8], usize)>>(5u8);
let stuffing_length =
take_bits::<_, usize, usize, nom::error::Error<(&[u8], usize)>>(3usize);
let (input, (_, scr, bit_rate, _, _, stuffing_length)) = (
tag_mpeg2,
clock_and_ext,
bit_rate,
marker_bits,
reserved,
stuffing_length,
)
.parse(input)?;
let (input, _) = take_bits::<_, u64, _, _>(stuffing_length * 8)(input)?;
Ok((input, Header { scr, bit_rate }))
});
let (input, (_, header)) = (tag1, header_parse).parse(input)?;
Ok((input, header))
}
#[derive(Debug, PartialEq, Eq)]
pub struct PesPacket<'a> {
pub ps_header: Header,
pub pes_packet: pes::Packet<'a>,
}
pub fn pes_packet(input: &[u8]) -> IResult<&[u8], PesPacket<'_>> {
let (input, (ps_header, pes_packet)) = (header, pes::packet).parse(input)?;
Ok((
input,
PesPacket {
ps_header,
pes_packet,
},
))
}
pub struct PesPackets<'a> {
remaining: &'a [u8],
}
impl<'a> Iterator for PesPackets<'a> {
type Item = Result<PesPacket<'a>, VobSubError>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let needle = &[0x00, 0x00, 0x01, 0xba];
let start = self
.remaining
.windows(needle.len())
.position(|window| needle == window);
if let Some(start) = start {
self.remaining = &self.remaining[start..];
match pes_packet(self.remaining) {
IResult::Ok((remaining, packet)) => {
self.remaining = remaining;
trace!("Decoded packet {:?}", &packet);
return Some(Ok(packet));
}
IResult::Err(err) => match err {
nom::Err::Incomplete(needed) => {
self.remaining = &[];
warn!("Incomplete packet, need: {needed:?}");
return Some(Err(VobSubError::PESPacket(NomError::IncompleteInput(
needed,
))));
}
nom::Err::Error(err) | nom::Err::Failure(err) => {
self.remaining = &self.remaining[needle.len()..];
debug!("Skipping packet {:?}", &err);
}
},
}
} else {
self.remaining = &[];
trace!("Reached end of data");
return None;
}
}
}
}
pub const fn pes_packets(input: &[u8]) -> PesPackets<'_> {
PesPackets { remaining: input }
}