#![allow(
clippy::redundant_pub_crate,
reason = "workspace `unreachable_pub` policy (Cargo.toml) wants `pub(crate)` here; \
clippy::pedantic's redundant_pub_crate disagrees for private modules — the \
two lints are mutually exclusive for this shape, workspace policy wins"
)]
use super::h264_gop::WORKSPACE_DPB_CAP;
pub(crate) const LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4: u8 = 12;
#[derive(Debug, Clone, Copy)]
pub(crate) struct DpbSlot {
pub(crate) poc: i32,
pub(crate) 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(crate) enum FrameRequest {
Auto,
ForceIdr,
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct FrameDecision {
pub(crate) is_idr: bool,
pub(crate) poc: i32,
pub(crate) setup_slot: usize,
pub(crate) reference: Option<(usize, DpbSlot)>,
}
#[derive(Debug)]
pub(crate) struct GopState {
gop_size: u32,
frames_since_idr: u32,
poc: i32,
dpb: Dpb,
last_written: Option<usize>,
}
impl GopState {
pub(crate) fn new(gop_size: u32) -> Self {
Self {
gop_size,
frames_since_idr: 0,
poc: 0,
dpb: Dpb::default(),
last_written: None,
}
}
pub(crate) 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
}
}