use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;
use crate::{Crop, Grade};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Image {
pub width: u32,
pub height: u32,
pub data: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LayerSource {
Video { input: PathBuf, start: Duration },
Image(Arc<Image>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Layer {
pub source: LayerSource,
pub grade: Grade,
pub from: i64,
pub to: i64,
pub rects: Vec<Crop>,
}
impl Layer {
pub fn rect_at(&self, frame: i64, width: u32, height: u32) -> Option<Crop> {
if frame < self.from || frame >= self.to {
return None;
}
let i = usize::try_from(frame - self.from).unwrap_or(0);
#[allow(clippy::cast_precision_loss)]
Some(
self.rects
.get(i)
.or(self.rects.last())
.copied()
.unwrap_or(Crop {
x: 0.0,
y: 0.0,
width: width as f32,
height: height as f32,
}),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rect_holds_and_ranges() {
let r = |x| Crop {
x,
y: 0.0,
width: 10.0,
height: 10.0,
};
let l = Layer {
source: LayerSource::Image(Arc::new(Image {
width: 1,
height: 1,
data: vec![0; 4],
})),
grade: Grade::default(),
from: 5,
to: 10,
rects: vec![r(0.0), r(1.0)],
};
assert_eq!(l.rect_at(4, 100, 50), None);
assert_eq!(l.rect_at(5, 100, 50), Some(r(0.0)));
assert_eq!(l.rect_at(9, 100, 50), Some(r(1.0)));
assert_eq!(l.rect_at(10, 100, 50), None);
let full = Layer {
rects: Vec::new(),
..l
};
assert_eq!(full.rect_at(5, 100, 50).map(|c| c.width), Some(100.0));
}
}