use crate::bitreader::BitReader;
use crate::error::DecodeError;
fn e(s: &'static str) -> DecodeError {
DecodeError::Bitstream(s.into())
}
#[derive(Clone, Default, Debug)]
pub(crate) struct ShortTermRps {
pub(crate) delta_poc_s0: Vec<i32>,
pub(crate) used_s0: Vec<bool>,
pub(crate) delta_poc_s1: Vec<i32>,
pub(crate) used_s1: Vec<bool>,
}
impl ShortTermRps {
#[inline]
pub(crate) fn num_negative(&self) -> usize {
self.delta_poc_s0.len()
}
#[inline]
pub(crate) fn num_positive(&self) -> usize {
self.delta_poc_s1.len()
}
#[inline]
pub(crate) fn num_delta_pocs(&self) -> usize {
self.num_negative() + self.num_positive()
}
}
pub(crate) fn parse_short_term_rps(
r: &mut BitReader,
idx: usize,
num_sets: usize,
sets: &[ShortTermRps],
) -> Result<ShortTermRps, DecodeError> {
let inter_pred = if idx != 0 {
r.read_flag().map_err(|_| e("inter_ref_pic_set_pred"))?
} else {
false
};
if inter_pred {
let delta_idx = if idx == num_sets {
r.read_ue().map_err(|_| e("delta_idx_minus1"))? as usize + 1
} else {
1
};
let ref_rps_idx = idx
.checked_sub(delta_idx)
.ok_or_else(|| e("delta_idx out of range"))?;
let src = sets.get(ref_rps_idx).ok_or_else(|| e("ref rps missing"))?;
let delta_rps_sign = r.read_bit().map_err(|_| e("delta_rps_sign"))?;
let abs_delta_rps = r.read_ue().map_err(|_| e("abs_delta_rps_minus1"))? as i32 + 1;
let delta_rps = if delta_rps_sign != 0 {
-abs_delta_rps
} else {
abs_delta_rps
};
let n = src.num_delta_pocs();
let mut used = vec![false; n + 1];
let mut use_delta = vec![true; n + 1];
for j in 0..=n {
let u = r.read_flag().map_err(|_| e("used_by_curr_pic_flag"))?;
used[j] = u;
if !u {
use_delta[j] = r.read_flag().map_err(|_| e("use_delta_flag"))?;
}
}
Ok(derive_inter_rps(src, delta_rps, &used, &use_delta))
} else {
let num_neg = r.read_ue().map_err(|_| e("num_negative_pics"))? as usize;
let num_pos = r.read_ue().map_err(|_| e("num_positive_pics"))? as usize;
let mut out = ShortTermRps::default();
let mut prev = 0i32;
for _ in 0..num_neg {
let d = r.read_ue().map_err(|_| e("delta_poc_s0_minus1"))? as i32 + 1;
prev -= d;
out.delta_poc_s0.push(prev);
out.used_s0
.push(r.read_flag().map_err(|_| e("used_by_curr_s0"))?);
}
prev = 0;
for _ in 0..num_pos {
let d = r.read_ue().map_err(|_| e("delta_poc_s1_minus1"))? as i32 + 1;
prev += d;
out.delta_poc_s1.push(prev);
out.used_s1
.push(r.read_flag().map_err(|_| e("used_by_curr_s1"))?);
}
Ok(out)
}
}
fn derive_inter_rps(
src: &ShortTermRps,
delta_rps: i32,
used: &[bool],
use_delta: &[bool],
) -> ShortTermRps {
let mut out = ShortTermRps::default();
let n_neg = src.num_negative();
let n_pos = src.num_positive();
let total = src.num_delta_pocs();
for j in (0..n_pos).rev() {
let dpoc = src.delta_poc_s1[j] + delta_rps;
let idx = n_neg + j; if dpoc < 0 && use_delta.get(idx).copied().unwrap_or(false) {
out.delta_poc_s0.push(dpoc);
out.used_s0.push(used.get(idx).copied().unwrap_or(false));
}
}
if delta_rps < 0 && use_delta.get(total).copied().unwrap_or(false) {
out.delta_poc_s0.push(delta_rps);
out.used_s0.push(used.get(total).copied().unwrap_or(false));
}
for j in 0..n_neg {
let dpoc = src.delta_poc_s0[j] + delta_rps;
if dpoc < 0 && use_delta.get(j).copied().unwrap_or(false) {
out.delta_poc_s0.push(dpoc);
out.used_s0.push(used.get(j).copied().unwrap_or(false));
}
}
for j in (0..n_neg).rev() {
let dpoc = src.delta_poc_s0[j] + delta_rps;
if dpoc > 0 && use_delta.get(j).copied().unwrap_or(false) {
out.delta_poc_s1.push(dpoc);
out.used_s1.push(used.get(j).copied().unwrap_or(false));
}
}
if delta_rps > 0 && use_delta.get(total).copied().unwrap_or(false) {
out.delta_poc_s1.push(delta_rps);
out.used_s1.push(used.get(total).copied().unwrap_or(false));
}
for j in 0..n_pos {
let dpoc = src.delta_poc_s1[j] + delta_rps;
let idx = n_neg + j;
if dpoc > 0 && use_delta.get(idx).copied().unwrap_or(false) {
out.delta_poc_s1.push(dpoc);
out.used_s1.push(used.get(idx).copied().unwrap_or(false));
}
}
out
}
pub(crate) fn derive_poc(
poc_lsb: i32,
prev_poc: i32,
max_poc_lsb: i32,
is_irap_no_rasl: bool,
) -> i32 {
if is_irap_no_rasl {
return poc_lsb;
}
let prev_lsb = prev_poc.rem_euclid(max_poc_lsb);
let prev_msb = prev_poc - prev_lsb;
let msb = if poc_lsb < prev_lsb && (prev_lsb - poc_lsb) >= (max_poc_lsb / 2) {
prev_msb + max_poc_lsb
} else if poc_lsb > prev_lsb && (poc_lsb - prev_lsb) > (max_poc_lsb / 2) {
prev_msb - max_poc_lsb
} else {
prev_msb
};
msb + poc_lsb
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bitreader::BitReader;
#[test]
fn parse_explicit_single_negative() {
let bytes = [0b0101_1100];
let mut r = BitReader::new(&bytes);
let rps = parse_short_term_rps(&mut r, 0, 1, &[]).unwrap();
assert_eq!(rps.delta_poc_s0, vec![-1]);
assert_eq!(rps.used_s0, vec![true]);
assert!(rps.delta_poc_s1.is_empty());
}
#[test]
fn poc_wraps() {
let max = 256;
let p = derive_poc(2, 255, max, false);
assert_eq!(p, 258);
assert_eq!(derive_poc(0, 999, max, true), 0);
}
fn src_rps(s0: &[i32], s1: &[i32]) -> ShortTermRps {
ShortTermRps {
delta_poc_s0: s0.to_vec(),
used_s0: vec![true; s0.len()],
delta_poc_s1: s1.to_vec(),
used_s1: vec![true; s1.len()],
}
}
#[test]
fn inter_rps_negative_delta() {
let src = src_rps(&[-1, -2], &[4]);
let used = [true, true, true, true];
let use_delta = [true, true, true, true];
let out = derive_inter_rps(&src, -1, &used, &use_delta);
assert_eq!(out.delta_poc_s0, vec![-1, -2, -3]);
assert_eq!(out.delta_poc_s1, vec![3]);
}
#[test]
fn inter_rps_positive_delta() {
let src = src_rps(&[-2], &[3]);
let used = [true, true, true];
let use_delta = [true, true, true];
let out = derive_inter_rps(&src, 2, &used, &use_delta);
assert!(out.delta_poc_s0.is_empty());
assert_eq!(out.delta_poc_s1, vec![2, 5]);
}
#[test]
fn inter_rps_use_delta_excludes_entry() {
let src = src_rps(&[-1], &[3]);
let used = [true, false, true];
let use_delta = [true, false, true]; let out = derive_inter_rps(&src, 1, &used, &use_delta);
assert_eq!(out.delta_poc_s1, vec![1]);
assert!(out.delta_poc_s0.is_empty());
}
}