#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct FrameDecision {
pub(super) is_idr: bool,
pub(super) poc: u32,
pub(super) intra_refresh_frame_index: Option<u32>,
}
#[derive(Debug, Clone, Copy)]
pub(super) struct HevcGopState {
gop_size: u32,
intra_refresh_period: u32,
started: bool,
frame_index_in_gop: u32,
poc: u32,
intra_refresh_frame_index: u32,
}
impl HevcGopState {
pub(super) const fn new(gop_size: u32) -> Self {
Self {
gop_size,
intra_refresh_period: 0,
started: false,
frame_index_in_gop: 0,
poc: 0,
intra_refresh_frame_index: 0,
}
}
pub(super) const fn new_intra_refresh(period: u32) -> Self {
Self {
gop_size: 0,
intra_refresh_period: period,
started: false,
frame_index_in_gop: 0,
poc: 0,
intra_refresh_frame_index: 0,
}
}
pub(super) fn decide(&mut self) -> FrameDecision {
let is_idr = if self.intra_refresh_period > 0 {
!self.started
} else {
self.gop_size <= 1 || self.frame_index_in_gop == 0
};
self.started = true;
self.poc = if is_idr { 0 } else { self.poc.wrapping_add(1) };
let intra_refresh_frame_index = (self.intra_refresh_period > 0 && !is_idr).then(|| {
let index = self.intra_refresh_frame_index;
self.intra_refresh_frame_index = (index + 1) % self.intra_refresh_period;
index
});
let decision = FrameDecision {
is_idr,
poc: self.poc,
intra_refresh_frame_index,
};
self.frame_index_in_gop = (self.frame_index_in_gop + 1) % self.gop_size.max(1);
decision
}
}
#[cfg(test)]
#[path = "gop_hevc_tests.rs"]
mod tests;