#![forbid(unsafe_code)]
use crate::DecodeError;
use mediaway_sw::h264::BitReader;
#[allow(
dead_code,
reason = "exercised by bits_tests.rs; no field in this crate's KEY_FRAME-only, \
decoder-model-disabled scope currently needs uvlc() (AV1's other two \
non-Exp-Golomb VLCs, su()/ns(), are both real call sites in \
frame_header.rs/tile_info.rs) — kept for API completeness matching this ADR's \
own 'implement AV1's own small set of variable-length decoders' design table \
entry, ready for whatever future field (e.g. timing_info()) needs it"
)]
pub(super) fn uvlc(r: &mut BitReader<'_>) -> Result<u32, DecodeError> {
let map_err = |_| DecodeError::InvalidInput;
let mut leading_zeros = 0u32;
loop {
let done = r.read_bit().map_err(map_err)?;
if done != 0 {
break;
}
leading_zeros += 1;
if leading_zeros >= 32 {
return Ok(u32::MAX);
}
}
if leading_zeros == 0 {
return Ok(0);
}
let value = r.read_bits(leading_zeros).map_err(map_err)?;
let bias = 1u32
.checked_shl(leading_zeros)
.unwrap_or(u32::MAX)
.saturating_sub(1);
Ok(value.saturating_add(bias))
}
pub(super) fn su(r: &mut BitReader<'_>, n: u32) -> Result<i32, DecodeError> {
let map_err = |_| DecodeError::InvalidInput;
let value = r.read_bits(n).map_err(map_err)?;
let sign_mask = 1u32.checked_shl(n - 1).ok_or(DecodeError::InvalidInput)?;
let value = i64::from(value);
let signed = if value & i64::from(sign_mask) != 0 {
value - 2 * i64::from(sign_mask)
} else {
value
};
i32::try_from(signed).map_err(|_| DecodeError::InvalidInput)
}
#[allow(
clippy::many_single_char_names,
reason = "w/m/v are the AV1 spec's own ns(n) variable names (§4.10.7); longer synonyms \
would obscure the direct correspondence to the spec pseudocode"
)]
pub(super) fn ns(reader: &mut BitReader<'_>, n: u32) -> Result<u32, DecodeError> {
let map_err = |_| DecodeError::InvalidInput;
if n <= 1 {
return Ok(0);
}
let w = u32::BITS - n.leading_zeros();
let m = (1u32 << w) - n;
let v = reader.read_bits(w - 1).map_err(map_err)?;
if v < m {
return Ok(v);
}
let extra_bit = reader.read_bit().map_err(map_err)?;
Ok((v << 1) - m + extra_bit)
}
#[cfg(test)]
#[path = "bits_tests.rs"]
mod tests;