1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
//! Push parsing of encoded NALs.
use crate::nal::{NalHeader, RefNal};
/// [`AccumulatedNalHandler`]'s interest in receiving additional callbacks on a NAL.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum NalInterest {
/// If this NAL is incomplete, buffer it and call again later.
/// No effect if the NAL is complete.
Buffer,
/// Don't buffer any more of this NAL or make any more calls on it.
Ignore,
}
/// [NalAccumulator] callback which handles partially- or completely-buffered NALs.
///
/// The simplest handler is a closure. Implement this type manually when you
/// your handler to own state which can be accessed via [NalAccumulator::handler],
/// [NalAccumulator::handler_mut], or [NalAccumulator::into_handler].
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)
}
}
/// Handles arbitrary fragments of NALs. See [NalAccumulator].
///
/// It's probably unnecessary to provide your own implementation of this trait
/// except when benchmarking or testing a parser.
pub trait NalFragmentHandler {
/// Pushes a fragment of a NAL.
///
/// The caller must ensure that each element of `bufs` (if there are any)
/// is non-empty.
fn nal_fragment(&mut self, bufs: &[&[u8]], end: bool);
}
/// NAL accumulator for push parsers.
///
/// This is meant to be used by parsers for a specific format: Annex B, AVC, MPEG-TS, RTP, etc.
/// Accumulates NALs in an internal buffer and delegates to an [AccumulatedNalHandler].
///
/// ```
/// use h264_reader::nal::{Nal, RefNal, UnitType};
/// use h264_reader::push::{NalAccumulator, NalFragmentHandler, NalInterest};
/// let mut calls = Vec::new();
/// let mut acc = NalAccumulator::new(|nal: RefNal<'_>| {
/// let nal_unit_type = nal.header().unwrap().nal_unit_type();
/// calls.push((nal_unit_type, nal.is_complete()));
/// match nal_unit_type {
/// UnitType::SeqParameterSet => NalInterest::Buffer,
/// _ => NalInterest::Ignore,
/// }
/// });
///
/// // Push a SeqParameterSet in two calls (the latter with two byte slices).
/// acc.nal_fragment(&[&b"\x67\x64\x00\x0A\xAC\x72\x84\x44\x26\x84\x00\x00\x03"[..]], false);
/// acc.nal_fragment(&[&b"\x00"[..], &b"\x04\x00\x00\x03\x00\xCA\x3C\x48\x96\x11\x80"[..]], true);
///
/// // Push a PicParameterSet in two calls.
/// acc.nal_fragment(&[&b"\x68"[..]], false);
/// acc.nal_fragment(&[&b"\xE8\x43\x8F\x13\x21\x30"[..]], true);
///
/// assert_eq!(calls, &[
/// (UnitType::SeqParameterSet, false),
/// (UnitType::SeqParameterSet, true),
/// (UnitType::PicParameterSet, false),
/// // no second call on the PicParameterSet because the handler returned Ignore.
/// ]);
/// ```
///
/// Non-trivial handlers may need to *own* state that can be accessed outside the handler:
///
/// ```
/// use h264_reader::nal::{Nal, RefNal, UnitType};
/// use h264_reader::push::{AccumulatedNalHandler, NalAccumulator, NalFragmentHandler, NalInterest};
/// struct MyHandler(Vec<UnitType>);
/// impl AccumulatedNalHandler for MyHandler {
/// fn nal(&mut self, nal: RefNal<'_>) -> NalInterest {
/// self.0.push(nal.header().unwrap().nal_unit_type());
/// NalInterest::Ignore
/// }
/// }
/// let mut acc = NalAccumulator::new(MyHandler(Vec::new()));
/// acc.nal_fragment(&[&b"\x67\x64\x00\x0A\xAC\x72\x84\x44\x26\x84\x00\x00\x03"[..]], false);
/// acc.nal_fragment(&[&b"\x00"[..], &b"\x04\x00\x00\x03\x00\xCA\x3C\x48\x96\x11\x80"[..]], true);
/// acc.nal_fragment(&[&b"\x68"[..]], false);
/// acc.nal_fragment(&[&b"\xE8\x43\x8F\x13\x21\x30"[..]], true);
/// assert_eq!(acc.handler().0, &[
/// UnitType::SeqParameterSet,
/// UnitType::PicParameterSet,
/// ]);
/// ```
pub struct NalAccumulator<H: AccumulatedNalHandler> {
buf: Vec<u8>,
nal_handler: H,
interest: NalInterest,
}
impl<H: AccumulatedNalHandler> NalAccumulator<H> {
/// Creates a new accumulator which delegates to the given `nal_handler` on every push.
/// `nal_handler` always sees the NAL from the beginning.
pub fn new(nal_handler: H) -> Self {
Self {
buf: Vec::new(),
interest: NalInterest::Buffer,
nal_handler,
}
}
/// Gets a reference to the handler.
pub fn handler(&self) -> &H {
&self.nal_handler
}
/// Gets a mutable reference to the handler.
pub fn handler_mut(&mut self) -> &mut H {
&mut self.nal_handler
}
/// Unwraps this `NalAccumulator<h>`, returning the inner handler.
pub fn into_handler(self) -> H {
self.nal_handler
}
}
impl<H: AccumulatedNalHandler> NalFragmentHandler for NalAccumulator<H> {
/// Calls `nal_handler` with accumulated NAL unless any of the following are true:
/// * a previous call on the same NAL returned [`NalInterest::Ignore`].
/// * the NAL is totally empty.
/// * `bufs` is empty and `end` is false.
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; // no-op.
} else {
RefNal::new(bufs[0], &bufs[1..], end)
};
// Call the NAL handler. Avoid copying unless necessary.
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() {
// Try buffering everything.
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][..],
]
);
// Try buffering nothing and see what's given on the first push.
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][..],
]
);
}
}