use crate::ts::{
PACKET_SIZE,
SYNC_BYTE,
TsPacketRef,
};
#[inline]
fn find_sync(data: &[u8]) -> Option<usize> {
let mut pos = 0;
while data.len() > pos {
if data[pos] == SYNC_BYTE {
let next = pos + PACKET_SIZE;
if data.len() > next {
if data[next] == SYNC_BYTE {
return Some(pos);
}
} else {
return Some(pos);
}
}
pos += 1;
}
None
}
pub struct TsSlicer {
buffer: [u8; PACKET_SIZE],
fill: usize,
}
impl Default for TsSlicer {
fn default() -> Self {
Self {
buffer: [0u8; PACKET_SIZE],
fill: 0,
}
}
}
impl TsSlicer {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn reset(&mut self) {
self.fill = 0;
}
pub fn slice<'a>(&'a mut self, data: &'a [u8]) -> TsSlicerIter<'a> {
if data.is_empty() {
return TsSlicerIter::new(self, &[]);
}
if self.fill > 0 {
let remain = PACKET_SIZE - self.fill;
if data.len() > remain {
if data[remain] != SYNC_BYTE {
self.fill = 0;
} else {
self.buffer[self.fill ..].copy_from_slice(&data[.. remain]);
self.fill = PACKET_SIZE;
return TsSlicerIter::new(self, &data[remain ..]);
}
} else {
let end = self.fill + data.len();
self.buffer[self.fill .. end].copy_from_slice(data);
self.fill = end;
return TsSlicerIter::new(self, &[]);
}
}
if let Some(skip) = find_sync(data) {
TsSlicerIter::new(self, &data[skip ..])
} else {
TsSlicerIter::new(self, &[])
}
}
}
pub struct TsSlicerIter<'a> {
slicer: &'a mut TsSlicer,
data: &'a [u8],
skip: usize,
}
impl<'a> TsSlicerIter<'a> {
#[inline]
fn new(slicer: &'a mut TsSlicer, data: &'a [u8]) -> Self {
Self {
slicer,
data,
skip: 0,
}
}
}
impl<'a> Iterator for TsSlicerIter<'a> {
type Item = TsPacketRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.slicer.fill > 0 {
if self.slicer.fill == PACKET_SIZE {
self.slicer.fill = 0;
let slice = self.slicer.buffer.as_ptr() as *const [u8; PACKET_SIZE];
return Some(TsPacketRef::from(unsafe { &*slice }));
} else {
return None;
}
}
let remain = self.data.len() - self.skip;
if remain >= PACKET_SIZE {
let end = self.skip + PACKET_SIZE;
let packet = &self.data[self.skip .. end];
self.skip = end;
let slice = packet.as_ptr() as *const [u8; PACKET_SIZE];
return Some(TsPacketRef::from(unsafe { &*slice }));
}
if remain > 0 {
self.slicer.buffer[.. remain].copy_from_slice(&self.data[self.skip ..]);
self.slicer.fill = remain;
}
None
}
}