use crate::picture::Picture;
use std::collections::HashMap;
pub trait RefPicProvider {
fn ref_pic(&self, list: u8, idx: u32) -> Option<&Picture>;
fn ref_pic_poc(&self, list: u8, idx: u32) -> Option<i32> {
self.ref_pic(list, idx).map(|p| p.pic_order_cnt)
}
fn ref_list_0_pocs(&self) -> &[i32] {
&[]
}
fn ref_list_0_longterm(&self) -> &[bool] {
&[]
}
fn ref_list_1_longterm(&self) -> &[bool] {
&[]
}
fn ref_field_parity(&self, _list: u8, _idx: u32) -> Option<u8> {
None
}
fn ref_list_0_keys(&self) -> &[u32] {
&[]
}
fn ref_list_0_unit_keys(&self) -> &[u32] {
&[]
}
fn ref_list_0_parities(&self) -> &[Option<u8>] {
&[]
}
fn ref_entry_identity(&self, _list: u8, _idx: u32) -> Option<(u32, Option<u8>, u32)> {
None
}
fn ref_entry_unit_focs(&self, _list: u8, _idx: u32) -> Option<(i32, i32)> {
None
}
fn ref_pair_field(&self, _list: u8, _idx: u32, _bottom: bool) -> Option<&Picture> {
None
}
}
pub struct RefPicStore {
pictures: HashMap<u32, Picture>,
ref_pic_list_0: Vec<u32>,
ref_pic_list_1: Vec<u32>,
}
impl Default for RefPicStore {
fn default() -> Self {
Self::new()
}
}
impl RefPicStore {
pub fn new() -> Self {
Self {
pictures: HashMap::new(),
ref_pic_list_0: Vec::new(),
ref_pic_list_1: Vec::new(),
}
}
pub fn insert(&mut self, key: u32, pic: Picture) {
self.pictures.insert(key, pic);
}
pub fn retain_keys(&mut self, live: &[u32]) {
self.pictures.retain(|k, _| live.contains(k));
}
pub fn stored_count(&self) -> usize {
self.pictures.len()
}
pub fn set_list_0(&mut self, keys: Vec<u32>) {
self.ref_pic_list_0 = keys;
}
pub fn set_list_1(&mut self, keys: Vec<u32>) {
self.ref_pic_list_1 = keys;
}
pub fn get_by_key(&self, key: u32) -> Option<&Picture> {
self.pictures.get(&key)
}
}
impl RefPicProvider for RefPicStore {
fn ref_pic(&self, list: u8, idx: u32) -> Option<&Picture> {
let keys = match list {
0 => &self.ref_pic_list_0,
1 => &self.ref_pic_list_1,
_ => return None,
};
let key = keys.get(idx as usize).copied()?;
self.get_by_key(key)
}
}
pub struct NoRefs;
impl RefPicProvider for NoRefs {
fn ref_pic(&self, _list: u8, _idx: u32) -> Option<&Picture> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
fn pic(w: u32, fill: i32) -> Picture {
let mut p = Picture::new(w, w, 1, 8, 8);
for v in p.luma.iter_mut() {
*v = fill;
}
p
}
#[test]
fn store_insert_and_get_by_key() {
let mut s = RefPicStore::new();
s.insert(0, pic(16, 10));
s.insert(3, pic(16, 40));
assert!(s.get_by_key(0).is_some());
assert!(s.get_by_key(1).is_none());
assert!(s.get_by_key(2).is_none());
assert!(s.get_by_key(3).is_some());
assert!(s.get_by_key(4).is_none());
}
#[test]
fn store_list0_lookup() {
let mut s = RefPicStore::new();
s.insert(5, pic(16, 42));
s.insert(7, pic(16, 99));
s.set_list_0(vec![5, 7]);
assert_eq!(s.ref_pic(0, 0).unwrap().luma[0], 42);
assert_eq!(s.ref_pic(0, 1).unwrap().luma[0], 99);
assert!(s.ref_pic(0, 2).is_none());
assert!(s.ref_pic(1, 0).is_none());
}
#[test]
fn store_list1_lookup_after_set() {
let mut s = RefPicStore::new();
s.insert(0, pic(16, 1));
s.set_list_1(vec![0]);
assert_eq!(s.ref_pic(1, 0).unwrap().luma[0], 1);
}
#[test]
fn store_retain_keys_prunes_dead_pictures() {
let mut s = RefPicStore::new();
for k in 0..10 {
s.insert(k, pic(16, k as i32));
}
assert_eq!(s.stored_count(), 10);
s.retain_keys(&[3, 7]);
assert_eq!(s.stored_count(), 2);
assert!(s.get_by_key(3).is_some());
assert!(s.get_by_key(7).is_some());
assert!(s.get_by_key(0).is_none());
assert!(s.get_by_key(9).is_none());
s.retain_keys(&[]);
assert_eq!(s.stored_count(), 0);
}
#[test]
fn store_unknown_list_returns_none() {
let s = RefPicStore::new();
assert!(s.ref_pic(2, 0).is_none());
}
#[test]
fn no_refs_always_none() {
let nr = NoRefs;
assert!(nr.ref_pic(0, 0).is_none());
assert!(nr.ref_pic(1, 0).is_none());
assert!(nr.ref_pic(5, 99).is_none());
}
}