use std::hash::{Hash, Hasher};
use visual_cortex_capture::FrameView;
use crate::detector::{Detector, DetectorError, DetectorOutput};
#[derive(Default)]
pub struct FrameDiff {
last_hash: Option<u64>,
}
impl FrameDiff {
pub fn new() -> Self {
Self::default()
}
}
impl Detector for FrameDiff {
fn evaluate(&mut self, view: &FrameView<'_>) -> Result<DetectorOutput, DetectorError> {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
for row in view.rows() {
row.hash(&mut hasher);
}
let hash = hasher.finish();
let changed = self.last_hash != Some(hash);
self.last_hash = Some(hash);
Ok(DetectorOutput::Bool(changed))
}
}
#[cfg(test)]
mod tests {
use super::*;
use visual_cortex_capture::{Frame, PxRect};
fn full_view(frame: &Frame) -> FrameView<'_> {
frame
.view(PxRect {
x: 0,
y: 0,
w: frame.width(),
h: frame.height(),
})
.unwrap()
}
#[test]
fn first_evaluation_reports_changed() {
let f = Frame::solid(4, 4, [0, 0, 0, 255]);
let mut gate = FrameDiff::new();
assert_eq!(
gate.evaluate(&full_view(&f)).unwrap(),
DetectorOutput::Bool(true)
);
}
#[test]
fn identical_pixels_report_unchanged() {
let a = Frame::solid(4, 4, [9, 9, 9, 255]);
let b = Frame::solid(4, 4, [9, 9, 9, 255]); let mut gate = FrameDiff::new();
gate.evaluate(&full_view(&a)).unwrap();
assert_eq!(
gate.evaluate(&full_view(&b)).unwrap(),
DetectorOutput::Bool(false)
);
}
#[test]
fn different_pixels_report_changed() {
let a = Frame::solid(4, 4, [0, 0, 0, 255]);
let b = Frame::solid(4, 4, [255, 0, 0, 255]);
let mut gate = FrameDiff::new();
gate.evaluate(&full_view(&a)).unwrap();
assert_eq!(
gate.evaluate(&full_view(&b)).unwrap(),
DetectorOutput::Bool(true)
);
}
}