diff --git a/crates/apv/src/dct.rs b/crates/apv/src/dct.rs index 742e7510f..741ee8349 100644 --- a/crates/apv/src/dct.rs +++ b/crates/apv/src/dct.rs @@ -2,10 +2,17 @@ use crate::tables::LEVEL_SCALE; +/// Gathers column `x` of an 8x8 block stored row-major. +#[inline(always)] +fn column(block: &[i32; 64], x: usize) -> [i32; 8] { + std::array::from_fn(|i| block[i * 8 + x]) +} + /// 1D 8-point inverse transform using the RFC 9924 ยง6.3.2.3 even/odd butterfly decomposition, /// shifting each output by `(sum + round) >> shift`. #[inline(always)] -fn idct_1d(x0: i32, x1: i32, x2: i32, x3: i32, x4: i32, x5: i32, x6: i32, x7: i32, round: i32, shift: u32) -> [i32; 8] { +fn idct_1d(x: [i32; 8], round: i32, shift: u32) -> [i32; 8] { + let [x0, x1, x2, x3, x4, x5, x6, x7] = x; if (x1 | x2 | x3 | x4 | x5 | x6 | x7) == 0 { let v = (x0 * 64 + round) >> shift; return [v; 8]; @@ -79,7 +86,7 @@ pub fn scale_and_idct8x8(coeff: &[i16; 64], q_matrix: &[u8; 64], qp: u8, bit_dep // 1D vertical transform on each column x = 0..8, followed by (e + 64) >> 7 let mut g = [0i32; 64]; for x in 0..8 { - let col = idct_1d(d[x], d[8 + x], d[16 + x], d[24 + x], d[32 + x], d[40 + x], d[48 + x], d[56 + x], 64, 7); + let col = idct_1d(column(&d, x), 64, 7); for i in 0..8 { g[i * 8 + x] = col[i]; } @@ -93,7 +100,7 @@ pub fn scale_and_idct8x8(coeff: &[i16; 64], q_matrix: &[u8; 64], qp: u8, bit_dep for y in 0..8 { let r = &g[y * 8..y * 8 + 8]; - let row = idct_1d(r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], round, bd_shift); + let row = idct_1d([r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]], round, bd_shift); for i in 0..8 { out[y * 8 + i] = (row[i] + mid).clamp(0, max_val) as u16; } @@ -102,7 +109,8 @@ pub fn scale_and_idct8x8(coeff: &[i16; 64], q_matrix: &[u8; 64], qp: u8, bit_dep /// 1D 8-point forward butterfly transform matching `TRANS_MATRIX`. #[inline(always)] -fn fdct_1d(x0: i32, x1: i32, x2: i32, x3: i32, x4: i32, x5: i32, x6: i32, x7: i32, round: i32, shift: u32) -> [i32; 8] { +fn fdct_1d(x: [i32; 8], round: i32, shift: u32) -> [i32; 8] { + let [x0, x1, x2, x3, x4, x5, x6, x7] = x; let s0 = x0 + x7; let d0 = x0 - x7; let s1 = x1 + x6; @@ -141,25 +149,14 @@ pub fn fdct8x8(samples: &[u16; 64], bit_depth: u8) -> [i32; 64] { let mut t = [0i32; 64]; for y in 0..8 { let s = &samples[y * 8..y * 8 + 8]; - let row = fdct_1d( - s[0] as i32 - mid, - s[1] as i32 - mid, - s[2] as i32 - mid, - s[3] as i32 - mid, - s[4] as i32 - mid, - s[5] as i32 - mid, - s[6] as i32 - mid, - s[7] as i32 - mid, - add1, - shift1, - ); + let row = fdct_1d(std::array::from_fn(|i| s[i] as i32 - mid), add1, shift1); t[y * 8..y * 8 + 8].copy_from_slice(&row); } // Vertical forward pass let mut f = [0i32; 64]; for u in 0..8 { - let col = fdct_1d(t[u], t[8 + u], t[16 + u], t[24 + u], t[32 + u], t[40 + u], t[48 + u], t[56 + u], 128, 8); + let col = fdct_1d(column(&t, u), 128, 8); for v in 0..8 { f[v * 8 + u] = col[v]; } diff --git a/crates/apv/src/decode.rs b/crates/apv/src/decode.rs index 910ea5207..37847dd91 100644 --- a/crates/apv/src/decode.rs +++ b/crates/apv/src/decode.rs @@ -250,26 +250,48 @@ fn decode_pbu_planes(hdr: &FrameHeader, payload: &[u8], out_depth: u8, threads: let sub_h = hdr.chroma.sub_height_c() as usize; for tile in &decoded_tiles { - copy_tile_comp(&tile.comps[0], tile.w_luma as usize, tile.h_luma as usize, tile.x0 as usize, tile.y0 as usize, &mut out.y, w, h); + copy_tile_comp( + &tile.comps[0], + &TilePlacement { w: tile.w_luma as usize, h: tile.h_luma as usize, x: tile.x0 as usize, y: tile.y0 as usize }, + &mut out.y, + w, + h, + ); if hdr.chroma.num_comps() >= 3 { let tw_c = (tile.w_luma as usize) / sub_w; let th_c = (tile.h_luma as usize) / sub_h; let tx_c = (tile.x0 as usize) / sub_w; let ty_c = (tile.y0 as usize) / sub_h; - copy_tile_comp(&tile.comps[1], tw_c, th_c, tx_c, ty_c, &mut out.cb, cw, ch); - copy_tile_comp(&tile.comps[2], tw_c, th_c, tx_c, ty_c, &mut out.cr, cw, ch); + let chroma = TilePlacement { w: tw_c, h: th_c, x: tx_c, y: ty_c }; + copy_tile_comp(&tile.comps[1], &chroma, &mut out.cb, cw, ch); + copy_tile_comp(&tile.comps[2], &chroma, &mut out.cr, cw, ch); } if hdr.chroma == ChromaFormat::Yuv4444 && let Some(alpha) = out.alpha.as_mut() { - copy_tile_comp(&tile.comps[3], tile.w_luma as usize, tile.h_luma as usize, tile.x0 as usize, tile.y0 as usize, alpha, w, h); + copy_tile_comp( + &tile.comps[3], + &TilePlacement { w: tile.w_luma as usize, h: tile.h_luma as usize, x: tile.x0 as usize, y: tile.y0 as usize }, + alpha, + w, + h, + ); } } Ok(()) } -fn copy_tile_comp(src: &[u16], tw: usize, th: usize, tx: usize, ty: usize, dst: &mut [u16], fw: usize, fh: usize) { +/// Placement of a tile plane (`w` x `h` samples at `x`, `y`) within a frame plane. +struct TilePlacement { + w: usize, + h: usize, + x: usize, + y: usize, +} + +fn copy_tile_comp(src: &[u16], tile: &TilePlacement, dst: &mut [u16], fw: usize, fh: usize) { + let TilePlacement { w: tw, h: th, x: tx, y: ty } = *tile; if tx >= fw || ty >= fh { return; } @@ -342,18 +364,19 @@ fn decode_single_tile(hdr: &FrameHeader, tile_idx: usize, tile_bytes: &[u8], out comp_slices.push((c, comp_bytes)); } + let geom = TileGeom { w_luma, h_luma, out_depth }; #[cfg(feature = "threads")] let decoded_comps: Result>> = if par_comps && comp_slices.len() > 1 { use rayon::prelude::*; - comp_slices.into_par_iter().map(|(c, comp_bytes)| decode_tile_comp(hdr, tile_idx, c, comp_bytes, tile_qp[c], w_luma, h_luma, out_depth)).collect() + comp_slices.into_par_iter().map(|(c, comp_bytes)| decode_tile_comp(hdr, tile_idx, c, comp_bytes, tile_qp[c], geom)).collect() } else { - comp_slices.into_iter().map(|(c, comp_bytes)| decode_tile_comp(hdr, tile_idx, c, comp_bytes, tile_qp[c], w_luma, h_luma, out_depth)).collect() + comp_slices.into_iter().map(|(c, comp_bytes)| decode_tile_comp(hdr, tile_idx, c, comp_bytes, tile_qp[c], geom)).collect() }; #[cfg(not(feature = "threads"))] let decoded_comps: Result>> = { let _ = par_comps; - comp_slices.into_iter().map(|(c, comp_bytes)| decode_tile_comp(hdr, tile_idx, c, comp_bytes, tile_qp[c], w_luma, h_luma, out_depth)).collect() + comp_slices.into_iter().map(|(c, comp_bytes)| decode_tile_comp(hdr, tile_idx, c, comp_bytes, tile_qp[c], geom)).collect() }; let mut comps: [Vec; 4] = Default::default(); @@ -364,8 +387,16 @@ fn decode_single_tile(hdr: &FrameHeader, tile_idx: usize, tile_bytes: &[u8], out Ok(DecodedTile { x0, y0, w_luma, h_luma, comps }) } -#[allow(clippy::too_many_arguments)] -fn decode_tile_comp(hdr: &FrameHeader, tile_idx: usize, c: usize, comp_bytes: &[u8], qp: u8, w_luma: u32, h_luma: u32, out_depth: u8) -> Result> { +/// Luma size of a tile and the output sample bit depth. +#[derive(Clone, Copy)] +struct TileGeom { + w_luma: u32, + h_luma: u32, + out_depth: u8, +} + +fn decode_tile_comp(hdr: &FrameHeader, tile_idx: usize, c: usize, comp_bytes: &[u8], qp: u8, geom: TileGeom) -> Result> { + let TileGeom { w_luma, h_luma, out_depth } = geom; let num_mb_cols = w_luma / 16; let num_mb_rows = h_luma / 16; let sub_w = if c == 0 { 1 } else { hdr.chroma.sub_width_c() };