use crate::Pixel;
#[derive(Clone)]
pub struct RefFrame<T: Pixel> {
pub planes: std::sync::Arc<Vec<Vec<T>>>, pub width: usize,
pub height: usize,
pub strides: Vec<usize>,
pub order_hint: u64,
}
pub struct Dpb<T: Pixel> {
slots: [Option<RefFrame<T>>; 3],
last_slot: usize,
next_refresh_slot: usize,
}
impl<T: Pixel> Default for Dpb<T> {
fn default() -> Self {
Self {
slots: [None, None, None],
last_slot: 0,
next_refresh_slot: 0,
}
}
}
impl<T: Pixel> Dpb<T> {
pub fn last(&self) -> Option<&RefFrame<T>> {
self.slots[self.last_slot].as_ref()
}
pub fn slot(&self, slot: usize) -> Option<&RefFrame<T>> {
self.slots.get(slot).and_then(Option::as_ref)
}
pub fn populated_slots(&self, limit: usize) -> impl Iterator<Item = usize> + '_ {
let mut slots = [0usize, 1, 2];
slots.sort_by_key(|&slot| {
std::cmp::Reverse(self.slots[slot].as_ref().map(|frame| frame.order_hint))
});
slots
.into_iter()
.filter(|&slot| self.slots[slot].is_some())
.take(limit.min(self.slots.len()))
}
pub fn next_refresh_slot(&self) -> usize {
self.next_refresh_slot
}
pub fn latest_slot(&self) -> usize {
self.last_slot
}
pub fn reset_with_key(&mut self, frame: RefFrame<T>) {
self.slots = [Some(frame), None, None];
self.last_slot = 0;
self.next_refresh_slot = 1;
}
pub fn refresh_slot(&mut self, slot: usize, frame: RefFrame<T>) {
debug_assert!(slot < self.slots.len());
self.slots[slot] = Some(frame);
self.last_slot = slot;
self.next_refresh_slot = (slot + 1) % self.slots.len();
}
pub fn is_empty(&self) -> bool {
self.slots.iter().all(Option::is_none)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn frame(order_hint: u64) -> RefFrame<f32> {
RefFrame {
planes: std::sync::Arc::new(vec![vec![order_hint as f32]]),
width: 1,
height: 1,
strides: vec![1],
order_hint,
}
}
#[test]
fn rotating_slots_are_returned_in_recency_order() {
let mut dpb = Dpb::default();
dpb.reset_with_key(frame(0));
assert_eq!(dpb.populated_slots(3).collect::<Vec<_>>(), [0]);
assert_eq!(dpb.next_refresh_slot(), 1);
dpb.refresh_slot(1, frame(1));
dpb.refresh_slot(2, frame(2));
assert_eq!(dpb.populated_slots(3).collect::<Vec<_>>(), [2, 1, 0]);
assert_eq!(dpb.populated_slots(2).collect::<Vec<_>>(), [2, 1]);
dpb.refresh_slot(0, frame(3));
assert_eq!(dpb.populated_slots(3).collect::<Vec<_>>(), [0, 2, 1]);
assert_eq!(dpb.next_refresh_slot(), 1);
}
}