Compare commits

..
Author SHA1 Message Date
Dylan M. TaylorandClaude Sonnet 5.5 e9debd30bb refactor(h264,hevc): reduce parameter counts (S107)
Group geometry/size/weight parameters into tuples and a PbGeom struct.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 08:47:31 +00:00
7 changed files with 211 additions and 275 deletions
+152 -199
View File
@@ -3,7 +3,7 @@
use crate::error::{Result, ensure};
use crate::picture::{FrameRef, RefPic};
use crate::slice::{Mmco, RefPicListMod, SliceHeader, SliceType};
use crate::slice::{Mmco, SliceHeader, SliceType};
use std::sync::Arc;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -174,103 +174,6 @@ impl Dpb {
}
}
/// Initial reference picture lists (8.2.4.2) as DPB entries.
fn initial_entry_lists<'a>(
sh: &SliceHeader,
cur_poc: i32,
short: &[&'a DpbEntry],
long: &[&'a DpbEntry],
pic_num: impl Fn(&DpbEntry) -> i32,
) -> [Vec<&'a DpbEntry>; 2] {
let mut entry_lists: [Vec<&'a DpbEntry>; 2] = [Vec::new(), Vec::new()];
if sh.slice_type != SliceType::B {
let mut s = short.to_vec();
s.sort_by_key(|e| std::cmp::Reverse(pic_num(e)));
entry_lists[0] = s.into_iter().chain(long.iter().copied()).collect();
} else {
let mut before: Vec<&'a DpbEntry> = short.iter().copied().filter(|e| e.poc < cur_poc).collect();
let mut after: Vec<&'a DpbEntry> = short.iter().copied().filter(|e| e.poc > cur_poc).collect();
before.sort_by_key(|e| std::cmp::Reverse(e.poc));
after.sort_by_key(|e| e.poc);
entry_lists[0] = before.iter().chain(after.iter()).chain(long.iter()).copied().collect();
entry_lists[1] = after.iter().chain(before.iter()).chain(long.iter()).copied().collect();
if entry_lists[1].len() > 1 && entry_lists[0].len() == entry_lists[1].len() {
let same = entry_lists[0].iter().zip(entry_lists[1].iter()).all(|(a, b)| std::ptr::eq(*a, *b));
if same {
entry_lists[1].swap(0, 1);
}
}
}
entry_lists
}
/// Reference picture list modification (8.2.4.3) of one list; `n` is num_ref_idx_active.
fn modify_ref_list<'a>(
list: &mut Vec<Option<&'a DpbEntry>>,
mods: &[RefPicListMod],
n: usize,
cur_fn: u32,
max_frame_num: u32,
short: &[&'a DpbEntry],
long: &[&'a DpbEntry],
) -> Result<()> {
let max_pic_num = max_frame_num as i32;
let curr_pic_num = cur_fn as i32;
let mut pred = curr_pic_num;
let mut ref_idx = 0usize;
for m in mods {
ensure!(ref_idx < n, "too many ref_pic_list_modification entries");
list.push(None); // temporarily one longer
let (target, is_long): (Option<&DpbEntry>, bool) = match m.idc {
0 | 1 => {
let d = m.value as i32 + 1;
let no_wrap = if m.idc == 0 {
if pred - d < 0 { pred - d + max_pic_num } else { pred - d }
} else if pred + d >= max_pic_num {
pred + d - max_pic_num
} else {
pred + d
};
pred = no_wrap;
let pn = if no_wrap > curr_pic_num { no_wrap - max_pic_num } else { no_wrap };
(short.iter().copied().find(|e| Self::frame_num_wrap(e, cur_fn, max_frame_num) == pn), false)
}
2 => (long.iter().copied().find(|e| e.long_term_frame_idx == m.value), true),
_ => continue,
};
let Some(target) = target else {
// Missing picture: keep the list unchanged (error concealment).
list.pop();
ref_idx += 1;
continue;
};
for c in (ref_idx + 1..=n).rev() {
list[c] = list[c - 1];
}
list[ref_idx] = Some(target);
ref_idx += 1;
let mut nidx = ref_idx;
for c in ref_idx..=n {
let keep = match list[c] {
None => true,
Some(e) => {
if is_long {
!(e.mark == RefMark::Long && e.long_term_frame_idx == target.long_term_frame_idx)
} else {
!(e.mark == RefMark::Short && std::ptr::eq(e, target))
}
}
};
if keep {
list[nidx] = list[c];
nidx += 1;
}
}
list.truncate(n);
}
Ok(())
}
/// Initial reference picture lists (8.2.4.2) + modification (8.2.4.3) for a frame slice.
pub fn build_ref_lists(&self, sh: &SliceHeader, cur_poc: i32, max_frame_num: u32) -> Result<[Vec<RefPic>; 2]> {
let mut lists: [Vec<RefPic>; 2] = [Vec::new(), Vec::new()];
@@ -283,7 +186,25 @@ impl Dpb {
let mut long: Vec<&DpbEntry> = self.entries.iter().filter(|e| e.mark == RefMark::Long).collect();
long.sort_by_key(|e| e.long_term_frame_idx);
let to_ref = |e: &&DpbEntry| RefPic { frame: e.frame.clone(), long_term: e.mark == RefMark::Long };
let entry_lists = Self::initial_entry_lists(sh, cur_poc, &short, &long, pic_num);
let mut entry_lists: [Vec<&DpbEntry>; 2] = [Vec::new(), Vec::new()];
if sh.slice_type != SliceType::B {
let mut s = short.clone();
s.sort_by_key(|e| std::cmp::Reverse(pic_num(e)));
entry_lists[0] = s.into_iter().chain(long.iter().copied()).collect();
} else {
let mut before: Vec<&DpbEntry> = short.iter().copied().filter(|e| e.poc < cur_poc).collect();
let mut after: Vec<&DpbEntry> = short.iter().copied().filter(|e| e.poc > cur_poc).collect();
before.sort_by_key(|e| std::cmp::Reverse(e.poc));
after.sort_by_key(|e| e.poc);
entry_lists[0] = before.iter().chain(after.iter()).chain(long.iter()).copied().collect();
entry_lists[1] = after.iter().chain(before.iter()).chain(long.iter()).copied().collect();
if entry_lists[1].len() > 1 && entry_lists[0].len() == entry_lists[1].len() {
let same = entry_lists[0].iter().zip(entry_lists[1].iter()).all(|(a, b)| std::ptr::eq(*a, *b));
if same {
entry_lists[1].swap(0, 1);
}
}
}
let nlists = if sh.slice_type == SliceType::B { 2 } else { 1 };
for l in 0..nlists {
let n = sh.num_ref_idx_active[l] as usize;
@@ -291,7 +212,60 @@ impl Dpb {
list.truncate(n);
list.resize(n, None);
if !sh.ref_pic_list_mod[l].is_empty() {
Self::modify_ref_list(&mut list, &sh.ref_pic_list_mod[l], n, cur_fn, max_frame_num, &short, &long)?;
let max_pic_num = max_frame_num as i32;
let curr_pic_num = cur_fn as i32;
let mut pred = curr_pic_num;
let mut ref_idx = 0usize;
for m in &sh.ref_pic_list_mod[l] {
ensure!(ref_idx < n, "too many ref_pic_list_modification entries");
list.push(None); // temporarily one longer
let (target, is_long): (Option<&DpbEntry>, bool) = match m.idc {
0 | 1 => {
let d = m.value as i32 + 1;
let no_wrap = if m.idc == 0 {
if pred - d < 0 { pred - d + max_pic_num } else { pred - d }
} else if pred + d >= max_pic_num {
pred + d - max_pic_num
} else {
pred + d
};
pred = no_wrap;
let pn = if no_wrap > curr_pic_num { no_wrap - max_pic_num } else { no_wrap };
(short.iter().copied().find(|e| pic_num(e) == pn), false)
}
2 => (long.iter().copied().find(|e| e.long_term_frame_idx == m.value), true),
_ => continue,
};
let Some(target) = target else {
// Missing picture: keep the list unchanged (error concealment).
list.pop();
ref_idx += 1;
continue;
};
for c in (ref_idx + 1..=n).rev() {
list[c] = list[c - 1];
}
list[ref_idx] = Some(target);
ref_idx += 1;
let mut nidx = ref_idx;
for c in ref_idx..=n {
let keep = match list[c] {
None => true,
Some(e) => {
if is_long {
!(e.mark == RefMark::Long && e.long_term_frame_idx == target.long_term_frame_idx)
} else {
!(e.mark == RefMark::Short && std::ptr::eq(e, target))
}
}
};
if keep {
list[nidx] = list[c];
nidx += 1;
}
}
list.truncate(n);
}
}
// Fill missing entries (should not happen in conforming streams) with the first valid entry.
let fallback = list.iter().flatten().next().copied().or_else(|| self.entries.last());
@@ -301,81 +275,85 @@ impl Dpb {
Ok(lists)
}
/// One memory management control operation; returns true for MMCO 5.
fn apply_mmco(&mut self, m: &Mmco, cur_frame_num: u32, max_frame_num: u32, cur_long: &mut Option<u32>) -> bool {
let mut had5 = false;
let curr_pic_num = cur_frame_num as i32;
match m.op {
1 => {
let pn = curr_pic_num - (m.difference_of_pic_nums_minus1 as i32 + 1);
for e in &mut self.entries {
if e.mark == RefMark::Short && Self::frame_num_wrap(e, cur_frame_num, max_frame_num) == pn {
e.mark = RefMark::Unused;
}
}
}
2 => {
for e in &mut self.entries {
if e.mark == RefMark::Long && e.long_term_frame_idx == m.long_term_pic_num {
e.mark = RefMark::Unused;
}
}
}
3 => {
let pn = curr_pic_num - (m.difference_of_pic_nums_minus1 as i32 + 1);
for e in &mut self.entries {
if e.mark == RefMark::Long && e.long_term_frame_idx == m.long_term_frame_idx {
e.mark = RefMark::Unused;
}
}
for e in &mut self.entries {
if e.mark == RefMark::Short && Self::frame_num_wrap(e, cur_frame_num, max_frame_num) == pn {
e.mark = RefMark::Long;
e.long_term_frame_idx = m.long_term_frame_idx;
}
}
}
4 => {
let max = m.max_long_term_frame_idx_plus1;
for e in &mut self.entries {
if e.mark == RefMark::Long && (max == 0 || e.long_term_frame_idx > max - 1) {
e.mark = RefMark::Unused;
}
}
self.max_long_term_frame_idx = if max == 0 { None } else { Some(max - 1) };
}
5 => {
for e in &mut self.entries {
e.mark = RefMark::Unused;
}
self.max_long_term_frame_idx = None;
had5 = true;
}
6 => {
for e in &mut self.entries {
if e.mark == RefMark::Long && e.long_term_frame_idx == m.long_term_frame_idx {
e.mark = RefMark::Unused;
}
}
*cur_long = Some(m.long_term_frame_idx);
}
_ => {}
}
had5
}
/// Adaptive memory control (8.2.5.4). Returns true if MMCO 5 was executed.
fn apply_mmcos(&mut self, mmcos: &[Mmco], cur_frame_num: u32, max_frame_num: u32, cur_long: &mut Option<u32>) -> bool {
let mut had5 = false;
let curr_pic_num = cur_frame_num as i32;
for m in mmcos {
had5 |= self.apply_mmco(m, cur_frame_num, max_frame_num, cur_long);
match m.op {
1 => {
let pn = curr_pic_num - (m.difference_of_pic_nums_minus1 as i32 + 1);
for e in &mut self.entries {
if e.mark == RefMark::Short && Self::frame_num_wrap(e, cur_frame_num, max_frame_num) == pn {
e.mark = RefMark::Unused;
}
}
}
2 => {
for e in &mut self.entries {
if e.mark == RefMark::Long && e.long_term_frame_idx == m.long_term_pic_num {
e.mark = RefMark::Unused;
}
}
}
3 => {
let pn = curr_pic_num - (m.difference_of_pic_nums_minus1 as i32 + 1);
for e in &mut self.entries {
if e.mark == RefMark::Long && e.long_term_frame_idx == m.long_term_frame_idx {
e.mark = RefMark::Unused;
}
}
for e in &mut self.entries {
if e.mark == RefMark::Short && Self::frame_num_wrap(e, cur_frame_num, max_frame_num) == pn {
e.mark = RefMark::Long;
e.long_term_frame_idx = m.long_term_frame_idx;
}
}
}
4 => {
let max = m.max_long_term_frame_idx_plus1;
for e in &mut self.entries {
if e.mark == RefMark::Long && (max == 0 || e.long_term_frame_idx > max - 1) {
e.mark = RefMark::Unused;
}
}
self.max_long_term_frame_idx = if max == 0 { None } else { Some(max - 1) };
}
5 => {
for e in &mut self.entries {
e.mark = RefMark::Unused;
}
self.max_long_term_frame_idx = None;
had5 = true;
}
6 => {
for e in &mut self.entries {
if e.mark == RefMark::Long && e.long_term_frame_idx == m.long_term_frame_idx {
e.mark = RefMark::Unused;
}
}
*cur_long = Some(m.long_term_frame_idx);
}
_ => {}
}
}
self.prune();
had5
}
/// Reference marking of the current picture (8.2.5); returns (mark, long-term idx, MMCO 5 executed).
fn mark_current(&mut self, sh: &SliceHeader, max_frame_num: u32, max_num_ref_frames: usize) -> (RefMark, u32, bool) {
/// Reference marking for the just-decoded picture and insertion into the DPB with output bumping.
/// Returns pictures ready for output.
#[allow(clippy::too_many_arguments)]
pub fn store_picture(
&mut self,
sh: &SliceHeader,
frame: FrameRef,
poc: i32,
max_frame_num: u32,
max_num_ref_frames: usize,
meta: Arc<OutputMeta>,
out: &mut Vec<Output>,
) {
let mut mark = RefMark::Unused;
let mut long_idx = 0;
let mut had5 = false;
@@ -407,12 +385,12 @@ impl Dpb {
}
}
}
(mark, long_idx, had5)
}
/// Bumping until there is space (C.4.5.1 / C.4.5.2). Returns true when the (non-reference) current
/// picture has the smallest POC and is to be output directly instead of being stored.
fn bump_for_space(&mut self, mark: RefMark, poc: i32, out: &mut Vec<Output>) -> bool {
if had5 {
// All earlier pictures are output before the current one (C.4.4).
self.flush(out);
}
let frame_num = if had5 { 0 } else { sh.frame_num };
// Bumping until there is space (C.4.5.1 / C.4.5.2).
if mark == RefMark::Unused {
loop {
let waiting = self.entries.len();
@@ -422,7 +400,8 @@ impl Dpb {
// non-reference picture with the smallest POC is output directly
let min_poc = self.entries.iter().filter(|e| e.needed_for_output).map(|e| e.poc).min();
if min_poc.is_none_or(|m| poc < m) {
return true;
out.push(Output { frame, poc, meta });
return;
}
if !self.bump(out) {
break;
@@ -435,32 +414,6 @@ impl Dpb {
}
}
}
false
}
/// Reference marking for the just-decoded picture and insertion into the DPB with output bumping.
/// Returns pictures ready for output.
#[allow(clippy::too_many_arguments)]
pub fn store_picture(
&mut self,
sh: &SliceHeader,
frame: FrameRef,
poc: i32,
max_frame_num: u32,
max_num_ref_frames: usize,
meta: Arc<OutputMeta>,
out: &mut Vec<Output>,
) {
let (mark, long_idx, had5) = self.mark_current(sh, max_frame_num, max_num_ref_frames);
if had5 {
// All earlier pictures are output before the current one (C.4.4).
self.flush(out);
}
let frame_num = if had5 { 0 } else { sh.frame_num };
if self.bump_for_space(mark, poc, out) {
out.push(Output { frame, poc, meta });
return;
}
self.entries.push(DpbEntry {
frame,
poc,
+1 -1
View File
@@ -250,7 +250,7 @@ impl Frame {
/// Copy the w x h window of chroma component `c` at (x0, y0) (clamped) into `out`.
#[inline]
pub fn chroma_window(&self, c: usize, x0: i32, y0: i32, w: usize, h: usize, out: &mut [u8], os: usize) {
pub fn chroma_window(&self, c: usize, (x0, y0): (i32, i32), (w, h): (usize, usize), out: &mut [u8], os: usize) {
let (cw, ch) = (self.cwidth, self.cheight);
for r in 0..h {
let yy = (y0 + r as i32).clamp(0, ch as i32 - 1) as usize;
+1 -1
View File
@@ -232,7 +232,7 @@ fn predict_block(f: &Frame, mv: [i16; 2], px: usize, py: usize, bw: usize, bh: u
let (fx, fy) = ((mv[0] & 7) as u32, (mv[1] & 7) as u32);
for (comp, out) in c.into_iter().enumerate() {
let mut w = [0u8; 16 * 9];
f.chroma_window(comp, cx, cy, cw + 1, ch + 1, &mut w, 16);
f.chroma_window(comp, (cx, cy), (cw + 1, ch + 1), &mut w, 16);
inter::mc_chroma_win(&w, 16, fx, fy, cw, ch, out, cs);
}
}
+4 -9
View File
@@ -128,7 +128,7 @@ pub fn mc_chroma(f: &Frame, c: usize, x: i32, y: i32, mv: [i16; 2], w: usize, h:
let yi = y + (mv[1] as i32 >> 3);
let shift1 = bd.min(12) - 8;
let shift3 = 14 - bd;
f.chroma_window(c, xi - 1, yi - 1, w + 3, h + 3, &mut sc.win, WIN);
f.chroma_window(c, (xi - 1, yi - 1), (w + 3, h + 3), &mut sc.win, WIN);
interpolate::<4>(&sc.win, &mut sc.tmp, fx, fy, &CHROMA_FILTER[fx], &CHROMA_FILTER[fy], w, h, shift1, shift3, out);
}
@@ -158,7 +158,7 @@ pub fn put_bi(p0: &[i16], p1: &[i16], w: usize, h: usize, bd: u32, dst: &mut [u1
}
/// Explicit weighted prediction, one list (8-265). `o` is the offset already scaled to the bit depth.
pub fn put_weighted_uni(p: &[i16], w: usize, h: usize, bd: u32, log2wd: u32, wt: i32, o: i32, dst: &mut [u16], ds: usize) {
pub fn put_weighted_uni(p: &[i16], (w, h): (usize, usize), bd: u32, (log2wd, wt, o): (u32, i32, i32), dst: &mut [u16], ds: usize) {
let max = (1i32 << bd) - 1;
for r in 0..h {
for c in 0..w {
@@ -173,14 +173,9 @@ pub fn put_weighted_uni(p: &[i16], w: usize, h: usize, bd: u32, log2wd: u32, wt:
pub fn put_weighted_bi(
p0: &[i16],
p1: &[i16],
w: usize,
h: usize,
(w, h): (usize, usize),
bd: u32,
log2wd: u32,
w0: i32,
w1: i32,
o0: i32,
o1: i32,
(log2wd, w0, w1, o0, o1): (u32, i32, i32, i32, i32),
dst: &mut [u16],
ds: usize,
) {
+23 -34
View File
@@ -36,9 +36,23 @@ fn same_motion(a: &MvField, b: &MvField) -> bool {
true
}
/// Coding block and prediction block geometry (6.4.2): coding block (xc, yc, ncb), prediction block (xp, yp, w, h, part_idx).
#[derive(Clone, Copy)]
pub struct PbGeom {
pub xc: i32,
pub yc: i32,
pub ncb: i32,
pub xp: i32,
pub yp: i32,
pub w: i32,
pub h: i32,
pub part_idx: usize,
}
impl<'a> SliceDecoder<'a> {
/// Prediction block availability (6.4.2).
fn pb_avail(&self, xc: i32, yc: i32, ncb: i32, xp: i32, yp: i32, w: i32, h: i32, part_idx: usize, xn: i32, yn: i32) -> bool {
fn pb_avail(&self, g: &PbGeom, xn: i32, yn: i32) -> bool {
let PbGeom { xc, yc, ncb, xp, yp, w, h, part_idx } = *g;
let same_cb = xc <= xn && yc <= yn && xc + ncb > xn && yc + ncb > yn;
let avail = if !same_cb {
self.pic.zavail(xp, yp, xn, yn, self.slice_addr)
@@ -59,23 +73,13 @@ impl<'a> SliceDecoder<'a> {
}
/// Merge mode motion (8.5.3.2.2).
pub fn derive_merge(
&self,
xc: i32,
yc: i32,
ncb: i32,
xp0: i32,
yp0: i32,
w0: i32,
h0: i32,
part_idx0: usize,
part: PartMode,
merge_idx: usize,
) -> MvField {
pub fn derive_merge(&self, g: PbGeom, part: PartMode, merge_idx: usize) -> MvField {
let PbGeom { xc, yc, ncb, xp: xp0, yp: yp0, w: w0, h: h0, part_idx: part_idx0 } = g;
let pml = self.pps.log2_parallel_merge_level;
let (xp, yp, w, h, part_idx) = if pml > 2 && ncb == 8 { (xc, yc, ncb, ncb, 0) } else { (xp0, yp0, w0, h0, part_idx0) };
let g = PbGeom { xc, yc, ncb, xp, yp, w, h, part_idx };
let same_mer = |xn: i32, yn: i32| (xp >> pml) == (xn >> pml) && (yp >> pml) == (yn >> pml);
let avail = |xn: i32, yn: i32| self.pb_avail(xc, yc, ncb, xp, yp, w, h, part_idx, xn, yn) && !same_mer(xn, yn);
let avail = |xn: i32, yn: i32| self.pb_avail(&g, xn, yn) && !same_mer(xn, yn);
let mut list: [MvField; 5] = [MvField::default(); 5];
let mut n = 0;
let max = self.sh.max_num_merge_cand as usize;
@@ -237,20 +241,8 @@ impl<'a> SliceDecoder<'a> {
}
/// AMVP predictor (8.5.3.2.6, 8.5.3.2.7).
pub fn derive_amvp(
&self,
xc: i32,
yc: i32,
ncb: i32,
xp: i32,
yp: i32,
w: i32,
h: i32,
part_idx: usize,
l: usize,
ref_idx: usize,
mvp_flag: usize,
) -> [i16; 2] {
pub fn derive_amvp(&self, g: PbGeom, l: usize, ref_idx: usize, mvp_flag: usize) -> [i16; 2] {
let PbGeom { xp, yp, w, h, .. } = g;
let target = &self.refs[l][ref_idx];
let (tpoc, tlt) = (target.poc, target.long_term);
let cur_poc = self.pic.poc;
@@ -277,10 +269,7 @@ impl<'a> SliceDecoder<'a> {
pick.map(|(mv, r)| if r.poc != tpoc && !r.long_term && !tlt { scale_mv(mv, cur_poc - r.poc, cur_poc - tpoc) } else { mv })
};
let pa = [(xp - 1, yp + h), (xp - 1, yp + h - 1)];
let av_a = [
self.pb_avail(xc, yc, ncb, xp, yp, w, h, part_idx, pa[0].0, pa[0].1),
self.pb_avail(xc, yc, ncb, xp, yp, w, h, part_idx, pa[1].0, pa[1].1),
];
let av_a = [self.pb_avail(&g, pa[0].0, pa[0].1), self.pb_avail(&g, pa[1].0, pa[1].1)];
let is_scaled = av_a[0] || av_a[1];
let mut a = None;
for k in 0..2 {
@@ -296,7 +285,7 @@ impl<'a> SliceDecoder<'a> {
}
}
let pb = [(xp + w, yp - 1), (xp + w - 1, yp - 1), (xp - 1, yp - 1)];
let av_b = [0, 1, 2].map(|k| self.pb_avail(xc, yc, ncb, xp, yp, w, h, part_idx, pb[k].0, pb[k].1));
let av_b = [0, 1, 2].map(|k| self.pb_avail(&g, pb[k].0, pb[k].1));
let mut b = None;
for k in 0..3 {
if av_b[k] && b.is_none() {
+1 -1
View File
@@ -125,7 +125,7 @@ impl Frame {
}
/// Copy a w x h window of chroma component `c` (0 = Cb, 1 = Cr) with edge replication.
pub fn chroma_window(&self, c: usize, x0: i32, y0: i32, w: usize, h: usize, out: &mut [i16], os: usize) {
pub fn chroma_window(&self, c: usize, (x0, y0): (i32, i32), (w, h): (usize, usize), out: &mut [i16], os: usize) {
let (cw, ch) = (self.cwidth as i32, self.cheight as i32);
let sh = self.log2_ctb - 1;
let mask = (1i32 << sh) - 1;
+29 -30
View File
@@ -7,6 +7,7 @@ use crate::cabac::{Cabac, Contexts, init_contexts};
use crate::error::{Result, ensure, invalid};
use crate::inter;
use crate::intra::{self, Refs};
use crate::mvpred::PbGeom;
use crate::params::{Layout, Pps, Sps};
use crate::picture::{FrameRef, RefPic};
use crate::slice::{SliceHeader, SliceType};
@@ -668,7 +669,7 @@ impl<'a> SliceDecoder<'a> {
self.mark_edges(x0, y0, n, n, E_TU_V | E_PU_V, E_TU_H | E_PU_H);
if skip {
self.cu_intra = false;
self.prediction_unit(x0, y0, n, x0, y0, n, n, 0, PartMode::P2Nx2N, true)?;
self.prediction_unit(PbGeom { xc: x0, yc: y0, ncb: n, xp: x0, yp: y0, w: n, h: n, part_idx: 0 }, PartMode::P2Nx2N, true)?;
self.finish_cu(x0, y0, n);
return Ok(());
}
@@ -697,7 +698,7 @@ impl<'a> SliceDecoder<'a> {
}
self.parse_intra_modes(x0, y0, n, part)?;
self.max_trafo_depth = self.sps.max_th_depth_intra + self.intra_split as u32;
self.transform_tree(x0, y0, x0, y0, log2, 0, 0, [true, true])?;
self.transform_tree((x0, y0), (x0, y0), log2, 0, 0, [true, true])?;
} else {
self.intra_split = false;
let mut merge2nx2n = false;
@@ -714,7 +715,8 @@ impl<'a> SliceDecoder<'a> {
PartMode::PNxN => &[(0, 0, h, h), (h, 0, h, h), (0, h, h, h), (h, h, h, h)],
};
for (i, &(px, py, pw, ph)) in parts.iter().enumerate() {
let merge = self.prediction_unit(x0, y0, n, x0 + px, y0 + py, pw, ph, i, part, false)?;
let merge =
self.prediction_unit(PbGeom { xc: x0, yc: y0, ncb: n, xp: x0 + px, yp: y0 + py, w: pw, h: ph, part_idx: i }, part, false)?;
if part == PartMode::P2Nx2N {
merge2nx2n = merge;
}
@@ -728,7 +730,7 @@ impl<'a> SliceDecoder<'a> {
let root_cbf = if !merge2nx2n { self.dd(RQT_ROOT_CBF) == 1 } else { true };
if root_cbf {
self.max_trafo_depth = self.sps.max_th_depth_inter;
self.transform_tree(x0, y0, x0, y0, log2, 0, 0, [true, true])?;
self.transform_tree((x0, y0), (x0, y0), log2, 0, 0, [true, true])?;
}
}
self.finish_cu(x0, y0, n);
@@ -898,7 +900,7 @@ impl<'a> SliceDecoder<'a> {
Ok(())
}
fn transform_tree(&mut self, x0: i32, y0: i32, xb: i32, yb: i32, log2: u32, depth: u32, blk_idx: u32, parent_cbf_c: [bool; 2]) -> Result<()> {
fn transform_tree(&mut self, (x0, y0): (i32, i32), base: (i32, i32), log2: u32, depth: u32, blk_idx: u32, parent_cbf_c: [bool; 2]) -> Result<()> {
let split =
if log2 <= self.sps.log2_max_tb && log2 > self.sps.log2_min_tb && depth < self.max_trafo_depth && !(self.intra_split && depth == 0) {
self.dd(SPLIT_TRANSFORM + (5 - log2 as usize)) == 1
@@ -923,10 +925,10 @@ impl<'a> SliceDecoder<'a> {
}
if split {
let h = 1 << (log2 - 1);
self.transform_tree(x0, y0, x0, y0, log2 - 1, depth + 1, 0, cbf_c)?;
self.transform_tree(x0 + h, y0, x0, y0, log2 - 1, depth + 1, 1, cbf_c)?;
self.transform_tree(x0, y0 + h, x0, y0, log2 - 1, depth + 1, 2, cbf_c)?;
self.transform_tree(x0 + h, y0 + h, x0, y0, log2 - 1, depth + 1, 3, cbf_c)?;
self.transform_tree((x0, y0), (x0, y0), log2 - 1, depth + 1, 0, cbf_c)?;
self.transform_tree((x0 + h, y0), (x0, y0), log2 - 1, depth + 1, 1, cbf_c)?;
self.transform_tree((x0, y0 + h), (x0, y0), log2 - 1, depth + 1, 2, cbf_c)?;
self.transform_tree((x0 + h, y0 + h), (x0, y0), log2 - 1, depth + 1, 3, cbf_c)?;
return Ok(());
}
let cbf_luma =
@@ -935,10 +937,18 @@ impl<'a> SliceDecoder<'a> {
if depth > 0 {
self.mark_edges(x0, y0, n, n, E_TU_V, E_TU_H);
}
self.transform_unit(x0, y0, xb, yb, log2, blk_idx, cbf_luma, cbf_c)
self.transform_unit((x0, y0), base, log2, blk_idx, cbf_luma, cbf_c)
}
fn transform_unit(&mut self, x0: i32, y0: i32, xb: i32, yb: i32, log2: u32, blk_idx: u32, cbf_luma: bool, cbf_c: [bool; 2]) -> Result<()> {
fn transform_unit(
&mut self,
(x0, y0): (i32, i32),
(xb, yb): (i32, i32),
log2: u32,
blk_idx: u32,
cbf_luma: bool,
cbf_c: [bool; 2],
) -> Result<()> {
let n = 1i32 << log2;
let chroma_here = log2 > 2 || blk_idx == 3;
let cbf_chroma = cbf_c[0] || cbf_c[1];
@@ -1264,7 +1274,7 @@ impl<'a> SliceDecoder<'a> {
max_y = max_y.max(yc);
}
}
self.reconstruct(x0, y0, log2, c, qp, ts, max_x, max_y)
self.reconstruct((x0, y0), log2, c, qp, ts, (max_x, max_y))
}
fn coeff_abs_level_remaining(&mut self, rice: u32) -> Result<i32> {
@@ -1283,7 +1293,7 @@ impl<'a> SliceDecoder<'a> {
}
/// Scaling, transform and addition to the prediction.
fn reconstruct(&mut self, x0: i32, y0: i32, log2: u32, c: usize, qp: i32, ts: bool, max_x: usize, max_y: usize) -> Result<()> {
fn reconstruct(&mut self, (x0, y0): (i32, i32), log2: u32, c: usize, qp: i32, ts: bool, (max_x, max_y): (usize, usize)) -> Result<()> {
let n = 1usize << log2;
let bd = if c == 0 { self.pic.bd_y } else { self.pic.bd_c };
let coeffs = &mut self.coeffs[..n * n];
@@ -1335,19 +1345,8 @@ impl<'a> SliceDecoder<'a> {
}
/// prediction_unit(): parse, derive motion, store it and predict. Returns merge_flag.
fn prediction_unit(
&mut self,
xc: i32,
yc: i32,
ncb: i32,
xp: i32,
yp: i32,
w: i32,
h: i32,
part_idx: usize,
part: PartMode,
skip: bool,
) -> Result<bool> {
fn prediction_unit(&mut self, g: PbGeom, part: PartMode, skip: bool) -> Result<bool> {
let PbGeom { xc, yc, ncb, xp, yp, w, h, part_idx } = g;
let merge = if skip { true } else { self.dd(MERGE_FLAG) == 1 };
let mvf = if merge {
let idx = if self.sh.max_num_merge_cand > 1 {
@@ -1362,7 +1361,7 @@ impl<'a> SliceDecoder<'a> {
} else {
0
};
self.derive_merge(xc, yc, ncb, xp, yp, w, h, part_idx, part, idx as usize)
self.derive_merge(PbGeom { xc, yc, ncb, xp, yp, w, h, part_idx }, part, idx as usize)
} else {
let pred_idc = if self.sh.is_b() {
if w + h != 12 {
@@ -1406,7 +1405,7 @@ impl<'a> SliceDecoder<'a> {
if ref_idx[l] < 0 {
continue;
}
let mvp = self.derive_amvp(xc, yc, ncb, xp, yp, w, h, part_idx, l, ref_idx[l] as usize, mvp_flag[l] as usize);
let mvp = self.derive_amvp(PbGeom { xc, yc, ncb, xp, yp, w, h, part_idx }, l, ref_idx[l] as usize, mvp_flag[l] as usize);
// mvLX = (mvp + mvd) wrapped to 16 bits (8-94)
f.mv[l] = [(mvp[0] as i32 + mvd[l][0]) as i16, (mvp[1] as i32 + mvd[l][1]) as i16];
}
@@ -1504,11 +1503,11 @@ impl<'a> SliceDecoder<'a> {
if bi {
let (w0, o0) = get(0);
let (w1, o1) = get(1);
inter::put_weighted_bi(&self.pred0, &self.pred1, bw, bh, bd, log2wd, w0, w1, o0, o1, dst, stride);
inter::put_weighted_bi(&self.pred0, &self.pred1, (bw, bh), bd, (log2wd, w0, w1, o0, o1), dst, stride);
} else {
let l = if lists[0] { 0 } else { 1 };
let (wt, o) = get(l);
inter::put_weighted_uni(&self.pred0, bw, bh, bd, log2wd, wt, o, dst, stride);
inter::put_weighted_uni(&self.pred0, (bw, bh), bd, (log2wd, wt, o), dst, stride);
}
}
}