mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-28 20:47:15 -06:00
Refactor h264 for strict Clippy checks
This commit is contained in:
+76
-63
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user