#![allow(dead_code)]
#[derive(Debug, Clone)]
pub struct OutputEntry<P> {
pub picture: P,
pub pic_order_cnt: i32,
pub frame_num: u32,
pub needed_for_output: bool,
}
pub struct DpbOutput<P> {
pub max_num_reorder_frames: u32,
pub max_dec_frame_buffering: u32,
entries: Vec<OutputEntry<P>>,
}
impl<P> DpbOutput<P> {
pub fn new(max_num_reorder_frames: u32, max_dec_frame_buffering: u32) -> Self {
Self {
max_num_reorder_frames,
max_dec_frame_buffering,
entries: Vec::new(),
}
}
pub fn push(&mut self, mut entry: OutputEntry<P>) -> Option<OutputEntry<P>> {
entry.needed_for_output = true;
let bumped = if self.entries.len() as u32 >= self.max_num_reorder_frames {
self.bump_lowest()
} else {
None
};
self.entries.push(entry);
bumped
}
pub fn pop_ready(&mut self) -> Option<OutputEntry<P>> {
if (self.entries.len() as u32) > self.max_num_reorder_frames {
self.bump_lowest()
} else {
None
}
}
pub fn flush(&mut self) -> Vec<OutputEntry<P>> {
self.entries.sort_by(|a, b| {
a.pic_order_cnt
.cmp(&b.pic_order_cnt)
.then(a.frame_num.cmp(&b.frame_num))
});
let mut out = std::mem::take(&mut self.entries);
for e in out.iter_mut() {
e.needed_for_output = false;
}
out
}
pub fn reset(&mut self) -> Vec<OutputEntry<P>> {
self.flush()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
fn bump_lowest(&mut self) -> Option<OutputEntry<P>> {
if self.entries.is_empty() {
return None;
}
let mut min_idx = 0usize;
for i in 1..self.entries.len() {
let a = &self.entries[i];
let b = &self.entries[min_idx];
if a.pic_order_cnt < b.pic_order_cnt
|| (a.pic_order_cnt == b.pic_order_cnt && a.frame_num < b.frame_num)
{
min_idx = i;
}
}
let mut e = self.entries.remove(min_idx);
e.needed_for_output = false;
Some(e)
}
}
#[cfg(test)]
mod tests {
use super::*;
type TestPic = u32;
fn mk(poc: i32, fnum: u32) -> OutputEntry<TestPic> {
OutputEntry {
picture: fnum,
pic_order_cnt: poc,
frame_num: fnum,
needed_for_output: false,
}
}
#[test]
fn empty_queue_yields_nothing() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(2, 4);
assert!(d.is_empty());
assert_eq!(d.len(), 0);
assert!(d.pop_ready().is_none());
assert!(d.flush().is_empty());
}
#[test]
fn push_below_capacity_returns_none() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(3, 4);
assert!(d.push(mk(0, 0)).is_none());
assert!(d.push(mk(2, 1)).is_none());
assert_eq!(d.len(), 2);
assert!(d.pop_ready().is_none());
}
#[test]
fn push_at_capacity_triggers_bump() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(2, 4);
assert!(d.push(mk(4, 0)).is_none());
assert!(d.push(mk(1, 1)).is_none());
let bumped = d.push(mk(7, 2)).expect("bump expected on overflow");
assert_eq!(bumped.pic_order_cnt, 1);
assert_eq!(bumped.frame_num, 1);
assert!(!bumped.needed_for_output);
assert_eq!(d.len(), 2);
}
#[test]
fn push_sets_needed_for_output_flag() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(4, 4);
d.push(mk(0, 0));
let drained = d.flush();
assert_eq!(drained.len(), 1);
assert!(!drained[0].needed_for_output);
}
#[test]
fn flush_drains_in_poc_order() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(8, 8);
d.push(mk(8, 0));
d.push(mk(2, 1));
d.push(mk(5, 2));
let out = d.flush();
let pocs: Vec<i32> = out.iter().map(|e| e.pic_order_cnt).collect();
assert_eq!(pocs, vec![2, 5, 8]);
assert!(d.is_empty());
}
#[test]
fn poc_tie_broken_by_frame_num() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(8, 8);
d.push(mk(10, 2));
d.push(mk(10, 1));
let out = d.flush();
assert_eq!(out[0].frame_num, 1);
assert_eq!(out[1].frame_num, 2);
}
#[test]
fn reset_clears_all() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(4, 4);
d.push(mk(0, 0));
d.push(mk(1, 1));
let drained = d.reset();
assert_eq!(drained.len(), 2);
assert_eq!(d.len(), 0);
assert!(d.is_empty());
assert!(d.flush().is_empty());
}
#[test]
fn idr_mmco5_scenario_leaves_queue_empty() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(3, 4);
d.push(mk(0, 0));
d.push(mk(4, 1));
d.push(mk(2, 2));
let _pre_mmco5 = d.reset();
assert!(d.push(mk(0, 0)).is_none());
assert_eq!(d.len(), 1);
let final_batch = d.flush();
assert_eq!(final_batch.len(), 1);
assert_eq!(final_batch[0].pic_order_cnt, 0);
}
#[test]
fn bump_cascade_preserves_remaining_poc_order() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(2, 4);
assert!(d.push(mk(3, 0)).is_none());
assert!(d.push(mk(1, 1)).is_none());
let b1 = d.push(mk(5, 2)).unwrap();
assert_eq!(b1.pic_order_cnt, 1);
let b2 = d.push(mk(2, 3)).unwrap();
assert_eq!(b2.pic_order_cnt, 3);
let rest = d.flush();
let pocs: Vec<i32> = rest.iter().map(|e| e.pic_order_cnt).collect();
assert_eq!(pocs, vec![2, 5]);
}
#[test]
fn pop_ready_only_emits_over_capacity() {
let mut d: DpbOutput<TestPic> = DpbOutput::new(2, 4);
d.push(mk(7, 0));
d.push(mk(3, 1));
assert!(d.pop_ready().is_none());
assert_eq!(d.len(), 2);
}
}