use crate::nal::{NalHeader, RefNal};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum NalInterest {
Buffer,
Ignore,
}
pub trait AccumulatedNalHandler {
fn nal(&mut self, nal: RefNal<'_>) -> NalInterest;
}
impl<F: FnMut(RefNal<'_>) -> NalInterest> AccumulatedNalHandler for F {
fn nal(&mut self, nal: RefNal<'_>) -> NalInterest {
(self)(nal)
}
}
pub trait NalFragmentHandler {
fn nal_fragment(&mut self, bufs: &[&[u8]], end: bool);
}
pub struct NalAccumulator<H: AccumulatedNalHandler> {
buf: Vec<u8>,
nal_handler: H,
interest: NalInterest,
}
impl<H: AccumulatedNalHandler> NalAccumulator<H> {
pub fn new(nal_handler: H) -> Self {
Self {
buf: Vec::new(),
interest: NalInterest::Buffer,
nal_handler,
}
}
pub fn handler(&self) -> &H {
&self.nal_handler
}
pub fn handler_mut(&mut self) -> &mut H {
&mut self.nal_handler
}
pub fn into_handler(self) -> H {
self.nal_handler
}
}
impl<H: AccumulatedNalHandler> NalFragmentHandler for NalAccumulator<H> {
fn nal_fragment(&mut self, bufs: &[&[u8]], end: bool) {
if self.interest != NalInterest::Ignore {
let nal = if !self.buf.is_empty() {
RefNal::new(&self.buf[..], bufs, end)
} else if bufs.is_empty() {
return; } else {
RefNal::new(bufs[0], &bufs[1..], end)
};
match self.nal_handler.nal(nal) {
NalInterest::Buffer if !end => {
let len = bufs.iter().map(|b| b.len()).sum();
self.buf.reserve(len);
for b in bufs {
self.buf.extend_from_slice(b);
}
}
NalInterest::Ignore => self.interest = NalInterest::Ignore,
_ => {}
}
}
if end {
self.buf.clear();
self.interest = NalInterest::Buffer;
}
}
}
impl<H: AccumulatedNalHandler + std::fmt::Debug> std::fmt::Debug for NalAccumulator<H> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NalAccumulator")
.field("interest", &self.interest)
.field("buf", &self.buf)
.field("header", &self.buf.first().map(|&h| NalHeader::new(h)))
.field("nal_handler", &self.nal_handler)
.finish()
}
}
#[cfg(test)]
mod test {
use crate::nal::Nal;
use std::io::{BufRead, Read};
use super::*;
#[test]
fn accumulate() {
let mut nals = Vec::new();
let handler = |nal: RefNal<'_>| {
if nal.is_complete() {
let mut buf = Vec::new();
nal.reader().read_to_end(&mut buf).unwrap();
nals.push(buf);
}
NalInterest::Buffer
};
let mut accumulator = NalAccumulator::new(handler);
accumulator.nal_fragment(&[], false);
accumulator.nal_fragment(&[], true);
accumulator.nal_fragment(&[&[0b0101_0001], &[1]], true);
accumulator.nal_fragment(&[&[0b0101_0001]], false);
accumulator.nal_fragment(&[], false);
accumulator.nal_fragment(&[&[2]], true);
accumulator.nal_fragment(&[&[0b0101_0001]], false);
accumulator.nal_fragment(&[], false);
accumulator.nal_fragment(&[&[3]], false);
accumulator.nal_fragment(&[], true);
assert_eq!(
nals,
&[
&[0b0101_0001, 1][..],
&[0b0101_0001, 2][..],
&[0b0101_0001, 3][..],
]
);
nals.clear();
let handler = |nal: RefNal<'_>| {
nals.push(nal.reader().fill_buf().unwrap().to_owned());
NalInterest::Ignore
};
let mut accumulator = NalAccumulator::new(handler);
accumulator.nal_fragment(&[], false);
accumulator.nal_fragment(&[], true);
accumulator.nal_fragment(&[&[0b0101_0001, 1]], true);
accumulator.nal_fragment(&[&[0b0101_0001]], false);
accumulator.nal_fragment(&[], false);
accumulator.nal_fragment(&[&[2]], true);
accumulator.nal_fragment(&[&[0b0101_0001]], false);
accumulator.nal_fragment(&[], false);
accumulator.nal_fragment(&[&[3]], false);
accumulator.nal_fragment(&[], true);
assert_eq!(
nals,
&[
&[0b0101_0001, 1][..],
&[0b0101_0001][..],
&[0b0101_0001][..],
]
);
}
}