| pub mod fwht; | |
| pub mod h264; | |
| use log::error; | |
| use std::io; | |
| /// Trait for classes able to iterate an encoded stream over chunks of decodable units (typically | |
| /// frames). | |
| pub trait StreamSplitter: Iterator<Item = Vec<u8>> {} | |
| /// Splits a stream at each encounter of a given pattern. Useful to extract decodable units (or | |
| /// frames from an encoded stream. | |
| struct PatternSplitter<S: io::Read> { | |
| /// The pattern to split at. | |
| pattern: Vec<u8>, | |
| stream: io::Bytes<S>, | |
| } | |
| impl<S: io::Read> PatternSplitter<S> { | |
| /// Create a new splitter that will split `stream` at each instance of `pattern`. | |
| /// | |
| /// `stream` must start with `pattern`, otherwise the input is considered invalid and `None` is | |
| /// returned. | |
| fn new(pattern: impl Into<Vec<u8>>, stream: S) -> Option<Self> { | |
| let mut stream = stream.bytes(); | |
| let pattern = pattern.into(); | |
| // The stream must begin by our header, or it is invalid. | |
| let stream_start = (0..pattern.len()) | |
| .map(|_| stream.next().unwrap_or(Ok(0)).unwrap_or(0)) | |
| .collect::<Vec<_>>(); | |
| if stream_start == pattern { | |
| Some(PatternSplitter { pattern, stream }) | |
| } else { | |
| None | |
| } | |
| } | |
| } | |
| impl<S: io::Read> Iterator for PatternSplitter<S> { | |
| type Item = Vec<u8>; | |
| /// Returns the next frame in the stream, header included. | |
| fn next(&mut self) -> Option<Self::Item> { | |
| let mut frame_data: Vec<u8> = Vec::with_capacity(0x10000); | |
| // Add the header of the frame since we are already past it. | |
| frame_data.extend(&self.pattern); | |
| // Window used to try and detect the next frame header. | |
| let mut header_window: Vec<u8> = Vec::with_capacity(self.pattern.len()); | |
| // Iterator to the next character expected for a frame header. | |
| let mut header_iter = self.pattern.iter().peekable(); | |
| loop { | |
| let b = match self.stream.next() { | |
| Some(Ok(b)) => b, | |
| // End of stream, commit all read data and return. | |
| None => { | |
| frame_data.extend(&header_window); | |
| // If the only data is our pre-filled header, then we haven't | |
| // read anything and thus there is no frame to return. | |
| return if frame_data.len() <= self.pattern.len() { | |
| None | |
| } else { | |
| Some(frame_data) | |
| }; | |
| } | |
| Some(Err(e)) => { | |
| error!("Error while reading stream: {}", e); | |
| return None; | |
| } | |
| }; | |
| // Add the read byte to the header candidate buffer. | |
| header_window.push(b); | |
| // Possibly a header? | |
| if Some(&&b) == header_iter.peek() { | |
| header_iter.next(); | |
| // Found next frame's header, return read data. | |
| if header_iter.peek().is_none() { | |
| return Some(frame_data); | |
| } | |
| } else { | |
| // Not a header, commit header window data to current frame and reset. | |
| frame_data.extend(&header_window); | |
| if header_window.len() > 1 { | |
| header_iter = self.pattern.iter().peekable(); | |
| } | |
| header_window.clear(); | |
| } | |
| } | |
| } | |
| } |