pub const POC_LOG2_MAX_LSB_MINUS4: u8 = 4;
pub const POC_MAX_LSB: u32 = 1u32 << (POC_LOG2_MAX_LSB_MINUS4 as u32 + 4);
#[derive(Debug, Clone, Copy)]
pub struct PocTracker {
idr_display_index: u32,
}
impl PocTracker {
pub fn new() -> Self {
Self {
idr_display_index: 0,
}
}
pub fn reset_at_idr(&mut self, display_index: u32) {
self.idr_display_index = display_index;
}
pub fn poc_lsb_for(&self, display_index: u32) -> u32 {
let full_poc =
2u32.wrapping_mul(display_index.wrapping_sub(self.idr_display_index));
full_poc & (POC_MAX_LSB - 1)
}
pub fn full_poc_for(&self, display_index: u32) -> u32 {
2u32.wrapping_mul(display_index.wrapping_sub(self.idr_display_index))
}
}
impl Default for PocTracker {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn idr_poc_is_zero() {
let mut t = PocTracker::new();
t.reset_at_idr(0);
assert_eq!(t.poc_lsb_for(0), 0);
assert_eq!(t.full_poc_for(0), 0);
}
#[test]
fn step_of_two_per_display_frame() {
let mut t = PocTracker::new();
t.reset_at_idr(0);
assert_eq!(t.poc_lsb_for(1), 2);
assert_eq!(t.poc_lsb_for(2), 4);
assert_eq!(t.poc_lsb_for(3), 6);
assert_eq!(t.poc_lsb_for(10), 20);
}
#[test]
fn idr_anchor_offsets_correctly() {
let mut t = PocTracker::new();
t.reset_at_idr(0);
assert_eq!(t.poc_lsb_for(5), 10);
t.reset_at_idr(30);
assert_eq!(t.poc_lsb_for(30), 0); assert_eq!(t.poc_lsb_for(31), 2);
assert_eq!(t.poc_lsb_for(35), 10);
}
#[test]
fn lsb_wraps_at_max() {
let mut t = PocTracker::new();
t.reset_at_idr(0);
assert_eq!(t.poc_lsb_for(128), 0);
assert_eq!(t.poc_lsb_for(129), 2);
assert_eq!(t.full_poc_for(128), 256);
assert_eq!(t.full_poc_for(200), 400);
}
#[test]
fn poc_max_lsb_constant_matches_spec() {
assert_eq!(POC_MAX_LSB, 256);
}
}