#![allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RefFrameType {
ShortTerm,
LongTerm,
}
impl RefFrameType {
pub fn is_long_term(self) -> bool {
self == Self::LongTerm
}
pub fn is_short_term(self) -> bool {
self == Self::ShortTerm
}
}
#[derive(Debug, Clone)]
pub struct RefFrame {
pub poc: i32,
pub frame_num: u32,
pub ref_type: RefFrameType,
pub in_use: bool,
pub buffer_index: usize,
}
impl RefFrame {
pub fn short_term(poc: i32, frame_num: u32, buffer_index: usize) -> Self {
Self {
poc,
frame_num,
ref_type: RefFrameType::ShortTerm,
in_use: true,
buffer_index,
}
}
pub fn long_term(poc: i32, long_term_frame_idx: u32, buffer_index: usize) -> Self {
Self {
poc,
frame_num: long_term_frame_idx,
ref_type: RefFrameType::LongTerm,
in_use: true,
buffer_index,
}
}
pub fn is_valid(&self) -> bool {
self.in_use
}
pub fn mark_unused(&mut self) {
self.in_use = false;
}
}
#[derive(Debug)]
pub struct RefFrameList {
frames: Vec<RefFrame>,
max_size: usize,
}
impl RefFrameList {
pub fn new(max_size: usize) -> Self {
Self {
frames: Vec::with_capacity(max_size),
max_size,
}
}
pub fn add(&mut self, frame: RefFrame) -> bool {
if self.frames.len() < self.max_size {
self.frames.push(frame);
return true;
}
if self.remove_oldest() {
self.frames.push(frame);
true
} else {
false
}
}
pub fn remove_oldest(&mut self) -> bool {
let pos = self
.frames
.iter()
.enumerate()
.filter(|(_, f)| f.ref_type == RefFrameType::ShortTerm && f.in_use)
.min_by_key(|(_, f)| f.frame_num)
.map(|(i, _)| i);
if let Some(idx) = pos {
self.frames.remove(idx);
true
} else {
false
}
}
pub fn find_closest_poc(&self, target_poc: i32) -> Option<&RefFrame> {
self.frames
.iter()
.filter(|f| f.in_use)
.min_by_key(|f| (f.poc - target_poc).unsigned_abs())
}
pub fn len(&self) -> usize {
self.frames.iter().filter(|f| f.in_use).count()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn iter(&self) -> impl Iterator<Item = &RefFrame> {
self.frames.iter().filter(|f| f.in_use)
}
pub fn long_term_count(&self) -> usize {
self.frames
.iter()
.filter(|f| f.in_use && f.ref_type == RefFrameType::LongTerm)
.count()
}
pub fn short_term_count(&self) -> usize {
self.frames
.iter()
.filter(|f| f.in_use && f.ref_type == RefFrameType::ShortTerm)
.count()
}
pub fn clear(&mut self) {
self.frames.clear();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ref_frame_type_is_long_term() {
assert!(RefFrameType::LongTerm.is_long_term());
assert!(!RefFrameType::ShortTerm.is_long_term());
}
#[test]
fn test_ref_frame_type_is_short_term() {
assert!(RefFrameType::ShortTerm.is_short_term());
assert!(!RefFrameType::LongTerm.is_short_term());
}
#[test]
fn test_ref_frame_short_term_constructor() {
let f = RefFrame::short_term(10, 3, 0);
assert_eq!(f.poc, 10);
assert_eq!(f.frame_num, 3);
assert!(f.is_valid());
assert_eq!(f.ref_type, RefFrameType::ShortTerm);
}
#[test]
fn test_ref_frame_long_term_constructor() {
let f = RefFrame::long_term(20, 1, 5);
assert_eq!(f.ref_type, RefFrameType::LongTerm);
assert_eq!(f.frame_num, 1);
assert!(f.is_valid());
}
#[test]
fn test_ref_frame_mark_unused() {
let mut f = RefFrame::short_term(0, 0, 0);
f.mark_unused();
assert!(!f.is_valid());
}
#[test]
fn test_ref_frame_list_add_within_capacity() {
let mut list = RefFrameList::new(4);
assert!(list.add(RefFrame::short_term(0, 0, 0)));
assert_eq!(list.len(), 1);
}
#[test]
fn test_ref_frame_list_is_empty_initially() {
let list = RefFrameList::new(4);
assert!(list.is_empty());
}
#[test]
fn test_ref_frame_list_remove_oldest_evicts_min_frame_num() {
let mut list = RefFrameList::new(10);
list.add(RefFrame::short_term(4, 4, 0));
list.add(RefFrame::short_term(2, 2, 1));
list.add(RefFrame::short_term(6, 6, 2));
assert!(list.remove_oldest());
assert_eq!(list.len(), 2);
assert!(list.iter().all(|f| f.frame_num != 2));
}
#[test]
fn test_ref_frame_list_add_evicts_oldest_when_full() {
let mut list = RefFrameList::new(2);
list.add(RefFrame::short_term(0, 0, 0));
list.add(RefFrame::short_term(2, 2, 1));
let ok = list.add(RefFrame::short_term(4, 4, 2));
assert!(ok);
assert_eq!(list.len(), 2);
}
#[test]
fn test_ref_frame_list_find_closest_poc() {
let mut list = RefFrameList::new(4);
list.add(RefFrame::short_term(0, 0, 0));
list.add(RefFrame::short_term(10, 1, 1));
list.add(RefFrame::short_term(20, 2, 2));
let closest = list.find_closest_poc(12).expect("should succeed");
assert_eq!(closest.poc, 10);
}
#[test]
fn test_ref_frame_list_find_closest_poc_empty_returns_none() {
let list = RefFrameList::new(4);
assert!(list.find_closest_poc(0).is_none());
}
#[test]
fn test_ref_frame_list_long_term_count() {
let mut list = RefFrameList::new(4);
list.add(RefFrame::short_term(0, 0, 0));
list.add(RefFrame::long_term(10, 0, 1));
assert_eq!(list.long_term_count(), 1);
assert_eq!(list.short_term_count(), 1);
}
#[test]
fn test_ref_frame_list_clear() {
let mut list = RefFrameList::new(4);
list.add(RefFrame::short_term(0, 0, 0));
list.add(RefFrame::short_term(2, 1, 1));
list.clear();
assert!(list.is_empty());
}
#[test]
fn test_ref_frame_list_iter_only_active() {
let mut list = RefFrameList::new(4);
let mut f = RefFrame::short_term(0, 0, 0);
f.mark_unused();
list.frames.push(f);
list.add(RefFrame::short_term(2, 1, 1));
assert_eq!(list.iter().count(), 1);
}
}