Refactor hevc for strict Clippy checks

This commit is contained in:
Dylan M. Taylor
2026-10-28 06:02:27 +00:00
parent 9c52950536
commit 0e7cd01381
2 changed files with 433 additions and 342 deletions
+190 -147
View File
@@ -154,6 +154,194 @@ impl SliceHeader {
(st + lt) as u32
}
/// Fields present only in independent slice segments.
fn parse_independent_fields(&mut self, r: &mut BitReader, nal: NalHeader, pps: &Pps, sps: &Sps) -> Result<()> {
r.skip(pps.num_extra_slice_header_bits as usize)?;
let st = r.read_ue()?;
self.slice_type = match st {
0 => SliceType::B,
1 => SliceType::P,
2 => SliceType::I,
_ => return invalid(format!("slice_type {st}")),
};
if nal.is_irap() {
ensure!(self.slice_type == SliceType::I, "IRAP picture with inter slice");
}
if pps.output_flag_present {
self.pic_output = r.read_flag()?;
}
if sps.separate_colour_plane {
r.skip(2)?;
}
if !nal.is_idr() {
self.parse_reference_picture_set(r, sps)?;
}
if sps.sao {
self.sao_luma = r.read_flag()?;
if sps.chroma_array_type() != 0 {
self.sao_chroma = r.read_flag()?;
}
}
if self.slice_type != SliceType::I {
self.parse_inter_params(r, pps, sps)?;
}
self.parse_qp_and_deblocking(r, pps, sps)
}
/// POC LSB, short-term and long-term reference picture sets and the temporal MVP flag.
fn parse_reference_picture_set(&mut self, r: &mut BitReader, sps: &Sps) -> Result<()> {
self.poc_lsb = r.read_bits(sps.log2_max_poc_lsb)?;
if !r.read_flag()? {
let start = r.position();
self.st_rps = StRps::parse(r, sps.st_rps.len(), &sps.st_rps, sps.st_rps.len())?;
self.st_rps_bits = r.position() - start;
} else {
ensure!(!sps.st_rps.is_empty(), "no short-term RPS in the SPS");
let idx = if sps.st_rps.len() > 1 { r.read_bits(ceil_log2(sps.st_rps.len() as u32))? as usize } else { 0 };
ensure!(idx < sps.st_rps.len(), "short_term_ref_pic_set_idx out of range");
self.st_rps = sps.st_rps[idx].clone();
}
if sps.long_term_refs_present {
self.parse_long_term_pics(r, sps)?;
}
if sps.temporal_mvp {
self.temporal_mvp = r.read_flag()?;
}
Ok(())
}
fn parse_long_term_pics(&mut self, r: &mut BitReader, sps: &Sps) -> Result<()> {
let num_lt_sps = if !sps.lt_ref_pics.is_empty() { r.read_ue()? } else { 0 };
ensure!(num_lt_sps as usize <= sps.lt_ref_pics.len(), "num_long_term_sps out of range");
let num_lt_pics = r.read_ue()?;
ensure!(num_lt_sps + num_lt_pics <= 32, "too many long-term pictures");
let mut msb_acc = 0u32;
for i in 0..num_lt_sps + num_lt_pics {
let (lsb, used) = if i < num_lt_sps {
let idx = if sps.lt_ref_pics.len() > 1 { r.read_bits(ceil_log2(sps.lt_ref_pics.len() as u32))? } else { 0 };
ensure!((idx as usize) < sps.lt_ref_pics.len(), "lt_idx_sps out of range");
sps.lt_ref_pics[idx as usize]
} else {
(r.read_bits(sps.log2_max_poc_lsb)?, r.read_flag()?)
};
let msb_present = r.read_flag()?;
let cycle = if msb_present { r.read_ue()? } else { 0 };
// DeltaPocMsbCycleLt accumulates within each of the two groups (7-52)
if i == 0 || i == num_lt_sps {
msb_acc = cycle;
} else {
msb_acc = msb_acc.wrapping_add(cycle);
}
self.lt.push((lsb, used, msb_present, msb_acc));
}
Ok(())
}
/// Reference index counts, list modification, collocated picture, prediction weights and merge candidates (P and B slices).
fn parse_inter_params(&mut self, r: &mut BitReader, pps: &Pps, sps: &Sps) -> Result<()> {
self.num_ref_idx = [pps.num_ref_idx_l0_default, if self.is_b() { pps.num_ref_idx_l1_default } else { 0 }];
if r.read_flag()? {
self.num_ref_idx[0] = r.read_ue_plus(1)?;
if self.is_b() {
self.num_ref_idx[1] = r.read_ue_plus(1)?;
}
}
ensure!(self.num_ref_idx[0] <= 15 && self.num_ref_idx[1] <= 15, "num_ref_idx_active out of range");
let total = self.num_pic_total_curr();
ensure!(total > 0, "inter slice without reference pictures in the RPS");
if pps.lists_modification_present && total > 1 {
self.parse_list_entries(r, total)?;
}
if self.is_b() {
self.mvd_l1_zero = r.read_flag()?;
}
if pps.cabac_init_present {
self.cabac_init_flag = r.read_flag()?;
}
if self.temporal_mvp {
self.parse_collocated(r)?;
}
if (pps.weighted_pred && self.slice_type == SliceType::P) || (pps.weighted_bipred && self.is_b()) {
self.pwt = Some(parse_pwt(r, self, sps)?);
}
let five_minus = r.read_ue()?;
ensure!(five_minus <= 4, "five_minus_max_num_merge_cand out of range");
self.max_num_merge_cand = 5 - five_minus;
Ok(())
}
fn parse_list_entries(&mut self, r: &mut BitReader, total: u32) -> Result<()> {
let bits = ceil_log2(total);
for l in 0..if self.is_b() { 2 } else { 1 } {
if r.read_flag()? {
let mut e = Vec::new();
for _ in 0..self.num_ref_idx[l] {
let v = r.read_bits(bits)?;
ensure!(v < total, "list_entry out of range");
e.push(v);
}
self.list_entry[l] = Some(e);
}
}
Ok(())
}
fn parse_collocated(&mut self, r: &mut BitReader) -> Result<()> {
if self.is_b() {
self.collocated_from_l0 = r.read_flag()?;
}
let l = if self.collocated_from_l0 { 0 } else { 1 };
if self.num_ref_idx[l] > 1 {
self.collocated_ref_idx = r.read_ue()?;
ensure!(self.collocated_ref_idx < self.num_ref_idx[l], "collocated_ref_idx out of range");
}
Ok(())
}
/// Slice QP delta, chroma QP offsets and the deblocking / loop filter overrides.
fn parse_qp_and_deblocking(&mut self, r: &mut BitReader, pps: &Pps, sps: &Sps) -> Result<()> {
self.qp_delta = r.read_se()?;
let qp = pps.init_qp.checked_add(self.qp_delta).ok_or_else(|| crate::Error::Invalid("SliceQpY out of range".into()))?;
let qp_bd = 6 * (sps.bit_depth_luma as i32 - 8);
ensure!((-qp_bd..=51).contains(&qp), "SliceQpY {qp} out of range");
if pps.slice_chroma_qp_offsets_present {
self.cb_qp_offset = r.read_se()?;
self.cr_qp_offset = r.read_se()?;
ensure!((-12..=12).contains(&self.cb_qp_offset) && (-12..=12).contains(&self.cr_qp_offset), "slice chroma QP offset out of range");
}
let override_flag = if pps.deblocking_override_enabled { r.read_flag()? } else { false };
if override_flag {
self.deblocking_disabled = r.read_flag()?;
if !self.deblocking_disabled {
self.beta_offset_div2 = r.read_se()?;
self.tc_offset_div2 = r.read_se()?;
ensure!((-6..=6).contains(&self.beta_offset_div2) && (-6..=6).contains(&self.tc_offset_div2), "deblocking offsets out of range");
}
}
if pps.loop_filter_across_slices && (self.sao_luma || self.sao_chroma || !self.deblocking_disabled) {
self.loop_filter_across_slices = r.read_flag()?;
}
Ok(())
}
/// entry_point_offset list (tiles / wavefront substreams).
fn parse_entry_points(&mut self, r: &mut BitReader, pps: &Pps, sps: &Sps) -> Result<()> {
self.entry_points.clear();
if pps.tiles_enabled || pps.entropy_coding_sync {
let n = r.read_ue()?;
ensure!(n <= sps.pic_width_in_ctbs() * sps.pic_height_in_ctbs(), "num_entry_point_offsets out of range");
if n > 0 {
let len = r.read_ue_plus(1)?;
ensure!(len <= 32, "offset_len_minus1 out of range");
for _ in 0..n {
let off = r.read_bits(len)?.checked_add(1).ok_or_else(|| crate::Error::Invalid("entry_point_offset out of range".into()))?;
self.entry_points.push(off);
}
}
}
Ok(())
}
/// Parse a slice segment header. `prev` is the header of the preceding independent slice segment
/// of the same picture (needed for dependent slice segments).
pub fn parse(
@@ -225,154 +413,9 @@ impl SliceHeader {
sh.dependent = dependent;
sh.segment_address = segment_address;
if !dependent {
r.skip(pps.num_extra_slice_header_bits as usize)?;
let st = r.read_ue()?;
sh.slice_type = match st {
0 => SliceType::B,
1 => SliceType::P,
2 => SliceType::I,
_ => return invalid(format!("slice_type {st}")),
};
if nal.is_irap() {
ensure!(sh.slice_type == SliceType::I, "IRAP picture with inter slice");
}
if pps.output_flag_present {
sh.pic_output = r.read_flag()?;
}
if sps.separate_colour_plane {
r.skip(2)?;
}
if !nal.is_idr() {
sh.poc_lsb = r.read_bits(sps.log2_max_poc_lsb)?;
let from_sps = r.read_flag()?;
if !from_sps {
let start = r.position();
sh.st_rps = StRps::parse(&mut r, sps.st_rps.len(), &sps.st_rps, sps.st_rps.len())?;
sh.st_rps_bits = r.position() - start;
} else {
ensure!(!sps.st_rps.is_empty(), "no short-term RPS in the SPS");
let idx = if sps.st_rps.len() > 1 { r.read_bits(ceil_log2(sps.st_rps.len() as u32))? as usize } else { 0 };
ensure!(idx < sps.st_rps.len(), "short_term_ref_pic_set_idx out of range");
sh.st_rps = sps.st_rps[idx].clone();
}
if sps.long_term_refs_present {
let num_lt_sps = if !sps.lt_ref_pics.is_empty() { r.read_ue()? } else { 0 };
ensure!(num_lt_sps as usize <= sps.lt_ref_pics.len(), "num_long_term_sps out of range");
let num_lt_pics = r.read_ue()?;
ensure!(num_lt_sps + num_lt_pics <= 32, "too many long-term pictures");
let mut msb_acc = 0u32;
for i in 0..num_lt_sps + num_lt_pics {
let (lsb, used) = if i < num_lt_sps {
let idx = if sps.lt_ref_pics.len() > 1 { r.read_bits(ceil_log2(sps.lt_ref_pics.len() as u32))? } else { 0 };
ensure!((idx as usize) < sps.lt_ref_pics.len(), "lt_idx_sps out of range");
sps.lt_ref_pics[idx as usize]
} else {
(r.read_bits(sps.log2_max_poc_lsb)?, r.read_flag()?)
};
let msb_present = r.read_flag()?;
let cycle = if msb_present { r.read_ue()? } else { 0 };
// DeltaPocMsbCycleLt accumulates within each of the two groups (7-52)
if i == 0 || i == num_lt_sps {
msb_acc = cycle;
} else {
msb_acc = msb_acc.wrapping_add(cycle);
}
sh.lt.push((lsb, used, msb_present, msb_acc));
}
}
if sps.temporal_mvp {
sh.temporal_mvp = r.read_flag()?;
}
}
if sps.sao {
sh.sao_luma = r.read_flag()?;
if sps.chroma_array_type() != 0 {
sh.sao_chroma = r.read_flag()?;
}
}
if sh.slice_type != SliceType::I {
sh.num_ref_idx = [pps.num_ref_idx_l0_default, if sh.is_b() { pps.num_ref_idx_l1_default } else { 0 }];
if r.read_flag()? {
sh.num_ref_idx[0] = r.read_ue_plus(1)?;
if sh.is_b() {
sh.num_ref_idx[1] = r.read_ue_plus(1)?;
}
}
ensure!(sh.num_ref_idx[0] <= 15 && sh.num_ref_idx[1] <= 15, "num_ref_idx_active out of range");
let total = sh.num_pic_total_curr();
ensure!(total > 0, "inter slice without reference pictures in the RPS");
if pps.lists_modification_present && total > 1 {
let bits = ceil_log2(total);
for l in 0..if sh.is_b() { 2 } else { 1 } {
if r.read_flag()? {
let mut e = Vec::new();
for _ in 0..sh.num_ref_idx[l] {
let v = r.read_bits(bits)?;
ensure!(v < total, "list_entry out of range");
e.push(v);
}
sh.list_entry[l] = Some(e);
}
}
}
if sh.is_b() {
sh.mvd_l1_zero = r.read_flag()?;
}
if pps.cabac_init_present {
sh.cabac_init_flag = r.read_flag()?;
}
if sh.temporal_mvp {
if sh.is_b() {
sh.collocated_from_l0 = r.read_flag()?;
}
let l = if sh.collocated_from_l0 { 0 } else { 1 };
if sh.num_ref_idx[l] > 1 {
sh.collocated_ref_idx = r.read_ue()?;
ensure!(sh.collocated_ref_idx < sh.num_ref_idx[l], "collocated_ref_idx out of range");
}
}
if (pps.weighted_pred && sh.slice_type == SliceType::P) || (pps.weighted_bipred && sh.is_b()) {
sh.pwt = Some(parse_pwt(&mut r, &sh, &sps)?);
}
let five_minus = r.read_ue()?;
ensure!(five_minus <= 4, "five_minus_max_num_merge_cand out of range");
sh.max_num_merge_cand = 5 - five_minus;
}
sh.qp_delta = r.read_se()?;
let qp = pps.init_qp.checked_add(sh.qp_delta).ok_or_else(|| crate::Error::Invalid("SliceQpY out of range".into()))?;
let qp_bd = 6 * (sps.bit_depth_luma as i32 - 8);
ensure!((-qp_bd..=51).contains(&qp), "SliceQpY {qp} out of range");
if pps.slice_chroma_qp_offsets_present {
sh.cb_qp_offset = r.read_se()?;
sh.cr_qp_offset = r.read_se()?;
ensure!((-12..=12).contains(&sh.cb_qp_offset) && (-12..=12).contains(&sh.cr_qp_offset), "slice chroma QP offset out of range");
}
let override_flag = if pps.deblocking_override_enabled { r.read_flag()? } else { false };
if override_flag {
sh.deblocking_disabled = r.read_flag()?;
if !sh.deblocking_disabled {
sh.beta_offset_div2 = r.read_se()?;
sh.tc_offset_div2 = r.read_se()?;
ensure!((-6..=6).contains(&sh.beta_offset_div2) && (-6..=6).contains(&sh.tc_offset_div2), "deblocking offsets out of range");
}
}
if pps.loop_filter_across_slices && (sh.sao_luma || sh.sao_chroma || !sh.deblocking_disabled) {
sh.loop_filter_across_slices = r.read_flag()?;
}
}
sh.entry_points.clear();
if pps.tiles_enabled || pps.entropy_coding_sync {
let n = r.read_ue()?;
ensure!(n <= sps.pic_width_in_ctbs() * sps.pic_height_in_ctbs(), "num_entry_point_offsets out of range");
if n > 0 {
let len = r.read_ue_plus(1)?;
ensure!(len <= 32, "offset_len_minus1 out of range");
for _ in 0..n {
let off = r.read_bits(len)?.checked_add(1).ok_or_else(|| crate::Error::Invalid("entry_point_offset out of range".into()))?;
sh.entry_points.push(off);
}
}
sh.parse_independent_fields(&mut r, nal, &pps, &sps)?;
}
sh.parse_entry_points(&mut r, &pps, &sps)?;
if pps.slice_header_extension_present {
let len = r.read_ue()?;
ensure!(len <= 256, "slice_segment_header_extension_length out of range");
+243 -195
View File
@@ -1105,7 +1105,52 @@ impl<'a> SliceDecoder<'a> {
let n = 1usize << log2;
let bypass = self.cu_transquant_bypass;
let ts = if self.pps.transform_skip && !bypass && log2 == 2 { self.dd(TRANSFORM_SKIP + (c > 0) as usize) == 1 } else { false };
// last significant coefficient
let scan_idx = self.scan_idx(x0, y0, log2, c);
let (mut lx, mut ly) = self.last_sig_coeff_pos(log2, c);
if scan_idx == 2 {
std::mem::swap(&mut lx, &mut ly);
}
ensure!((lx as usize) < n && (ly as usize) < n, "last significant coefficient outside the block");
let t = TbCtx { c, log2, scan_idx, sdh: self.pps.sign_data_hiding && !bypass };
let log2sb = log2 - 2;
let sb_scan = scan_order(log2sb, scan_idx);
let pos_scan = &SCAN_4[scan_idx];
let sb_w = 1usize << log2sb;
let last_sb = sb_scan.iter().position(|&(x, y)| x as u32 == lx >> 2 && y as u32 == ly >> 2).unwrap_or(0);
let last_pos = pos_scan.iter().position(|&(x, y)| x as u32 == lx & 3 && y as u32 == ly & 3).unwrap_or(0);
self.coeffs[..n * n].fill(0);
let mut csbf = [0u8; 64];
let mut prev_g1: Option<u32> = None;
let (mut max_x, mut max_y) = (0usize, 0usize);
for i in (0..=last_sb).rev() {
let sb = SubBlock { xs: sb_scan[i].0 as usize, ys: sb_scan[i].1 as usize };
let right = if sb.xs + 1 < sb_w { csbf[sb.ys * 8 + sb.xs + 1] } else { 0 };
let below = if sb.ys + 1 < sb_w { csbf[(sb.ys + 1) * 8 + sb.xs] } else { 0 };
let mut infer_dc = false;
if i < last_sb && i > 0 {
let inc = (right | below).min(1) as usize + if c > 0 { 2 } else { 0 };
csbf[sb.ys * 8 + sb.xs] = self.c.decode_decision(CODED_SUB_BLOCK + inc) as u8;
infer_dc = true;
} else {
csbf[sb.ys * 8 + sb.xs] = 1;
}
if csbf[sb.ys * 8 + sb.xs] == 0 {
continue;
}
let (sig, nsig) = self.sig_coeff_flags(&t, &sb, right + (below << 1), infer_dc, (i == last_sb).then_some(last_pos));
if nsig == 0 {
continue;
}
let g = self.greater_flags(&t, i, nsig, &mut prev_g1);
let (mx, my) = self.store_levels(&t, &sb, &sig[..nsig], &g)?;
max_x = max_x.max(mx);
max_y = max_y.max(my);
}
self.reconstruct((x0, y0), log2, c, qp, ts, (max_x, max_y))
}
/// Decodes last_sig_coeff_{x,y}_prefix / suffix (before any scan-order swap).
fn last_sig_coeff_pos(&mut self, log2: u32, c: usize) -> (u32, u32) {
let cmax = (log2 << 1) - 1;
let (off, shift) = if c == 0 { (3 * (log2 - 2) + ((log2 - 1) >> 2), (log2 + 1) >> 2) } else { (15, log2 - 2) };
let mut px = 0;
@@ -1116,209 +1161,144 @@ impl<'a> SliceDecoder<'a> {
while py < cmax && self.dd(LAST_Y_PREFIX + (off + (py >> shift)) as usize) == 1 {
py += 1;
}
let mut lx = px;
if px > 3 {
let nb = (px >> 1) - 1;
lx = (1 << nb) * (2 + (px & 1)) + self.bypass_bits(nb);
let lx = self.last_pos_with_suffix(px);
let ly = self.last_pos_with_suffix(py);
(lx, ly)
}
fn last_pos_with_suffix(&mut self, prefix: u32) -> u32 {
if prefix > 3 {
let nb = (prefix >> 1) - 1;
(1 << nb) * (2 + (prefix & 1)) + self.bypass_bits(nb)
} else {
prefix
}
let mut ly = py;
if py > 3 {
let nb = (py >> 1) - 1;
ly = (1 << nb) * (2 + (py & 1)) + self.bypass_bits(nb);
}
/// scanIdx (7.4.9.11): 0 diagonal, 1 horizontal, 2 vertical.
fn scan_idx(&self, x0: i32, y0: i32, log2: u32, c: usize) -> usize {
if !(self.cu_intra && (log2 == 2 || (log2 == 3 && c == 0))) {
return 0;
}
// scanIdx (7.4.9.11)
let scan_idx = if self.cu_intra && (log2 == 2 || (log2 == 3 && c == 0)) {
let m = if c == 0 { self.pic.blk_at(x0, y0).ipm as u32 } else { self.intra_chroma_mode };
if (6..=14).contains(&m) {
2
} else if (22..=30).contains(&m) {
1
} else {
0
}
let m = if c == 0 { self.pic.blk_at(x0, y0).ipm as u32 } else { self.intra_chroma_mode };
if (6..=14).contains(&m) {
2
} else if (22..=30).contains(&m) {
1
} else {
0
};
if scan_idx == 2 {
std::mem::swap(&mut lx, &mut ly);
}
ensure!((lx as usize) < n && (ly as usize) < n, "last significant coefficient outside the block");
let log2sb = log2 - 2;
let sb_scan = scan_order(log2sb, scan_idx);
let pos_scan = &SCAN_4[scan_idx];
let sb_w = 1usize << log2sb;
let last_sb = sb_scan.iter().position(|&(x, y)| x as u32 == lx >> 2 && y as u32 == ly >> 2).unwrap_or(0);
let last_pos = pos_scan.iter().position(|&(x, y)| x as u32 == lx & 3 && y as u32 == ly & 3).unwrap_or(0);
self.coeffs[..n * n].fill(0);
let mut csbf = [0u8; 64];
let mut prev_g1: Option<u32> = None;
let sdh = self.pps.sign_data_hiding && !bypass;
let (mut max_x, mut max_y) = (0usize, 0usize);
let c_off_sig = if c == 0 { 0 } else { 27 };
for i in (0..=last_sb).rev() {
let (xs, ys) = (sb_scan[i].0 as usize, sb_scan[i].1 as usize);
let mut infer_dc = false;
let right = if xs + 1 < sb_w { csbf[ys * 8 + xs + 1] } else { 0 };
let below = if ys + 1 < sb_w { csbf[(ys + 1) * 8 + xs] } else { 0 };
if i < last_sb && i > 0 {
let inc = (right | below).min(1) as usize + if c > 0 { 2 } else { 0 };
csbf[ys * 8 + xs] = self.c.decode_decision(CODED_SUB_BLOCK + inc) as u8;
infer_dc = true;
} else {
csbf[ys * 8 + xs] = 1;
}
// significance map
let mut sig = [0u8; 16]; // scan positions n of significant coefficients, descending
let mut nsig = 0;
let start: i32 = if i == last_sb {
sig[0] = last_pos as u8;
}
/// Significance map of one coded sub-block: scan positions of the significant coefficients, in
/// descending order, and their count.
fn sig_coeff_flags(&mut self, t: &TbCtx, sb: &SubBlock, prev_csbf: u8, infer_dc: bool, last_pos: Option<usize>) -> ([u8; 16], usize) {
let pos_scan = &SCAN_4[t.scan_idx];
let c_off_sig = if t.c == 0 { 0 } else { 27 };
let mut infer_dc = infer_dc;
let mut sig = [0u8; 16];
let mut nsig = 0;
let start: i32 = match last_pos {
Some(lp) => {
sig[0] = lp as u8;
nsig = 1;
last_pos as i32 - 1
lp as i32 - 1
}
None => 15,
};
for np in (0..=start).rev() {
let (xp, yp) = (pos_scan[np as usize].0 as usize, pos_scan[np as usize].1 as usize);
if np > 0 || !infer_dc {
let ctx = sig_coeff_ctx(t, sb, prev_csbf, (xp, yp));
if self.c.decode_decision(SIG_COEFF + c_off_sig + ctx) == 1 {
sig[nsig] = np as u8;
nsig += 1;
infer_dc = false;
}
} else {
15
};
if csbf[ys * 8 + xs] != 0 {
let prev_csbf = right + (below << 1);
let mut np = start;
while np >= 0 {
let (xp, yp) = (pos_scan[np as usize].0 as usize, pos_scan[np as usize].1 as usize);
let (xc, yc) = (xs * 4 + xp, ys * 4 + yp);
if np > 0 || !infer_dc {
let sig_ctx = if log2 == 2 {
CTX_IDX_MAP[(yc << 2) + xc] as usize
} else if xc + yc == 0 {
0
} else {
let mut s = match prev_csbf {
0 => {
if xp + yp == 0 {
2
} else if xp + yp < 3 {
1
} else {
0
}
}
1 => {
if yp == 0 {
2
} else if yp == 1 {
1
} else {
0
}
}
2 => {
if xp == 0 {
2
} else if xp == 1 {
1
} else {
0
}
}
_ => 2,
};
if c == 0 {
if xs + ys > 0 {
s += 3;
}
s += if log2 == 3 { if scan_idx == 0 { 9 } else { 15 } } else { 21 };
} else {
s += if log2 == 3 { 9 } else { 12 };
}
s
};
if self.c.decode_decision(SIG_COEFF + c_off_sig + sig_ctx) == 1 {
sig[nsig] = np as u8;
nsig += 1;
infer_dc = false;
}
} else {
// np == 0 with inferSbDcSigCoeffFlag
sig[nsig] = 0;
nsig += 1;
}
np -= 1;
}
}
if nsig == 0 {
continue;
}
// greater1 / greater2 flags
let mut ctx_set = if i == 0 || c > 0 { 0 } else { 2 };
if let Some(g) = prev_g1
&& g == 0
{
ctx_set += 1;
}
let mut g1ctx = 1u32;
let mut gt1 = [0u8; 16];
let mut first_g1: Option<usize> = None;
let c_off_g1 = if c > 0 { 16 } else { 0 };
for k in 0..nsig.min(8) {
let inc = ctx_set * 4 + g1ctx.min(3) as usize + c_off_g1;
let f = self.c.decode_decision(GT1 + inc);
gt1[k] = f as u8;
if f == 1 {
g1ctx = 0;
if first_g1.is_none() {
first_g1 = Some(k);
}
} else if g1ctx > 0 {
g1ctx += 1;
}
}
prev_g1 = Some(g1ctx);
let mut gt2 = 0u8;
if let Some(k) = first_g1 {
gt2 = self.c.decode_decision(GT2 + ctx_set + if c > 0 { 4 } else { 0 }) as u8;
let _ = k;
}
// signs
let last_sig_pos = sig[0] as i32;
let first_sig_pos = sig[nsig - 1] as i32;
let sign_hidden = sdh && last_sig_pos - first_sig_pos > 3;
let nsigns = if sign_hidden { nsig - 1 } else { nsig };
let mut signs = if nsigns > 0 { self.bypass_bits(nsigns as u32) << (32 - nsigns) } else { 0 };
// remaining levels
let mut rice = 0u32;
let mut sum_abs = 0i32;
for k in 0..nsig {
let mut base = 1 + gt1[k] as i32;
if Some(k) == first_g1 {
base += gt2 as i32;
}
let thresh = if k < 8 { if Some(k) == first_g1 { 3 } else { 2 } } else { 1 };
let mut level = base;
if base == thresh {
let rem = self.coeff_abs_level_remaining(rice)?;
level = base + rem;
if level > 3 * (1 << rice) {
rice = (rice + 1).min(4);
}
}
let np = sig[k] as usize;
let (xc, yc) = (xs * 4 + pos_scan[np].0 as usize, ys * 4 + pos_scan[np].1 as usize);
let mut v = level;
if !(sign_hidden && k == nsig - 1) {
if signs & 0x8000_0000 != 0 {
v = -v;
}
signs <<= 1;
}
if sign_hidden {
sum_abs += level;
if k == nsig - 1 && sum_abs & 1 == 1 {
v = -v;
}
}
self.coeffs[yc * n + xc] = v;
max_x = max_x.max(xc);
max_y = max_y.max(yc);
// np == 0 with inferSbDcSigCoeffFlag
sig[nsig] = 0;
nsig += 1;
}
}
self.reconstruct((x0, y0), log2, c, qp, ts, (max_x, max_y))
(sig, nsig)
}
/// coeff_abs_level_greater1_flag / greater2_flag of one sub-block with `nsig` significant coefficients.
fn greater_flags(&mut self, t: &TbCtx, sb_index: usize, nsig: usize, prev_g1: &mut Option<u32>) -> GreaterFlags {
let mut ctx_set = if sb_index == 0 || t.c > 0 { 0 } else { 2 };
if *prev_g1 == Some(0) {
ctx_set += 1;
}
let mut g1ctx = 1u32;
let mut g = GreaterFlags { gt1: [0u8; 16], first_g1: None, gt2: 0 };
let c_off_g1 = if t.c > 0 { 16 } else { 0 };
for k in 0..nsig.min(8) {
let inc = ctx_set * 4 + g1ctx.min(3) as usize + c_off_g1;
let f = self.c.decode_decision(GT1 + inc);
g.gt1[k] = f as u8;
if f == 1 {
g1ctx = 0;
if g.first_g1.is_none() {
g.first_g1 = Some(k);
}
} else if g1ctx > 0 {
g1ctx += 1;
}
}
*prev_g1 = Some(g1ctx);
if g.first_g1.is_some() {
g.gt2 = self.c.decode_decision(GT2 + ctx_set + if t.c > 0 { 4 } else { 0 }) as u8;
}
g
}
/// Reads signs and remaining levels of one sub-block and stores the coefficients. Returns the
/// largest x and y coefficient position written.
fn store_levels(&mut self, t: &TbCtx, sb: &SubBlock, sig: &[u8], g: &GreaterFlags) -> Result<(usize, usize)> {
let nsig = sig.len();
let n = 1usize << t.log2;
let pos_scan = &SCAN_4[t.scan_idx];
let sign_hidden = t.sdh && sig[0] as i32 - sig[nsig - 1] as i32 > 3;
let nsigns = if sign_hidden { nsig - 1 } else { nsig };
let mut signs = if nsigns > 0 { self.bypass_bits(nsigns as u32) << (32 - nsigns) } else { 0 };
let mut rice = 0u32;
let mut sum_abs = 0i32;
let (mut max_x, mut max_y) = (0usize, 0usize);
for k in 0..nsig {
let mut base = 1 + g.gt1[k] as i32;
if Some(k) == g.first_g1 {
base += g.gt2 as i32;
}
let thresh = if k < 8 { if Some(k) == g.first_g1 { 3 } else { 2 } } else { 1 };
let mut level = base;
if base == thresh {
let rem = self.coeff_abs_level_remaining(rice)?;
level = base + rem;
if level > 3 * (1 << rice) {
rice = (rice + 1).min(4);
}
}
let np = sig[k] as usize;
let (xc, yc) = (sb.xs * 4 + pos_scan[np].0 as usize, sb.ys * 4 + pos_scan[np].1 as usize);
let mut v = level;
if !(sign_hidden && k == nsig - 1) {
if signs & 0x8000_0000 != 0 {
v = -v;
}
signs <<= 1;
}
if sign_hidden {
sum_abs += level;
if k == nsig - 1 && sum_abs & 1 == 1 {
v = -v;
}
}
self.coeffs[yc * n + xc] = v;
max_x = max_x.max(xc);
max_y = max_y.max(yc);
}
Ok((max_x, max_y))
}
fn coeff_abs_level_remaining(&mut self, rice: u32) -> Result<i32> {
@@ -1565,3 +1545,71 @@ impl<'a> SliceDecoder<'a> {
}
}
}
/// Per-transform-block parameters of residual coding.
struct TbCtx {
c: usize,
log2: u32,
scan_idx: usize,
sdh: bool,
}
/// Position of a 4x4 sub-block in the sub-block grid.
struct SubBlock {
xs: usize,
ys: usize,
}
/// Greater-than-1 / greater-than-2 flags of one sub-block.
struct GreaterFlags {
gt1: [u8; 16],
first_g1: Option<usize>,
gt2: u8,
}
/// sigCtx (9.3.4.2.5) for the coefficient at (`xp`, `yp`) inside the sub-block.
fn sig_coeff_ctx(t: &TbCtx, sb: &SubBlock, prev_csbf: u8, (xp, yp): (usize, usize)) -> usize {
let (xc, yc) = (sb.xs * 4 + xp, sb.ys * 4 + yp);
if t.log2 == 2 {
CTX_IDX_MAP[(yc << 2) + xc] as usize
} else if xc + yc == 0 {
0
} else {
sig_ctx_neighbourhood(prev_csbf, xp, yp) + sig_ctx_offset(t, sb.xs + sb.ys > 0)
}
}
/// Base sigCtx from the coded-sub-block flags of the right and below neighbours.
fn sig_ctx_neighbourhood(prev_csbf: u8, xp: usize, yp: usize) -> usize {
let near = |v: usize| match v {
0 => 2,
1 => 1,
_ => 0,
};
match prev_csbf {
0 => {
if xp + yp == 0 {
2
} else if xp + yp < 3 {
1
} else {
0
}
}
1 => near(yp),
2 => near(xp),
_ => 2,
}
}
/// Offset added to sigCtx for the block size, colour component and sub-block position.
fn sig_ctx_offset(t: &TbCtx, not_first_sb: bool) -> usize {
if t.c == 0 {
let size_off = if t.log2 == 3 { if t.scan_idx == 0 { 9 } else { 15 } } else { 21 };
size_off + if not_first_sb { 3 } else { 0 }
} else if t.log2 == 3 {
9
} else {
12
}
}