use alloc::vec::Vec;
#[derive(Debug, Default)]
pub struct PesAssembler {
buf: Vec<u8>,
started: bool,
}
impl PesAssembler {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn feed(&mut self, payload_unit_start: bool, payload: &[u8]) -> Option<Vec<u8>> {
if payload_unit_start {
let completed = if self.started && !self.buf.is_empty() {
Some(core::mem::take(&mut self.buf))
} else {
None
};
self.started = true;
self.buf.extend_from_slice(payload);
completed
} else {
if self.started {
self.buf.extend_from_slice(payload);
}
None
}
}
#[must_use]
pub fn flush(&mut self) -> Option<Vec<u8>> {
self.started = false;
if self.buf.is_empty() {
None
} else {
Some(core::mem::take(&mut self.buf))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::PesPacket;
#[test]
fn reassembles_across_packets_and_flushes() {
let mut a = PesAssembler::new();
assert_eq!(
a.feed(true, &[0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x80]),
None
);
assert_eq!(
a.feed(false, &[0x80, 0x05, 0x21, 0x00, 0x01, 0x00, 0x01]),
None
);
assert_eq!(a.feed(false, &[0xAA, 0xBB]), None);
let first = a
.feed(
true,
&[0x00, 0x00, 0x01, 0xC0, 0x00, 0x00, 0x80, 0x00, 0x00, 0x11],
)
.expect("first PES emitted on next unit start");
let p1 = PesPacket::parse(&first).unwrap();
assert!(p1.stream_id.is_video());
assert_eq!(p1.payload, &[0xAA, 0xBB]);
let second = a.flush().expect("second PES flushed");
let p2 = PesPacket::parse(&second).unwrap();
assert!(p2.stream_id.is_audio());
assert!(a.flush().is_none());
}
#[test]
fn ignores_continuation_before_first_start() {
let mut a = PesAssembler::new();
assert_eq!(a.feed(false, &[0xDE, 0xAD]), None); assert!(a.flush().is_none());
}
}