mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-28 12:36:56 -06:00
Refactor hevc for strict Clippy checks
This commit is contained in:
+190
-147
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user