use alloc::vec::Vec;
use broadcast_common::pusi::PusiAccumulator;
#[derive(Debug, Default)]
pub struct PesAssembler {
inner: PusiAccumulator,
}
impl PesAssembler {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn with_max_unit_size(max: usize) -> Self {
Self {
inner: PusiAccumulator::with_max_unit_size(max),
}
}
#[must_use]
pub fn feed(&mut self, payload_unit_start: bool, payload: &[u8]) -> Option<Vec<u8>> {
self.inner.feed(payload_unit_start, payload)
}
#[must_use]
pub fn flush(&mut self) -> Option<Vec<u8>> {
self.inner.flush()
}
}
#[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 oversized_pes_is_discarded_not_buffered_forever() {
let mut a = PesAssembler::with_max_unit_size(100);
assert_eq!(a.feed(true, &[0xAA; 60]), None);
assert_eq!(a.feed(false, &[0xBB; 60]), None); assert_eq!(a.feed(false, &[0xCC; 10]), None); assert_eq!(
a.feed(true, &[0xDD; 3]),
None,
"nothing to emit: the PES was dropped"
);
assert_eq!(a.flush().as_deref(), Some([0xDD; 3].as_slice()));
}
#[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());
}
}