use std::io::Write;
use std::path::Path;
use nc_common::{Picture, PlaneIndex, yuv};
use nc_dsp::Dsp;
use crate::stdio;
pub(crate) struct SseLog {
reference: stdio::Input,
frame: Option<Picture>,
out: stdio::Output,
dsp: Dsp,
}
impl SseLog {
pub(crate) fn create(reference: &Path, log: &Path) -> Result<Self, String> {
let reference = stdio::open_raw(reference)?;
let mut out = stdio::create(log)?;
writeln!(out, "frame,sse_y,sse_u,sse_v").map_err(|e| e.to_string())?;
Ok(Self {
reference,
frame: None,
out,
dsp: Dsp::new(),
})
}
pub(crate) fn write(&mut self, index: u32, shown: &Picture) -> Result<(), String> {
let size = (shown.width(), shown.height());
if self
.frame
.as_ref()
.is_none_or(|f| (f.width(), f.height()) != size)
{
self.frame = Some(Picture::new(size.0, size.1, 0).map_err(|e| e.to_string())?);
}
let frame = self.frame.as_mut().expect("allocated above");
if !yuv::read_frame(&mut self.reference, frame).map_err(|e| e.to_string())? {
return Err(format!("--sse-reference ended before frame {index}"));
}
let [y, u, v] = PlaneIndex::ALL.map(|plane| {
self.dsp
.sse(&frame.plane(plane).view(), &shown.plane(plane).view())
});
writeln!(self.out, "{index},{y},{u},{v}").map_err(|e| e.to_string())
}
pub(crate) fn finish(mut self) -> Result<(), String> {
self.out.flush().map_err(|e| e.to_string())
}
}