#![forbid(unsafe_code)]
use super::gop::WORKSPACE_DPB_CAP;
#[derive(Debug, Clone, Copy)]
pub(super) struct DpbSlot {
pub(super) poc: i32,
#[allow(
dead_code,
reason = "verbatim-ported field (vulkan/hevc_gop.rs); this crate's own reference-list \
construction (hevc.rs::reference_picture_hevc) needs only `poc` — kept for \
parity with the porting source's shape, mirrors gop.rs::DpbSlot::is_idr's \
identical disposition"
)]
pub(super) is_idr: bool,
}
#[derive(Debug, Clone, Copy)]
struct Dpb {
slots: [Option<DpbSlot>; WORKSPACE_DPB_CAP],
next_slot: usize,
}
impl Default for Dpb {
fn default() -> Self {
Self {
slots: [None; WORKSPACE_DPB_CAP],
next_slot: 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(
dead_code,
reason = "ForceIdr is a documented hook, not wired by any caller yet"
)]
pub(super) enum FrameRequest {
Auto,
ForceIdr,
}
#[derive(Debug, Clone, Copy)]
pub(super) struct FrameDecision {
pub(super) is_idr: bool,
pub(super) poc: i32,
pub(super) setup_slot: usize,
pub(super) reference: Option<(usize, DpbSlot)>,
}
#[derive(Debug)]
pub(super) struct GopState {
gop_size: u32,
frames_since_idr: u32,
poc: i32,
dpb: Dpb,
last_written: Option<usize>,
}
impl GopState {
pub(super) fn new(gop_size: u32) -> Self {
Self {
gop_size,
frames_since_idr: 0,
poc: 0,
dpb: Dpb::default(),
last_written: None,
}
}
pub(super) fn decide(&mut self, request: FrameRequest) -> FrameDecision {
let is_idr = matches!(request, FrameRequest::ForceIdr)
|| self.frames_since_idr == 0
|| self.frames_since_idr >= self.gop_size;
if is_idr {
self.poc = 0;
self.frames_since_idr = 0;
self.dpb = Dpb::default();
self.last_written = None;
}
let setup_slot = self.dpb.next_slot;
let reference = if is_idr {
None
} else {
self.last_written
.and_then(|slot| self.dpb.slots[slot].map(|dpb_slot| (slot, dpb_slot)))
};
let poc = self.poc;
let decision = FrameDecision {
is_idr,
poc,
setup_slot,
reference,
};
self.dpb.slots[setup_slot] = Some(DpbSlot { poc, is_idr });
self.dpb.next_slot = (setup_slot + 1) % WORKSPACE_DPB_CAP;
self.last_written = Some(setup_slot);
self.poc += 1;
self.frames_since_idr += 1;
decision
}
}
#[cfg(test)]
#[path = "hevc_gop_tests.rs"]
mod tests;