| 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(); |
| } |
| } |
| } |
| } |