Refactor h264 for strict Clippy checks

This commit is contained in:
Dylan M. Taylor
2026-10-28 06:02:27 +00:00
parent 0e7cd01381
commit d9749fbcc5
3 changed files with 279 additions and 276 deletions
+76 -63
View File
@@ -302,71 +302,12 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
let top = usable(if my > 0 { Some(addr - mb_w) } else { None });
let alpha_off = sq.alpha_offset;
let beta_off = sq.beta_offset;
let t8 = q.transform_8x8;
// bS[dir][edge][segment]; dir 0 = vertical edges (x), 1 = horizontal edges (y)
let mut bs = [[[0u8; 4]; 4]; 2];
if q.kind.is_intra() {
for dir in 0..2 {
if (if dir == 0 { left } else { top }).is_some() {
bs[dir][0] = [4; 4];
}
for e in 1..4 {
if !(t8 && e % 2 == 1) {
bs[dir][e] = [3; 4];
}
}
}
} else {
let qids = ref_ids8(q, sq);
let q_uniform = (0..2).all(|l| {
let r = q.ref_idx[l];
r[1] == r[0] && r[2] == r[0] && r[3] == r[0] && q.mv[l].iter().all(|m| *m == q.mv[l][0])
});
let qm: [Motion; 16] = std::array::from_fn(|r| block_motion(q, &qids, r));
for dir in 0..2 {
let neighbor = if dir == 0 { left } else { top };
if let Some(n) = neighbor {
let p = &pic.mbs[n];
if p.kind.is_intra() {
bs[dir][0] = [4; 4];
} else {
let pids = ref_ids8(p, &pic.slices[p.slice_num as usize]);
for k in 0..4 {
let (rq, rp) = if dir == 0 { (k * 4, k * 4 + 3) } else { (k, 12 + k) };
bs[dir][0][k] = if (p.nz_mask >> rp) & 1 != 0 || (q.nz_mask >> rq) & 1 != 0 {
2
} else {
motion_bs(&block_motion(p, &pids, rp), &qm[rq])
};
}
}
}
if q_uniform && q.nz_mask == 0 {
// one motion for the whole MB and no coefficients: all internal edges have bS 0
continue;
}
for e in 1..4 {
if t8 && e % 2 == 1 {
continue;
}
for k in 0..4 {
let (rq, rp) = if dir == 0 { (k * 4 + e, k * 4 + e - 1) } else { (e * 4 + k, e * 4 + k - 4) };
bs[dir][e][k] = if (q.nz_mask >> rp) & 1 != 0 || (q.nz_mask >> rq) & 1 != 0 { 2 } else { motion_bs(&qm[rp], &qm[rq]) };
}
}
}
}
let bs = boundary_strengths(pic, q, sq, [left, top]);
let qp_of = |st: &MbState| if st.kind == MbKind::IPcm { 0 } else { st.qp as i32 };
let q_qp = qp_of(q);
let q_qpc = q.qpc;
let p_qp = [left.map(|n| (qp_of(&pic.mbs[n]), pic.mbs[n].qpc)), top.map(|n| (qp_of(&pic.mbs[n]), pic.mbs[n].qpc))];
let params = |qpp: i32, qpq: i32, b: [u8; 4]| {
let qpav = (qpp + qpq + 1) >> 1;
let index_a = (qpav + alpha_off).clamp(0, 51) as usize;
let index_b = (qpav + beta_off).clamp(0, 51) as usize;
let tc = |b: u8| if (1..4).contains(&b) { TC0[index_a][b as usize - 1] as i32 } else { 0 };
EdgeParams { bs: b, tc0: [tc(b[0]), tc(b[1]), tc(b[2]), tc(b[3])], alpha: ALPHA[index_a] as i32, beta: BETA[index_b] as i32 }
};
let offsets = (alpha_off, beta_off);
let width = pic.planes.width;
let cwidth = pic.planes.cwidth;
// luma
@@ -376,7 +317,7 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
continue;
}
let qpp = if e == 0 { p_qp[dir].map(|p| p.0).unwrap_or(q_qp) } else { q_qp };
let ep = params(qpp, q_qp, bs[dir][e]);
let ep = edge_params(offsets, qpp, q_qp, bs[dir][e]);
if ep.alpha == 0 || ep.beta == 0 {
// filterSamplesFlag needs |p0 - q0| < alpha and |p1 - p0| < beta (8.7.2.2): no
// sample of the edge changes (low QPs)
@@ -398,7 +339,7 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
continue;
}
let qpp = if e == 0 { p_qp[dir].map(|p| p.1[c]).unwrap_or(q_qpc[c]) } else { q_qpc[c] } as i32;
let ep = params(qpp, q_qpc[c] as i32, bs[dir][e]);
let ep = edge_params(offsets, qpp, q_qpc[c] as i32, bs[dir][e]);
if ep.alpha == 0 || ep.beta == 0 {
continue;
}
@@ -413,6 +354,78 @@ pub fn deblock_mb(pic: &mut PicState, addr: usize, mb_w: usize) {
}
}
/// Filter parameters of one edge from the neighbouring QPs and the slice's alpha/beta offsets.
fn edge_params((alpha_off, beta_off): (i32, i32), qpp: i32, qpq: i32, b: [u8; 4]) -> EdgeParams {
let qpav = (qpp + qpq + 1) >> 1;
let index_a = (qpav + alpha_off).clamp(0, 51) as usize;
let index_b = (qpav + beta_off).clamp(0, 51) as usize;
let tc = |b: u8| if (1..4).contains(&b) { TC0[index_a][b as usize - 1] as i32 } else { 0 };
EdgeParams { bs: b, tc0: [tc(b[0]), tc(b[1]), tc(b[2]), tc(b[3])], alpha: ALPHA[index_a] as i32, beta: BETA[index_b] as i32 }
}
/// bS[dir][edge][segment]; dir 0 = vertical edges (x), 1 = horizontal edges (y). `neighbors` is
/// `[left, top]`.
fn boundary_strengths(pic: &PicState, q: &MbState, sq: &SliceInfo, neighbors: [Option<usize>; 2]) -> [[[u8; 4]; 4]; 2] {
if q.kind.is_intra() { intra_strengths(q.transform_8x8, neighbors) } else { inter_strengths(pic, q, sq, neighbors) }
}
fn intra_strengths(t8: bool, neighbors: [Option<usize>; 2]) -> [[[u8; 4]; 4]; 2] {
let mut bs = [[[0u8; 4]; 4]; 2];
for dir in 0..2 {
if neighbors[dir].is_some() {
bs[dir][0] = [4; 4];
}
for e in 1..4 {
if !(t8 && e % 2 == 1) {
bs[dir][e] = [3; 4];
}
}
}
bs
}
fn inter_strengths(pic: &PicState, q: &MbState, sq: &SliceInfo, neighbors: [Option<usize>; 2]) -> [[[u8; 4]; 4]; 2] {
let mut bs = [[[0u8; 4]; 4]; 2];
let t8 = q.transform_8x8;
let qids = ref_ids8(q, sq);
let q_uniform = (0..2).all(|l| {
let r = q.ref_idx[l];
r[1] == r[0] && r[2] == r[0] && r[3] == r[0] && q.mv[l].iter().all(|m| *m == q.mv[l][0])
});
let qm: [Motion; 16] = std::array::from_fn(|r| block_motion(q, &qids, r));
for dir in 0..2 {
if let Some(n) = neighbors[dir] {
bs[dir][0] = edge_strengths_to_neighbor(&pic.mbs[n], &pic.slices[pic.mbs[n].slice_num as usize], q, &qm, dir);
}
if q_uniform && q.nz_mask == 0 {
// one motion for the whole MB and no coefficients: all internal edges have bS 0
continue;
}
for e in 1..4 {
if t8 && e % 2 == 1 {
continue;
}
for k in 0..4 {
let (rq, rp) = if dir == 0 { (k * 4 + e, k * 4 + e - 1) } else { (e * 4 + k, e * 4 + k - 4) };
bs[dir][e][k] = if (q.nz_mask >> rp) & 1 != 0 || (q.nz_mask >> rq) & 1 != 0 { 2 } else { motion_bs(&qm[rp], &qm[rq]) };
}
}
}
bs
}
/// bS of the macroblock edge shared with neighbour `p` (left for `dir` 0, top for `dir` 1).
fn edge_strengths_to_neighbor(p: &MbState, p_slice: &SliceInfo, q: &MbState, qm: &[Motion; 16], dir: usize) -> [u8; 4] {
if p.kind.is_intra() {
return [4; 4];
}
let pids = ref_ids8(p, p_slice);
std::array::from_fn(|k| {
let (rq, rp) = if dir == 0 { (k * 4, k * 4 + 3) } else { (k, 12 + k) };
if (p.nz_mask >> rp) & 1 != 0 || (q.nz_mask >> rq) & 1 != 0 { 2 } else { motion_bs(&block_motion(p, &pids, rp), &qm[rq]) }
})
}
#[cfg(test)]
mod tests {
use super::*;
+93 -117
View File
@@ -61,126 +61,102 @@ fn load_edge(plane: &[u8], stride: usize, x: usize, y: usize, n: usize, a: Avail
/// Directional / DC prediction shared by Intra_4x4 and Intra_8x8 (8.3.1.2.x, 8.3.2.2.x).
fn pred_nxn(mode: u8, e: &Edge, n: i32, a: Avail, out: &mut [u8], stride: usize) {
let mut put = |x: i32, y: i32, v: i32| out[y as usize * stride + x as usize] = v as u8;
let mut fill = |value: &dyn Fn(i32, i32) -> i32| {
for y in 0..n {
for x in 0..n {
out[y as usize * stride + x as usize] = value(x, y) as u8;
}
}
};
match mode {
0 => {
for y in 0..n {
for x in 0..n {
put(x, y, e.t(x));
}
}
}
1 => {
for y in 0..n {
for x in 0..n {
put(x, y, e.l(y));
}
}
}
0 => fill(&|x, _| e.t(x)),
1 => fill(&|_, y| e.l(y)),
2 => {
let shift = if n == 4 { 2 } else { 3 };
let st: i32 = (0..n).map(|x| e.t(x)).sum();
let sl: i32 = (0..n).map(|y| e.l(y)).sum();
let dc = match (a.top, a.left) {
(true, true) => (st + sl + n) >> (shift + 1),
(false, true) => (sl + (n >> 1)) >> shift,
(true, false) => (st + (n >> 1)) >> shift,
_ => 128,
};
for y in 0..n {
for x in 0..n {
put(x, y, dc);
}
}
}
3 => {
for y in 0..n {
for x in 0..n {
let v = if x == n - 1 && y == n - 1 {
(e.t(2 * n - 2) + 3 * e.t(2 * n - 1) + 2) >> 2
} else {
(e.t(x + y) + 2 * e.t(x + y + 1) + e.t(x + y + 2) + 2) >> 2
};
put(x, y, v);
}
}
}
4 => {
for y in 0..n {
for x in 0..n {
let v = if x > y {
(e.t(x - y - 2) + 2 * e.t(x - y - 1) + e.t(x - y) + 2) >> 2
} else if x < y {
(e.l(y - x - 2) + 2 * e.l(y - x - 1) + e.l(y - x) + 2) >> 2
} else {
(e.t(0) + 2 * e.tl + e.l(0) + 2) >> 2
};
put(x, y, v);
}
}
}
5 => {
for y in 0..n {
for x in 0..n {
let z = 2 * x - y;
let v = if z >= 0 && z % 2 == 0 {
(e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 1) >> 1
} else if z > 0 {
(e.t(x - (y >> 1) - 2) + 2 * e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 2) >> 2
} else if z == -1 {
(e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
} else {
(e.l(y - 2 * x - 1) + 2 * e.l(y - 2 * x - 2) + e.l(y - 2 * x - 3) + 2) >> 2
};
put(x, y, v);
}
}
}
6 => {
for y in 0..n {
for x in 0..n {
let z = 2 * y - x;
let v = if z >= 0 && z % 2 == 0 {
(e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 1) >> 1
} else if z > 0 {
(e.l(y - (x >> 1) - 2) + 2 * e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 2) >> 2
} else if z == -1 {
(e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
} else {
(e.t(x - 2 * y - 1) + 2 * e.t(x - 2 * y - 2) + e.t(x - 2 * y - 3) + 2) >> 2
};
put(x, y, v);
}
}
}
7 => {
for y in 0..n {
for x in 0..n {
let i = x + (y >> 1);
let v = if y % 2 == 0 { (e.t(i) + e.t(i + 1) + 1) >> 1 } else { (e.t(i) + 2 * e.t(i + 1) + e.t(i + 2) + 2) >> 2 };
put(x, y, v);
}
}
}
_ => {
let zmax = 2 * n - 3;
for y in 0..n {
for x in 0..n {
let z = x + 2 * y;
let i = y + (x >> 1);
let v = if z < zmax && z % 2 == 0 {
(e.l(i) + e.l(i + 1) + 1) >> 1
} else if z < zmax {
(e.l(i) + 2 * e.l(i + 1) + e.l(i + 2) + 2) >> 2
} else if z == zmax {
(e.l(n - 2) + 3 * e.l(n - 1) + 2) >> 2
} else {
e.l(n - 1)
};
put(x, y, v);
}
}
let dc = dc_value(e, n, a);
fill(&|_, _| dc);
}
3 => fill(&|x, y| diagonal_down_left(e, n, x, y)),
4 => fill(&|x, y| diagonal_down_right(e, x, y)),
5 => fill(&|x, y| vertical_right(e, x, y)),
6 => fill(&|x, y| horizontal_down(e, x, y)),
7 => fill(&|x, y| vertical_left(e, x, y)),
_ => fill(&|x, y| horizontal_up(e, n, x, y)),
}
}
fn dc_value(e: &Edge, n: i32, a: Avail) -> i32 {
let shift = if n == 4 { 2 } else { 3 };
let st: i32 = (0..n).map(|x| e.t(x)).sum();
let sl: i32 = (0..n).map(|y| e.l(y)).sum();
match (a.top, a.left) {
(true, true) => (st + sl + n) >> (shift + 1),
(false, true) => (sl + (n >> 1)) >> shift,
(true, false) => (st + (n >> 1)) >> shift,
_ => 128,
}
}
fn diagonal_down_left(e: &Edge, n: i32, x: i32, y: i32) -> i32 {
if x == n - 1 && y == n - 1 {
(e.t(2 * n - 2) + 3 * e.t(2 * n - 1) + 2) >> 2
} else {
(e.t(x + y) + 2 * e.t(x + y + 1) + e.t(x + y + 2) + 2) >> 2
}
}
fn diagonal_down_right(e: &Edge, x: i32, y: i32) -> i32 {
if x > y {
(e.t(x - y - 2) + 2 * e.t(x - y - 1) + e.t(x - y) + 2) >> 2
} else if x < y {
(e.l(y - x - 2) + 2 * e.l(y - x - 1) + e.l(y - x) + 2) >> 2
} else {
(e.t(0) + 2 * e.tl + e.l(0) + 2) >> 2
}
}
fn vertical_right(e: &Edge, x: i32, y: i32) -> i32 {
let z = 2 * x - y;
if z >= 0 && z % 2 == 0 {
(e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 1) >> 1
} else if z > 0 {
(e.t(x - (y >> 1) - 2) + 2 * e.t(x - (y >> 1) - 1) + e.t(x - (y >> 1)) + 2) >> 2
} else if z == -1 {
(e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
} else {
(e.l(y - 2 * x - 1) + 2 * e.l(y - 2 * x - 2) + e.l(y - 2 * x - 3) + 2) >> 2
}
}
fn horizontal_down(e: &Edge, x: i32, y: i32) -> i32 {
let z = 2 * y - x;
if z >= 0 && z % 2 == 0 {
(e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 1) >> 1
} else if z > 0 {
(e.l(y - (x >> 1) - 2) + 2 * e.l(y - (x >> 1) - 1) + e.l(y - (x >> 1)) + 2) >> 2
} else if z == -1 {
(e.l(0) + 2 * e.tl + e.t(0) + 2) >> 2
} else {
(e.t(x - 2 * y - 1) + 2 * e.t(x - 2 * y - 2) + e.t(x - 2 * y - 3) + 2) >> 2
}
}
fn vertical_left(e: &Edge, x: i32, y: i32) -> i32 {
let i = x + (y >> 1);
if y % 2 == 0 { (e.t(i) + e.t(i + 1) + 1) >> 1 } else { (e.t(i) + 2 * e.t(i + 1) + e.t(i + 2) + 2) >> 2 }
}
fn horizontal_up(e: &Edge, n: i32, x: i32, y: i32) -> i32 {
let zmax = 2 * n - 3;
let z = x + 2 * y;
let i = y + (x >> 1);
if z < zmax && z % 2 == 0 {
(e.l(i) + e.l(i + 1) + 1) >> 1
} else if z < zmax {
(e.l(i) + 2 * e.l(i + 1) + e.l(i + 2) + 2) >> 2
} else if z == zmax {
(e.l(n - 2) + 3 * e.l(n - 1) + 2) >> 2
} else {
e.l(n - 1)
}
}
+110 -96
View File
@@ -142,6 +142,107 @@ pub struct SliceHeader {
pub header_bits: usize,
}
/// ref_pic_list_modification() for list 0 and list 1.
fn read_ref_pic_list_mods(r: &mut BitReader, slice_type: SliceType) -> Result<[Vec<RefPicListMod>; 2]> {
let mut ref_pic_list_mod = [Vec::new(), Vec::new()];
for (list, mods) in ref_pic_list_mod.iter_mut().enumerate() {
let present = if list == 0 { !slice_type.is_intra() } else { slice_type.is_b() };
if present && r.read_flag()? {
loop {
let idc = r.read_ue()?;
ensure!(idc <= 5, "modification_of_pic_nums_idc out of range");
if idc == 3 {
break;
}
let value = r.read_ue()?;
mods.push(RefPicListMod { idc, value });
ensure!(mods.len() <= 66, "too many ref_pic_list_modification entries");
}
}
}
Ok(ref_pic_list_mod)
}
/// pred_weight_table().
fn read_pred_weight_table(r: &mut BitReader, sps: &Sps, slice_type: SliceType, num_ref_idx_active: [u32; 2]) -> Result<PredWeightTable> {
let luma_log2_denom = r.read_ue()?;
ensure!(luma_log2_denom <= 7, "luma_log2_weight_denom out of range");
let has_chroma = sps.chroma_array_type() != 0;
let mut chroma_log2_denom = 0;
if has_chroma {
chroma_log2_denom = r.read_ue()?;
ensure!(chroma_log2_denom <= 7, "chroma_log2_weight_denom out of range");
}
let mut lists = [Vec::new(), Vec::new()];
let nlists = if slice_type.is_b() { 2 } else { 1 };
for (l, entries) in lists.iter_mut().enumerate().take(nlists) {
for _ in 0..num_ref_idx_active[l] {
entries.push(read_weight_entry(r, has_chroma, luma_log2_denom, chroma_log2_denom)?);
}
}
let [l0, l1] = lists;
Ok(PredWeightTable { luma_log2_denom, chroma_log2_denom, l0, l1 })
}
fn read_weight_entry(r: &mut BitReader, has_chroma: bool, luma_log2_denom: u32, chroma_log2_denom: u32) -> Result<WeightEntry> {
let mut e = WeightEntry { luma_weight: 1 << luma_log2_denom, chroma_weight: [1 << chroma_log2_denom; 2], ..Default::default() };
if r.read_flag()? {
e.luma_flag = true;
e.luma_weight = r.read_se()?;
e.luma_offset = r.read_se()?;
ensure!((-128..=127).contains(&e.luma_weight) && (-128..=127).contains(&e.luma_offset), "luma weight out of range");
}
if has_chroma && r.read_flag()? {
e.chroma_flag = true;
for j in 0..2 {
e.chroma_weight[j] = r.read_se()?;
e.chroma_offset[j] = r.read_se()?;
ensure!((-128..=127).contains(&e.chroma_weight[j]) && (-128..=127).contains(&e.chroma_offset[j]), "chroma weight out of range");
}
}
Ok(e)
}
/// The memory_management_control_operation list of dec_ref_pic_marking().
fn read_mmcos(r: &mut BitReader) -> Result<Vec<Mmco>> {
let mut mmcos = Vec::new();
loop {
let op = r.read_ue()?;
ensure!(op <= 6, "memory_management_control_operation out of range");
if op == 0 {
return Ok(mmcos);
}
let mut m = Mmco { op, difference_of_pic_nums_minus1: 0, long_term_pic_num: 0, long_term_frame_idx: 0, max_long_term_frame_idx_plus1: 0 };
if op == 1 || op == 3 {
m.difference_of_pic_nums_minus1 = r.read_ue()?;
}
if op == 2 {
m.long_term_pic_num = r.read_ue()?;
}
if op == 3 || op == 6 {
m.long_term_frame_idx = r.read_ue()?;
}
if op == 4 {
m.max_long_term_frame_idx_plus1 = r.read_ue()?;
}
mmcos.push(m);
ensure!(mmcos.len() <= 66, "too many MMCOs");
}
}
/// Deblocking filter control: (disable_deblocking_filter_idc, alpha_c0_offset_div2, beta_offset_div2).
fn read_deblocking_params(r: &mut BitReader) -> Result<(u32, i32, i32)> {
let disable_deblocking_filter_idc = r.read_ue()?;
ensure!(disable_deblocking_filter_idc <= 2, "disable_deblocking_filter_idc out of range");
if disable_deblocking_filter_idc == 1 {
return Ok((disable_deblocking_filter_idc, 0, 0));
}
let alpha = r.read_se()?;
let beta = r.read_se()?;
ensure!((-6..=6).contains(&alpha) && (-6..=6).contains(&beta), "deblocking offsets out of range");
Ok((disable_deblocking_filter_idc, alpha, beta))
}
impl SliceHeader {
pub fn qp(&self, pps: &Pps) -> i32 {
pps.pic_init_qp.saturating_add(self.slice_qp_delta)
@@ -214,59 +315,12 @@ impl SliceHeader {
num_ref_idx_active[0] = 0;
}
ensure!(nal.nal_unit_type != 20 && nal.nal_unit_type != 21, "MVC slices are not supported");
let mut ref_pic_list_mod = [Vec::new(), Vec::new()];
for (list, mods) in ref_pic_list_mod.iter_mut().enumerate() {
let present = if list == 0 { !slice_type.is_intra() } else { slice_type.is_b() };
if present && r.read_flag()? {
loop {
let idc = r.read_ue()?;
ensure!(idc <= 5, "modification_of_pic_nums_idc out of range");
if idc == 3 {
break;
}
let value = r.read_ue()?;
mods.push(RefPicListMod { idc, value });
ensure!(mods.len() <= 66, "too many ref_pic_list_modification entries");
}
}
}
let mut pred_weight_table = None;
if (pps.weighted_pred && slice_type.is_p()) || (pps.weighted_bipred_idc == 1 && slice_type.is_b()) {
let luma_log2_denom = r.read_ue()?;
ensure!(luma_log2_denom <= 7, "luma_log2_weight_denom out of range");
let mut chroma_log2_denom = 0;
if sps.chroma_array_type() != 0 {
chroma_log2_denom = r.read_ue()?;
ensure!(chroma_log2_denom <= 7, "chroma_log2_weight_denom out of range");
}
let mut lists = [Vec::new(), Vec::new()];
let nlists = if slice_type.is_b() { 2 } else { 1 };
for (l, entries) in lists.iter_mut().enumerate().take(nlists) {
for _ in 0..num_ref_idx_active[l] {
let mut e = WeightEntry { luma_weight: 1 << luma_log2_denom, chroma_weight: [1 << chroma_log2_denom; 2], ..Default::default() };
if r.read_flag()? {
e.luma_flag = true;
e.luma_weight = r.read_se()?;
e.luma_offset = r.read_se()?;
ensure!((-128..=127).contains(&e.luma_weight) && (-128..=127).contains(&e.luma_offset), "luma weight out of range");
}
if sps.chroma_array_type() != 0 && r.read_flag()? {
e.chroma_flag = true;
for j in 0..2 {
e.chroma_weight[j] = r.read_se()?;
e.chroma_offset[j] = r.read_se()?;
ensure!(
(-128..=127).contains(&e.chroma_weight[j]) && (-128..=127).contains(&e.chroma_offset[j]),
"chroma weight out of range"
);
}
}
entries.push(e);
}
}
let [l0, l1] = lists;
pred_weight_table = Some(PredWeightTable { luma_log2_denom, chroma_log2_denom, l0, l1 });
}
let ref_pic_list_mod = read_ref_pic_list_mods(&mut r, slice_type)?;
let pred_weight_table = if (pps.weighted_pred && slice_type.is_p()) || (pps.weighted_bipred_idc == 1 && slice_type.is_b()) {
Some(read_pred_weight_table(&mut r, sps, slice_type, num_ref_idx_active)?)
} else {
None
};
let mut no_output_of_prior_pics = false;
let mut long_term_reference = false;
let mut adaptive_ref_pic_marking = false;
@@ -278,34 +332,7 @@ impl SliceHeader {
} else {
adaptive_ref_pic_marking = r.read_flag()?;
if adaptive_ref_pic_marking {
loop {
let op = r.read_ue()?;
ensure!(op <= 6, "memory_management_control_operation out of range");
if op == 0 {
break;
}
let mut m = Mmco {
op,
difference_of_pic_nums_minus1: 0,
long_term_pic_num: 0,
long_term_frame_idx: 0,
max_long_term_frame_idx_plus1: 0,
};
if op == 1 || op == 3 {
m.difference_of_pic_nums_minus1 = r.read_ue()?;
}
if op == 2 {
m.long_term_pic_num = r.read_ue()?;
}
if op == 3 || op == 6 {
m.long_term_frame_idx = r.read_ue()?;
}
if op == 4 {
m.max_long_term_frame_idx_plus1 = r.read_ue()?;
}
mmcos.push(m);
ensure!(mmcos.len() <= 66, "too many MMCOs");
}
mmcos = read_mmcos(&mut r)?;
}
}
}
@@ -325,21 +352,8 @@ impl SliceHeader {
}
slice_qs_delta = r.read_se()?;
}
let mut disable_deblocking_filter_idc = 0;
let mut slice_alpha_c0_offset_div2 = 0;
let mut slice_beta_offset_div2 = 0;
if pps.deblocking_filter_control_present {
disable_deblocking_filter_idc = r.read_ue()?;
ensure!(disable_deblocking_filter_idc <= 2, "disable_deblocking_filter_idc out of range");
if disable_deblocking_filter_idc != 1 {
slice_alpha_c0_offset_div2 = r.read_se()?;
slice_beta_offset_div2 = r.read_se()?;
ensure!(
(-6..=6).contains(&slice_alpha_c0_offset_div2) && (-6..=6).contains(&slice_beta_offset_div2),
"deblocking offsets out of range"
);
}
}
let (disable_deblocking_filter_idc, slice_alpha_c0_offset_div2, slice_beta_offset_div2) =
if pps.deblocking_filter_control_present { read_deblocking_params(&mut r)? } else { (0, 0, 0) };
let mut slice_group_change_cycle = 0;
if pps.num_slice_groups > 1 && (3..=5).contains(&pps.slice_group_map_type) {
// Ceil(Log2(PicSizeInMapUnits / SliceGroupChangeRate + 1)); rate is not retained, so read