mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-25 19:17:06 -06:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3613b2366a | ||
|
|
3418dec9e4 | ||
|
|
a78d9a9a19 | ||
|
|
560f80abe2 | ||
|
|
2aa0310e27 | ||
|
|
b6fd616977 | ||
|
|
9d23ff97b2 |
+78
-55
@@ -405,49 +405,35 @@ impl Decoder {
|
||||
r
|
||||
}
|
||||
|
||||
/// Whether an OBU belongs to the selected operating point (spec 7.5: OBUs of other layers are dropped).
|
||||
fn in_operating_point(&self, obu: &ObuUnit) -> bool {
|
||||
if obu.obu_type != OBU_SEQUENCE_HEADER_T
|
||||
&& obu.obu_type != OBU_TEMPORAL_DELIMITER_T
|
||||
&& obu.ext
|
||||
&& let Some(seq) = &self.seq
|
||||
&& seq.op_idc != 0
|
||||
{
|
||||
let idc = seq.op_idc;
|
||||
let in_t = (idc >> obu.temporal_id) & 1;
|
||||
let in_s = (idc >> (obu.spatial_id + 8)) & 1;
|
||||
if in_t == 0 || in_s == 0 {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_obus(&mut self, data: &[u8], out: &mut Vec<(Output, usize, u32)>) -> Result<()> {
|
||||
let mut tu = 0usize;
|
||||
let mut pos = 0;
|
||||
while pos < data.len() {
|
||||
let h = data[pos];
|
||||
if h & 0x80 != 0 {
|
||||
return Err(Error::Invalid("obu_forbidden_bit"));
|
||||
let obu = parse_obu_unit(data, pos)?;
|
||||
pos = obu.end;
|
||||
if !self.in_operating_point(&obu) {
|
||||
continue;
|
||||
}
|
||||
let obu_type = ((h >> 3) & 0xf) as u32;
|
||||
let ext = h & 4 != 0;
|
||||
let has_size = h & 2 != 0;
|
||||
let mut p = pos + 1;
|
||||
let (mut temporal_id, mut spatial_id) = (0, 0);
|
||||
if ext {
|
||||
let e = *data.get(p).ok_or(Error::Truncated)?;
|
||||
temporal_id = (e >> 5) as u32;
|
||||
spatial_id = ((e >> 3) & 3) as u32;
|
||||
p += 1;
|
||||
}
|
||||
let size = if has_size {
|
||||
let (v, n) = leb128(data.get(p..).ok_or(Error::Truncated)?)?;
|
||||
p += n;
|
||||
v as usize
|
||||
} else {
|
||||
data.len().checked_sub(p).ok_or(Error::Truncated)?
|
||||
};
|
||||
let end = p.checked_add(size).filter(|&e| e <= data.len()).ok_or(Error::Truncated)?;
|
||||
let payload = &data[p..end];
|
||||
pos = end;
|
||||
if obu_type != OBU_SEQUENCE_HEADER_T
|
||||
&& obu_type != OBU_TEMPORAL_DELIMITER_T
|
||||
&& ext
|
||||
&& let Some(seq) = &self.seq
|
||||
&& seq.op_idc != 0
|
||||
{
|
||||
let idc = seq.op_idc;
|
||||
let in_t = (idc >> temporal_id) & 1;
|
||||
let in_s = (idc >> (spatial_id + 8)) & 1;
|
||||
if in_t == 0 || in_s == 0 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match obu_type {
|
||||
let (payload, spatial_id) = (obu.payload, obu.spatial_id);
|
||||
match obu.obu_type {
|
||||
OBU_SEQUENCE_HEADER_T => {
|
||||
let s = SequenceHeader::parse(payload)?;
|
||||
self.seq = Some(s);
|
||||
@@ -457,27 +443,11 @@ impl Decoder {
|
||||
tu += 1;
|
||||
}
|
||||
OBU_FRAME_HEADER_T | OBU_REDUNDANT_FRAME_HEADER_T | OBU_FRAME_T => {
|
||||
if self.seen_frame_header {
|
||||
// frame_header_copy(): identical to the active header
|
||||
if obu_type != OBU_FRAME_T {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let mut r = BitReader::new(payload);
|
||||
let shown = self.frame_header(&mut r, temporal_id, spatial_id)?;
|
||||
if let Some(o) = shown {
|
||||
if let Some(o) = self.frame_obu(&obu)? {
|
||||
if out.iter().filter(|(o, _, _)| matches!(o, Output::Existing { .. })).count() >= 32 {
|
||||
return Err(Error::Invalid("too many frame outputs in chunk"));
|
||||
}
|
||||
out.push((o, tu, spatial_id));
|
||||
continue;
|
||||
}
|
||||
if obu_type == OBU_FRAME_T {
|
||||
r.byte_align();
|
||||
let rest = payload.get(r.byte_pos()..).ok_or(Error::Truncated)?;
|
||||
if let Some(o) = self.tile_group(rest)? {
|
||||
out.push((o, tu, spatial_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
OBU_TILE_GROUP_T => {
|
||||
@@ -492,6 +462,22 @@ impl Decoder {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A frame header or frame OBU: returns the picture it completes, if any.
|
||||
fn frame_obu(&mut self, obu: &ObuUnit) -> Result<Option<Output>> {
|
||||
// frame_header_copy(): identical to the active header
|
||||
if self.seen_frame_header && obu.obu_type != OBU_FRAME_T {
|
||||
return Ok(None);
|
||||
}
|
||||
let mut r = BitReader::new(obu.payload);
|
||||
let shown = self.frame_header(&mut r, obu.temporal_id, obu.spatial_id)?;
|
||||
if shown.is_some() || obu.obu_type != OBU_FRAME_T {
|
||||
return Ok(shown);
|
||||
}
|
||||
r.byte_align();
|
||||
let rest = obu.payload.get(r.byte_pos()..).ok_or(Error::Truncated)?;
|
||||
self.tile_group(rest)
|
||||
}
|
||||
|
||||
/// frame_header_obu( ): returns the output for show_existing_frame.
|
||||
fn frame_header(&mut self, r: &mut BitReader, temporal_id: u32, spatial_id: u32) -> Result<Option<Output>> {
|
||||
let seq = self.seq.clone().ok_or(Error::Invalid("frame before sequence header"))?;
|
||||
@@ -1017,6 +1003,43 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// One OBU: its header fields, payload and the position just past it.
|
||||
struct ObuUnit<'a> {
|
||||
obu_type: u32,
|
||||
ext: bool,
|
||||
temporal_id: u32,
|
||||
spatial_id: u32,
|
||||
payload: &'a [u8],
|
||||
end: usize,
|
||||
}
|
||||
|
||||
fn parse_obu_unit(data: &[u8], pos: usize) -> Result<ObuUnit<'_>> {
|
||||
let h = data[pos];
|
||||
if h & 0x80 != 0 {
|
||||
return Err(Error::Invalid("obu_forbidden_bit"));
|
||||
}
|
||||
let obu_type = ((h >> 3) & 0xf) as u32;
|
||||
let ext = h & 4 != 0;
|
||||
let has_size = h & 2 != 0;
|
||||
let mut p = pos + 1;
|
||||
let (mut temporal_id, mut spatial_id) = (0, 0);
|
||||
if ext {
|
||||
let e = *data.get(p).ok_or(Error::Truncated)?;
|
||||
temporal_id = (e >> 5) as u32;
|
||||
spatial_id = ((e >> 3) & 3) as u32;
|
||||
p += 1;
|
||||
}
|
||||
let size = if has_size {
|
||||
let (v, n) = leb128(data.get(p..).ok_or(Error::Truncated)?)?;
|
||||
p += n;
|
||||
v as usize
|
||||
} else {
|
||||
data.len().checked_sub(p).ok_or(Error::Truncated)?
|
||||
};
|
||||
let end = p.checked_add(size).filter(|&e| e <= data.len()).ok_or(Error::Truncated)?;
|
||||
Ok(ObuUnit { obu_type, ext, temporal_id, spatial_id, payload: &data[p..end], end })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod guard_tests {
|
||||
use super::*;
|
||||
|
||||
+313
-167
@@ -55,21 +55,79 @@ impl Rng {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply(pic: &mut Picture, g: &FilmGrainParams, seq: &SequenceHeader) {
|
||||
let _ = seq;
|
||||
let bd = pic.bit_depth as u32;
|
||||
let mono = pic.mono_chrome;
|
||||
let num_planes = if mono { 1 } else { 3 };
|
||||
let (sub_x, sub_y) = (pic.subsampling_x as usize, pic.subsampling_y as usize);
|
||||
let w = pic.width as usize;
|
||||
let h = pic.height as usize;
|
||||
let grain_center = 128i32 << (bd - 8);
|
||||
let grain_min = -grain_center;
|
||||
let grain_max = (256i32 << (bd - 8)) - 1 - grain_center;
|
||||
/// Picture-level parameters shared by the grain synthesis stages.
|
||||
struct GrainCtx<'a> {
|
||||
g: &'a FilmGrainParams,
|
||||
bd: u32,
|
||||
mono: bool,
|
||||
sub_x: usize,
|
||||
sub_y: usize,
|
||||
w: usize,
|
||||
h: usize,
|
||||
grain_min: i32,
|
||||
grain_max: i32,
|
||||
}
|
||||
|
||||
// Generate grain (7.18.3.3).
|
||||
let mut rng = Rng(g.grain_seed);
|
||||
let shift = 12 - bd + g.grain_scale_shift;
|
||||
impl GrainCtx<'_> {
|
||||
fn num_planes(&self) -> usize {
|
||||
if self.mono { 1 } else { 3 }
|
||||
}
|
||||
|
||||
fn grain_shift(&self) -> u32 {
|
||||
12 - self.bd + self.g.grain_scale_shift
|
||||
}
|
||||
|
||||
fn ar_shift(&self) -> u32 {
|
||||
self.g.ar_coeff_shift_minus_6 + 6
|
||||
}
|
||||
|
||||
fn lag(&self) -> i32 {
|
||||
self.g.ar_coeff_lag as i32
|
||||
}
|
||||
|
||||
fn stripe_w(&self) -> usize {
|
||||
self.w + 64
|
||||
}
|
||||
}
|
||||
|
||||
type GrainTemplate = Vec<[i32; 82]>;
|
||||
|
||||
/// The luma, Cb and Cr grain templates (7.18.3.3).
|
||||
struct Templates {
|
||||
luma: GrainTemplate,
|
||||
cb: GrainTemplate,
|
||||
cr: GrainTemplate,
|
||||
}
|
||||
|
||||
impl Templates {
|
||||
fn plane(&self, plane: usize) -> &GrainTemplate {
|
||||
match plane {
|
||||
0 => &self.luma,
|
||||
1 => &self.cb,
|
||||
_ => &self.cr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn luma_ar_sum(g: &FilmGrainParams, luma: &[[i32; 82]], lag: i32, y: usize, x: usize) -> i32 {
|
||||
let mut s = 0;
|
||||
let mut pos = 0;
|
||||
'outer: for dr in -lag..=0 {
|
||||
for dc in -lag..=lag {
|
||||
if dr == 0 && dc == 0 {
|
||||
break 'outer;
|
||||
}
|
||||
let c = g.ar_coeffs_y_plus_128[pos] as i32 - 128;
|
||||
s += luma[(y as i32 + dr) as usize][(x as i32 + dc) as usize] * c;
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
fn luma_grain(c: &GrainCtx, rng: &mut Rng) -> GrainTemplate {
|
||||
let g = c.g;
|
||||
let shift = c.grain_shift();
|
||||
let mut luma = vec![[0i32; 82]; 73];
|
||||
for row in luma.iter_mut() {
|
||||
for v in row.iter_mut() {
|
||||
@@ -77,77 +135,89 @@ pub(crate) fn apply(pic: &mut Picture, g: &FilmGrainParams, seq: &SequenceHeader
|
||||
*v = round2(gv, shift);
|
||||
}
|
||||
}
|
||||
let ar_shift = g.ar_coeff_shift_minus_6 + 6;
|
||||
let lag = g.ar_coeff_lag as i32;
|
||||
let ar_shift = c.ar_shift();
|
||||
let lag = c.lag();
|
||||
for y in 3..73 {
|
||||
for x in 3..82 - 3 {
|
||||
let mut s = 0;
|
||||
let mut pos = 0;
|
||||
'outer: for dr in -lag..=0 {
|
||||
for dc in -lag..=lag {
|
||||
if dr == 0 && dc == 0 {
|
||||
break 'outer;
|
||||
}
|
||||
let c = g.ar_coeffs_y_plus_128[pos] as i32 - 128;
|
||||
s += luma[(y as i32 + dr) as usize][(x as i32 + dc) as usize] * c;
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
luma[y][x] = (luma[y][x] + round2(s, ar_shift)).clamp(grain_min, grain_max);
|
||||
}
|
||||
}
|
||||
let chroma_w = if sub_x != 0 { 44 } else { 82 };
|
||||
let chroma_h = if sub_y != 0 { 38 } else { 73 };
|
||||
let mut cb = vec![[0i32; 82]; 73];
|
||||
let mut cr = vec![[0i32; 82]; 73];
|
||||
if !mono {
|
||||
for (arr, seed, on) in [(&mut cb, 0xb524u32, g.num_cb_points > 0), (&mut cr, 0x49d8, g.num_cr_points > 0)] {
|
||||
rng.0 = g.grain_seed ^ seed;
|
||||
for row in arr.iter_mut().take(chroma_h) {
|
||||
for v in row.iter_mut().take(chroma_w) {
|
||||
let gv = if on || g.chroma_scaling_from_luma { GAUSSIAN_SEQUENCE[rng.next(11) as usize] as i32 } else { 0 };
|
||||
*v = round2(gv, shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
for y in 3..chroma_h {
|
||||
for x in 3..chroma_w - 3 {
|
||||
let mut s0 = 0;
|
||||
let mut s1 = 0;
|
||||
let mut pos = 0;
|
||||
'outer: for dr in -lag..=0 {
|
||||
for dc in -lag..=lag {
|
||||
let c0 = g.ar_coeffs_cb_plus_128[pos] as i32 - 128;
|
||||
let c1 = g.ar_coeffs_cr_plus_128[pos] as i32 - 128;
|
||||
if dr == 0 && dc == 0 {
|
||||
if g.num_y_points > 0 {
|
||||
let mut l = 0;
|
||||
let lx = ((x - 3) << sub_x) + 3;
|
||||
let ly = ((y - 3) << sub_y) + 3;
|
||||
for i in 0..=sub_y {
|
||||
for j in 0..=sub_x {
|
||||
l += luma[ly + i][lx + j];
|
||||
}
|
||||
}
|
||||
let l = round2(l, (sub_x + sub_y) as u32);
|
||||
s0 += l * c0;
|
||||
s1 += l * c1;
|
||||
}
|
||||
break 'outer;
|
||||
}
|
||||
let (yy, xx) = ((y as i32 + dr) as usize, (x as i32 + dc) as usize);
|
||||
s0 += cb[yy][xx] * c0;
|
||||
s1 += cr[yy][xx] * c1;
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
cb[y][x] = (cb[y][x] + round2(s0, ar_shift)).clamp(grain_min, grain_max);
|
||||
cr[y][x] = (cr[y][x] + round2(s1, ar_shift)).clamp(grain_min, grain_max);
|
||||
}
|
||||
let s = luma_ar_sum(g, &luma, lag, y, x);
|
||||
luma[y][x] = (luma[y][x] + round2(s, ar_shift)).clamp(c.grain_min, c.grain_max);
|
||||
}
|
||||
}
|
||||
luma
|
||||
}
|
||||
|
||||
// Scaling lookup (7.18.3.4).
|
||||
/// The luma contribution to the chroma autoregressive filter at chroma position (y, x).
|
||||
fn chroma_luma_term(c: &GrainCtx, luma: &[[i32; 82]], y: usize, x: usize) -> i32 {
|
||||
let mut l = 0;
|
||||
let lx = ((x - 3) << c.sub_x) + 3;
|
||||
let ly = ((y - 3) << c.sub_y) + 3;
|
||||
for i in 0..=c.sub_y {
|
||||
for j in 0..=c.sub_x {
|
||||
l += luma[ly + i][lx + j];
|
||||
}
|
||||
}
|
||||
round2(l, (c.sub_x + c.sub_y) as u32)
|
||||
}
|
||||
|
||||
fn chroma_ar_sums(c: &GrainCtx, t: &Templates, y: usize, x: usize) -> (i32, i32) {
|
||||
let g = c.g;
|
||||
let lag = c.lag();
|
||||
let mut s0 = 0;
|
||||
let mut s1 = 0;
|
||||
let mut pos = 0;
|
||||
'outer: for dr in -lag..=0 {
|
||||
for dc in -lag..=lag {
|
||||
let c0 = g.ar_coeffs_cb_plus_128[pos] as i32 - 128;
|
||||
let c1 = g.ar_coeffs_cr_plus_128[pos] as i32 - 128;
|
||||
if dr == 0 && dc == 0 {
|
||||
if g.num_y_points > 0 {
|
||||
let l = chroma_luma_term(c, &t.luma, y, x);
|
||||
s0 += l * c0;
|
||||
s1 += l * c1;
|
||||
}
|
||||
break 'outer;
|
||||
}
|
||||
let (yy, xx) = ((y as i32 + dr) as usize, (x as i32 + dc) as usize);
|
||||
s0 += t.cb[yy][xx] * c0;
|
||||
s1 += t.cr[yy][xx] * c1;
|
||||
pos += 1;
|
||||
}
|
||||
}
|
||||
(s0, s1)
|
||||
}
|
||||
|
||||
/// Chroma grain templates; zero for monochrome pictures.
|
||||
fn chroma_grain(c: &GrainCtx, rng: &mut Rng, luma: GrainTemplate) -> Templates {
|
||||
let g = c.g;
|
||||
let mut t = Templates { luma, cb: vec![[0i32; 82]; 73], cr: vec![[0i32; 82]; 73] };
|
||||
if c.mono {
|
||||
return t;
|
||||
}
|
||||
let shift = c.grain_shift();
|
||||
let ar_shift = c.ar_shift();
|
||||
let chroma_w = if c.sub_x != 0 { 44 } else { 82 };
|
||||
let chroma_h = if c.sub_y != 0 { 38 } else { 73 };
|
||||
for (arr, seed, on) in [(&mut t.cb, 0xb524u32, g.num_cb_points > 0), (&mut t.cr, 0x49d8, g.num_cr_points > 0)] {
|
||||
rng.0 = g.grain_seed ^ seed;
|
||||
for row in arr.iter_mut().take(chroma_h) {
|
||||
for v in row.iter_mut().take(chroma_w) {
|
||||
let gv = if on || g.chroma_scaling_from_luma { GAUSSIAN_SEQUENCE[rng.next(11) as usize] as i32 } else { 0 };
|
||||
*v = round2(gv, shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
for y in 3..chroma_h {
|
||||
for x in 3..chroma_w - 3 {
|
||||
let (s0, s1) = chroma_ar_sums(c, &t, y, x);
|
||||
t.cb[y][x] = (t.cb[y][x] + round2(s0, ar_shift)).clamp(c.grain_min, c.grain_max);
|
||||
t.cr[y][x] = (t.cr[y][x] + round2(s1, ar_shift)).clamp(c.grain_min, c.grain_max);
|
||||
}
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
/// Scaling lookup tables (7.18.3.4), one per plane.
|
||||
fn scaling_luts(g: &FilmGrainParams, num_planes: usize) -> [[i32; 256]; 3] {
|
||||
let mut lut = [[0i32; 256]; 3];
|
||||
for (plane, l) in lut.iter_mut().enumerate().take(num_planes) {
|
||||
let (n, xs, ys) = if plane == 0 || g.chroma_scaling_from_luma {
|
||||
@@ -159,101 +229,141 @@ pub(crate) fn apply(pic: &mut Picture, g: &FilmGrainParams, seq: &SequenceHeader
|
||||
};
|
||||
*l = scaling_lut(n, xs, ys);
|
||||
}
|
||||
let scale_lut = |plane: usize, index: i32| -> i32 {
|
||||
let sh = bd - 8;
|
||||
let x = index >> sh;
|
||||
let rem = index - (x << sh);
|
||||
if bd == 8 || x == 255 {
|
||||
lut[plane][x as usize]
|
||||
} else {
|
||||
let start = lut[plane][x as usize];
|
||||
let end = lut[plane][x as usize + 1];
|
||||
start + round2((end - start) * rem, sh)
|
||||
}
|
||||
};
|
||||
lut
|
||||
}
|
||||
|
||||
// Noise stripes (7.18.3.5).
|
||||
let stripe_w = w + 64;
|
||||
let n_stripes = (h.div_ceil(2)).div_ceil(16).max(1);
|
||||
let mut stripes: Vec<[Vec<i32>; 3]> = (0..n_stripes).map(|_| [vec![0; 34 * stripe_w], vec![0; 34 * stripe_w], vec![0; 34 * stripe_w]]).collect();
|
||||
let overlap = g.overlap_flag;
|
||||
for (luma_num, stripe) in stripes.iter_mut().enumerate() {
|
||||
let mut r = g.grain_seed;
|
||||
r ^= (((luma_num * 37 + 178) & 255) << 8) as u32;
|
||||
r ^= ((luma_num * 173 + 105) & 255) as u32;
|
||||
rng.0 = r;
|
||||
let mut x = 0;
|
||||
while x < w.div_ceil(2) {
|
||||
let rand = rng.next(8) as usize;
|
||||
let off_x = rand >> 4;
|
||||
let off_y = rand & 15;
|
||||
for (plane, s) in stripe.iter_mut().enumerate().take(num_planes) {
|
||||
let psx = if plane > 0 { sub_x } else { 0 };
|
||||
let psy = if plane > 0 { sub_y } else { 0 };
|
||||
let pox = if psx != 0 { 6 + off_x } else { 9 + off_x * 2 };
|
||||
let poy = if psy != 0 { 6 + off_y } else { 9 + off_y * 2 };
|
||||
let src = match plane {
|
||||
0 => &luma,
|
||||
1 => &cb,
|
||||
_ => &cr,
|
||||
fn scale_lookup(lut: &[[i32; 256]; 3], bd: u32, plane: usize, index: i32) -> i32 {
|
||||
let sh = bd - 8;
|
||||
let x = index >> sh;
|
||||
let rem = index - (x << sh);
|
||||
if bd == 8 || x == 255 {
|
||||
lut[plane][x as usize]
|
||||
} else {
|
||||
let start = lut[plane][x as usize];
|
||||
let end = lut[plane][x as usize + 1];
|
||||
start + round2((end - start) * rem, sh)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fills one plane of a noise stripe from the grain template at stripe column `x`.
|
||||
fn fill_stripe_plane(c: &GrainCtx, src: &GrainTemplate, s: &mut [i32], plane: usize, offsets: (usize, usize), x: usize) {
|
||||
let (off_x, off_y) = offsets;
|
||||
let stripe_w = c.stripe_w();
|
||||
let overlap = c.g.overlap_flag;
|
||||
let psx = if plane > 0 { c.sub_x } else { 0 };
|
||||
let psy = if plane > 0 { c.sub_y } else { 0 };
|
||||
let pox = if psx != 0 { 6 + off_x } else { 9 + off_x * 2 };
|
||||
let poy = if psy != 0 { 6 + off_y } else { 9 + off_y * 2 };
|
||||
for i in 0..(34 >> psy) {
|
||||
for j in 0..(34 >> psx) {
|
||||
let mut gv = src[poy + i][pox + j];
|
||||
let (idx, blend) = if psx == 0 { (i * stripe_w + x * 2 + j, j < 2) } else { (i * stripe_w + x + j, j == 0) };
|
||||
if blend && overlap && x > 0 {
|
||||
let old = s[idx];
|
||||
gv = if psx != 0 {
|
||||
old * 23 + gv * 22
|
||||
} else if j == 0 {
|
||||
old * 27 + gv * 17
|
||||
} else {
|
||||
old * 17 + gv * 27
|
||||
};
|
||||
for i in 0..(34 >> psy) {
|
||||
for j in 0..(34 >> psx) {
|
||||
let mut gv = src[poy + i][pox + j];
|
||||
if psx == 0 {
|
||||
let idx = i * stripe_w + x * 2 + j;
|
||||
if j < 2 && overlap && x > 0 {
|
||||
let old = s[idx];
|
||||
gv = if j == 0 { old * 27 + gv * 17 } else { old * 17 + gv * 27 };
|
||||
gv = round2(gv, 5).clamp(grain_min, grain_max);
|
||||
}
|
||||
s[idx] = gv;
|
||||
} else {
|
||||
let idx = i * stripe_w + x + j;
|
||||
if j == 0 && overlap && x > 0 {
|
||||
let old = s[idx];
|
||||
gv = round2(old * 23 + gv * 22, 5).clamp(grain_min, grain_max);
|
||||
}
|
||||
s[idx] = gv;
|
||||
}
|
||||
}
|
||||
}
|
||||
gv = round2(gv, 5).clamp(c.grain_min, c.grain_max);
|
||||
}
|
||||
x += 16;
|
||||
s[idx] = gv;
|
||||
}
|
||||
}
|
||||
let noise_at = |plane: usize, y: usize, x: usize| -> i32 {
|
||||
let psy = if plane > 0 { sub_y } else { 0 };
|
||||
}
|
||||
|
||||
/// Noise stripes (7.18.3.5).
|
||||
struct Stripes {
|
||||
data: Vec<[Vec<i32>; 3]>,
|
||||
stripe_w: usize,
|
||||
overlap: bool,
|
||||
sub_y: usize,
|
||||
grain_min: i32,
|
||||
grain_max: i32,
|
||||
}
|
||||
|
||||
impl Stripes {
|
||||
fn build(c: &GrainCtx, t: &Templates, rng: &mut Rng) -> Stripes {
|
||||
let g = c.g;
|
||||
let stripe_w = c.stripe_w();
|
||||
let n_stripes = (c.h.div_ceil(2)).div_ceil(16).max(1);
|
||||
let mut data: Vec<[Vec<i32>; 3]> = (0..n_stripes).map(|_| [vec![0; 34 * stripe_w], vec![0; 34 * stripe_w], vec![0; 34 * stripe_w]]).collect();
|
||||
for (luma_num, stripe) in data.iter_mut().enumerate() {
|
||||
let mut r = g.grain_seed;
|
||||
r ^= (((luma_num * 37 + 178) & 255) << 8) as u32;
|
||||
r ^= ((luma_num * 173 + 105) & 255) as u32;
|
||||
rng.0 = r;
|
||||
let mut x = 0;
|
||||
while x < c.w.div_ceil(2) {
|
||||
let rand = rng.next(8) as usize;
|
||||
let offsets = (rand >> 4, rand & 15);
|
||||
for (plane, s) in stripe.iter_mut().enumerate().take(c.num_planes()) {
|
||||
fill_stripe_plane(c, t.plane(plane), s, plane, offsets, x);
|
||||
}
|
||||
x += 16;
|
||||
}
|
||||
}
|
||||
Stripes { data, stripe_w, overlap: g.overlap_flag, sub_y: c.sub_y, grain_min: c.grain_min, grain_max: c.grain_max }
|
||||
}
|
||||
|
||||
fn noise_at(&self, plane: usize, y: usize, x: usize) -> i32 {
|
||||
let psy = if plane > 0 { self.sub_y } else { 0 };
|
||||
let luma_num = y >> (5 - psy);
|
||||
let i = y - (luma_num << (5 - psy));
|
||||
let mut gv = stripes[luma_num][plane][i * stripe_w + x];
|
||||
let mut gv = self.data[luma_num][plane][i * self.stripe_w + x];
|
||||
if psy == 0 {
|
||||
if i < 2 && luma_num > 0 && overlap {
|
||||
let old = stripes[luma_num - 1][plane][(i + 32) * stripe_w + x];
|
||||
if i < 2 && luma_num > 0 && self.overlap {
|
||||
let old = self.data[luma_num - 1][plane][(i + 32) * self.stripe_w + x];
|
||||
gv = if i == 0 { old * 27 + gv * 17 } else { old * 17 + gv * 27 };
|
||||
gv = round2(gv, 5).clamp(grain_min, grain_max);
|
||||
gv = round2(gv, 5).clamp(self.grain_min, self.grain_max);
|
||||
}
|
||||
} else if i < 1 && luma_num > 0 && overlap {
|
||||
let old = stripes[luma_num - 1][plane][(i + 16) * stripe_w + x];
|
||||
gv = round2(old * 23 + gv * 22, 5).clamp(grain_min, grain_max);
|
||||
} else if i < 1 && luma_num > 0 && self.overlap {
|
||||
let old = self.data[luma_num - 1][plane][(i + 16) * self.stripe_w + x];
|
||||
gv = round2(old * 23 + gv * 22, 5).clamp(self.grain_min, self.grain_max);
|
||||
}
|
||||
gv
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Blend (7.18.3.5).
|
||||
let (min_value, max_luma, max_chroma) = if g.clip_to_restricted_range {
|
||||
let ml = 235 << (bd - 8);
|
||||
(16 << (bd - 8), ml, if pic.matrix_coefficients as usize == MC_IDENTITY { ml } else { 240 << (bd - 8) })
|
||||
} else {
|
||||
let m = (256 << (bd - 8)) - 1;
|
||||
(0, m, m)
|
||||
};
|
||||
let pix_max = (1i32 << bd) - 1;
|
||||
let scaling_shift = g.grain_scaling_minus_8 + 8;
|
||||
if !mono {
|
||||
/// Output clipping range and scaling shift for the blend step (7.18.3.5).
|
||||
struct BlendRange {
|
||||
min_value: i32,
|
||||
max_luma: i32,
|
||||
max_chroma: i32,
|
||||
pix_max: i32,
|
||||
scaling_shift: u32,
|
||||
}
|
||||
|
||||
impl BlendRange {
|
||||
fn new(c: &GrainCtx, matrix_coefficients: usize) -> BlendRange {
|
||||
let bd = c.bd;
|
||||
let (min_value, max_luma, max_chroma) = if c.g.clip_to_restricted_range {
|
||||
let ml = 235 << (bd - 8);
|
||||
(16 << (bd - 8), ml, if matrix_coefficients == MC_IDENTITY { ml } else { 240 << (bd - 8) })
|
||||
} else {
|
||||
let m = (256 << (bd - 8)) - 1;
|
||||
(0, m, m)
|
||||
};
|
||||
BlendRange { min_value, max_luma, max_chroma, pix_max: (1i32 << bd) - 1, scaling_shift: c.g.grain_scaling_minus_8 + 8 }
|
||||
}
|
||||
}
|
||||
|
||||
struct BlendEnv<'a> {
|
||||
c: &'a GrainCtx<'a>,
|
||||
lut: &'a [[i32; 256]; 3],
|
||||
stripes: &'a Stripes,
|
||||
range: &'a BlendRange,
|
||||
}
|
||||
|
||||
impl BlendEnv<'_> {
|
||||
fn blend_chroma(&self, py: &[u16], pu: &mut [u16], pv: &mut [u16]) {
|
||||
let c = self.c;
|
||||
let g = c.g;
|
||||
let (w, h, sub_x, sub_y, bd) = (c.w, c.h, c.sub_x, c.sub_y, c.bd);
|
||||
let cw = (w + sub_x) >> sub_x;
|
||||
let ch = (h + sub_y) >> sub_y;
|
||||
let [py, pu, pv] = &mut pic.planes;
|
||||
for y in 0..ch {
|
||||
for x in 0..cw {
|
||||
let lx = x << sub_x;
|
||||
@@ -272,26 +382,62 @@ pub(crate) fn apply(pic: &mut Picture, g: &FilmGrainParams, seq: &SequenceHeader
|
||||
avg
|
||||
} else {
|
||||
let combined = avg * (luma_mult as i32 - 128) + orig * (mult as i32 - 128);
|
||||
((combined >> 6) + ((offset as i32 - 256) << (bd - 8))).clamp(0, pix_max)
|
||||
((combined >> 6) + ((offset as i32 - 256) << (bd - 8))).clamp(0, self.range.pix_max)
|
||||
};
|
||||
let noise = round2(scale_lut(plane, merged) * noise_at(plane, y, x), scaling_shift);
|
||||
out[y * cw + x] = (orig + noise).clamp(min_value, max_chroma) as u16;
|
||||
let noise = round2(scale_lookup(self.lut, bd, plane, merged) * self.stripes.noise_at(plane, y, x), self.range.scaling_shift);
|
||||
out[y * cw + x] = (orig + noise).clamp(self.range.min_value, self.range.max_chroma) as u16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if g.num_y_points > 0 {
|
||||
let py = &mut pic.planes[0];
|
||||
|
||||
fn blend_luma(&self, py: &mut [u16]) {
|
||||
let (w, h) = (self.c.w, self.c.h);
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let orig = py[y * w + x] as i32;
|
||||
let noise = round2(scale_lut(0, orig) * noise_at(0, y, x), scaling_shift);
|
||||
py[y * w + x] = (orig + noise).clamp(min_value, max_luma) as u16;
|
||||
let noise = round2(scale_lookup(self.lut, self.c.bd, 0, orig) * self.stripes.noise_at(0, y, x), self.range.scaling_shift);
|
||||
py[y * w + x] = (orig + noise).clamp(self.range.min_value, self.range.max_luma) as u16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn apply(pic: &mut Picture, g: &FilmGrainParams, seq: &SequenceHeader) {
|
||||
let _ = seq;
|
||||
let bd = pic.bit_depth as u32;
|
||||
let grain_center = 128i32 << (bd - 8);
|
||||
let c = GrainCtx {
|
||||
g,
|
||||
bd,
|
||||
mono: pic.mono_chrome,
|
||||
sub_x: pic.subsampling_x as usize,
|
||||
sub_y: pic.subsampling_y as usize,
|
||||
w: pic.width as usize,
|
||||
h: pic.height as usize,
|
||||
grain_min: -grain_center,
|
||||
grain_max: (256i32 << (bd - 8)) - 1 - grain_center,
|
||||
};
|
||||
|
||||
// Generate grain (7.18.3.3).
|
||||
let mut rng = Rng(g.grain_seed);
|
||||
let luma = luma_grain(&c, &mut rng);
|
||||
let templates = chroma_grain(&c, &mut rng, luma);
|
||||
let lut = scaling_luts(g, c.num_planes());
|
||||
let stripes = Stripes::build(&c, &templates, &mut rng);
|
||||
|
||||
// Blend (7.18.3.5).
|
||||
let range = BlendRange::new(&c, pic.matrix_coefficients as usize);
|
||||
let env = BlendEnv { c: &c, lut: &lut, stripes: &stripes, range: &range };
|
||||
if !c.mono {
|
||||
let [py, pu, pv] = &mut pic.planes;
|
||||
env.blend_chroma(py, pu, pv);
|
||||
}
|
||||
if g.num_y_points > 0 {
|
||||
env.blend_luma(&mut pic.planes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
+197
-149
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::error::{Result, ensure};
|
||||
use crate::picture::{FrameRef, RefPic};
|
||||
use crate::slice::{Mmco, SliceHeader, SliceType};
|
||||
use crate::slice::{Mmco, RefPicListMod, SliceHeader, SliceType};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@@ -174,6 +174,103 @@ 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()];
|
||||
@@ -186,25 +283,7 @@ 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 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 entry_lists = Self::initial_entry_lists(sh, cur_poc, &short, &long, pic_num);
|
||||
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;
|
||||
@@ -212,60 +291,7 @@ impl Dpb {
|
||||
list.truncate(n);
|
||||
list.resize(n, None);
|
||||
if !sh.ref_pic_list_mod[l].is_empty() {
|
||||
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);
|
||||
}
|
||||
Self::modify_ref_list(&mut list, &sh.ref_pic_list_mod[l], n, cur_fn, max_frame_num, &short, &long)?;
|
||||
}
|
||||
// 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());
|
||||
@@ -275,91 +301,88 @@ impl Dpb {
|
||||
Ok(lists)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// 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;
|
||||
for m in mmcos {
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
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 => {
|
||||
// Only an index within the allowed range may be assigned (8.2.5.4.6).
|
||||
let allowed = match self.max_long_term_frame_idx {
|
||||
Some(max) => m.long_term_frame_idx <= max,
|
||||
None => false,
|
||||
};
|
||||
if allowed {
|
||||
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;
|
||||
}
|
||||
}
|
||||
*cur_long = Some(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 => {
|
||||
let allowed = match self.max_long_term_frame_idx {
|
||||
Some(max) => m.long_term_frame_idx <= max,
|
||||
None => false,
|
||||
};
|
||||
if allowed {
|
||||
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;
|
||||
for m in mmcos {
|
||||
had5 |= self.apply_mmco(m, cur_frame_num, max_frame_num, cur_long);
|
||||
}
|
||||
self.prune();
|
||||
had5
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
) {
|
||||
/// 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) {
|
||||
let mut mark = RefMark::Unused;
|
||||
let mut long_idx = 0;
|
||||
let mut had5 = false;
|
||||
@@ -391,12 +414,12 @@ impl Dpb {
|
||||
}
|
||||
}
|
||||
}
|
||||
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).
|
||||
(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 mark == RefMark::Unused {
|
||||
loop {
|
||||
let waiting = self.entries.len();
|
||||
@@ -406,8 +429,7 @@ 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) {
|
||||
out.push(Output { frame, poc, meta });
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if !self.bump(out) {
|
||||
break;
|
||||
@@ -425,6 +447,32 @@ 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,
|
||||
|
||||
@@ -575,7 +575,7 @@ impl Pps {
|
||||
ensure!(sps_id < 32, "seq_parameter_set_id out of range");
|
||||
let sps = spss
|
||||
.get(sps_id as usize)
|
||||
.and_then(|s| s.as_ref())
|
||||
.and_then(Option::as_ref)
|
||||
.ok_or_else(|| crate::Error::MissingParameterSet(format!("SPS {sps_id} for PPS {id}")))?;
|
||||
let entropy_coding_mode = r.read_flag()?;
|
||||
let bottom_field_pic_order_in_frame_present = r.read_flag()?;
|
||||
|
||||
@@ -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;
|
||||
|
||||
+39
-25
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -665,33 +665,38 @@ impl<'a> SliceDecoder<'a> {
|
||||
return Ok(());
|
||||
}
|
||||
for p in 0..4 {
|
||||
let sub = self.cur.sub[p];
|
||||
let (x8, y8) = ((p & 1) * 2, (p >> 1) * 2);
|
||||
if sub.direct {
|
||||
self.derive_direct(1 << p)?;
|
||||
continue;
|
||||
self.derive_sub_mb_motion(p, n)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Motion of one 8x8 sub-macroblock `p` of a P8x8/B8x8 MB.
|
||||
fn derive_sub_mb_motion(&mut self, p: usize, n: [usize; 2]) -> Result<()> {
|
||||
let sub = self.cur.sub[p];
|
||||
let (x8, y8) = ((p & 1) * 2, (p >> 1) * 2);
|
||||
if sub.direct {
|
||||
return self.derive_direct(1 << p);
|
||||
}
|
||||
let mut refs = [-1i8; 2];
|
||||
for (l, r) in refs.iter_mut().enumerate() {
|
||||
if sub.pred & (1 << l) != 0 {
|
||||
let v = self.cur.ref_idx[l][p];
|
||||
ensure!((v as usize) < n[l], "ref_idx {v} out of range (list {l}, size {})", n[l]);
|
||||
*r = v;
|
||||
}
|
||||
let mut refs = [-1i8; 2];
|
||||
for (l, r) in refs.iter_mut().enumerate() {
|
||||
if sub.pred & (1 << l) != 0 {
|
||||
let v = self.cur.ref_idx[l][p];
|
||||
ensure!((v as usize) < n[l], "ref_idx {v} out of range (list {l}, size {})", n[l]);
|
||||
*r = v;
|
||||
}
|
||||
for j in 0..sub.shape.num_parts() {
|
||||
let (sx, sy, w, h) = sub.shape.rect(j);
|
||||
let (x, y) = (x8 + sx, y8 + sy);
|
||||
let mut mvs = [[0i16; 2]; 2];
|
||||
for l in 0..2 {
|
||||
if refs[l] >= 0 {
|
||||
let mvp = self.mvp(l, x, y, w, refs[l], 0, 0);
|
||||
let d = self.cur.mvd[l][p * 4 + j];
|
||||
mvs[l] = [mvp[0].wrapping_add(d[0]), mvp[1].wrapping_add(d[1])];
|
||||
}
|
||||
}
|
||||
for j in 0..sub.shape.num_parts() {
|
||||
let (sx, sy, w, h) = sub.shape.rect(j);
|
||||
let (x, y) = (x8 + sx, y8 + sy);
|
||||
let mut mvs = [[0i16; 2]; 2];
|
||||
for l in 0..2 {
|
||||
if refs[l] >= 0 {
|
||||
let mvp = self.mvp(l, x, y, w, refs[l], 0, 0);
|
||||
let d = self.cur.mvd[l][p * 4 + j];
|
||||
mvs[l] = [mvp[0].wrapping_add(d[0]), mvp[1].wrapping_add(d[1])];
|
||||
}
|
||||
}
|
||||
self.set_motion(x, y, w, h, refs, mvs);
|
||||
}
|
||||
self.set_motion(x, y, w, h, refs, mvs);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1380,6 +1385,11 @@ impl<'a> SliceDecoder<'a> {
|
||||
cavlc::residual_block(r, &mut lv, 0, 15, 16, nc)?;
|
||||
self.put_luma_dc(&lv);
|
||||
}
|
||||
self.residual_cavlc_luma(r, cbp, kind, t8)?;
|
||||
self.residual_cavlc_chroma(r, cbp)
|
||||
}
|
||||
|
||||
fn residual_cavlc_luma(&mut self, r: &mut BitReader, cbp: u8, kind: MbKind, t8: bool) -> Result<()> {
|
||||
for b8 in 0..4 {
|
||||
let (bx8, by8) = ((b8 & 1) * 2, (b8 >> 1) * 2);
|
||||
if cbp & (1 << b8) == 0 {
|
||||
@@ -1413,6 +1423,10 @@ impl<'a> SliceDecoder<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn residual_cavlc_chroma(&mut self, r: &mut BitReader, cbp: u8) -> Result<()> {
|
||||
let cbp_c = cbp >> 4;
|
||||
if cbp_c & 3 != 0 {
|
||||
for c in 0..2 {
|
||||
|
||||
@@ -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
@@ -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() {
|
||||
|
||||
@@ -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
@@ -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};
|
||||
@@ -678,7 +679,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(());
|
||||
}
|
||||
@@ -707,7 +708,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;
|
||||
@@ -724,7 +725,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;
|
||||
}
|
||||
@@ -738,7 +740,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);
|
||||
@@ -912,7 +914,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
|
||||
@@ -937,10 +939,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 =
|
||||
@@ -949,7 +951,7 @@ 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)
|
||||
}
|
||||
|
||||
/// cu_qp_delta_abs / sign and QP update (7.3.8.14).
|
||||
@@ -979,7 +981,15 @@ impl<'a> SliceDecoder<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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];
|
||||
@@ -1284,7 +1294,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> {
|
||||
@@ -1303,7 +1313,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];
|
||||
@@ -1355,19 +1365,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 {
|
||||
@@ -1382,7 +1381,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 {
|
||||
@@ -1426,7 +1425,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];
|
||||
}
|
||||
@@ -1524,11 +1523,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user