use std::io::Write;
use super::{Error, LessEncoder, Result, YCbCrImage};
enum WriteState<W> {
Configured(W),
Recording(RecordingState<W>),
MovedOut,
}
impl<W: Write> WriteState<W> {
fn write_frame(&mut self, frame: &YCbCrImage) -> Result<()> {
let orig_state = std::mem::replace(self, WriteState::MovedOut);
let state = match orig_state {
WriteState::Configured(fd) => {
let (initial_nal_data, encoder) = LessEncoder::new(frame)?;
let mut state = RecordingState { wtr: fd, encoder };
state
.wtr
.write_all(&initial_nal_data.sps.to_annex_b_data())?;
state
.wtr
.write_all(&initial_nal_data.pps.to_annex_b_data())?;
state
.wtr
.write_all(&initial_nal_data.frame.to_annex_b_data())?;
state
}
WriteState::Recording(mut state) => {
let encoded = state.encoder.encode(frame)?;
state.wtr.write_all(&encoded.to_annex_b_data())?;
state
}
WriteState::MovedOut => {
return Err(Error::InconsistentState {
#[cfg(feature = "backtrace")]
backtrace: std::backtrace::Backtrace::capture(),
})
}
};
*self = WriteState::Recording(state);
Ok(())
}
}
struct RecordingState<W> {
wtr: W,
encoder: LessEncoder,
}
pub struct H264Writer<W> {
inner: WriteState<W>,
}
impl<W: Write> H264Writer<W> {
pub fn new(wtr: W) -> Result<Self> {
Ok(Self {
inner: WriteState::Configured(wtr),
})
}
pub fn into_inner(self) -> W {
match self.inner {
WriteState::Configured(w) => w,
WriteState::Recording(state) => state.wtr,
WriteState::MovedOut => {
unreachable!("inconsistent internal state");
}
}
}
pub fn write(&mut self, frame: &YCbCrImage) -> Result<()> {
self.inner.write_frame(frame)
}
}