From 804eb14fa9e4518f94ba3da5ee200fcbfa02fe2e Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 30 Sep 2026 22:37:46 -0400 Subject: [PATCH] M9.8: VP9 fixture matrix with backward adaptation / alt-ref / tile rows, synthetic scaled-reference, intra-only and show_existing streams, robustness tests Co-Authored-By: Claude Opus 5.5 --- crates/vp9/examples/vp9dec.rs | 38 ++ crates/vp9/src/boolcoder.rs | 10 +- crates/vp9/src/tile.rs | 3 - crates/vp9/src/transform.rs | 44 +- crates/vp9/src/transform_gen.rs | 862 ++++++++++++++--------------- crates/vp9/tests/common/mod.rs | 154 ++++-- crates/vp9/tests/conformance.rs | 66 +-- crates/vp9/tests/robustness.rs | 106 ++++ crates/vp9/tests/synthetic.rs | 357 ++++++++++++ crates/vp9/tools/gen_transforms.py | 33 +- 10 files changed, 1098 insertions(+), 575 deletions(-) create mode 100644 crates/vp9/examples/vp9dec.rs create mode 100644 crates/vp9/tests/robustness.rs create mode 100644 crates/vp9/tests/synthetic.rs diff --git a/crates/vp9/examples/vp9dec.rs b/crates/vp9/examples/vp9dec.rs new file mode 100644 index 000000000..ea4a7af56 --- /dev/null +++ b/crates/vp9/examples/vp9dec.rs @@ -0,0 +1,38 @@ +//! Decode an IVF file: `cargo run --release -p filmcraft-vp9 --example vp9dec -- in.ivf [out.yuv]`. +//! Writes raw planar output (8-bit or 16-bit little endian) and prints decoder statistics. + +use std::io::Write; + +fn main() { + let args: Vec = std::env::args().collect(); + let data = std::fs::read(&args[1]).expect("read input"); + let mut out = args.get(2).map(|p| std::io::BufWriter::new(std::fs::File::create(p).expect("create output"))); + let mut dec = filmcraft_vp9::Decoder::new(); + let hl = u16::from_le_bytes([data[6], data[7]]) as usize; + let mut p = hl; + let mut i = 0i64; + let t0 = std::time::Instant::now(); + let mut n = 0; + while p + 12 <= data.len() { + let sz = u32::from_le_bytes(data[p..p + 4].try_into().unwrap()) as usize; + p += 12; + let Some(frame) = data.get(p..p + sz) else { break }; + p += sz; + match dec.decode(frame, i) { + Ok(pics) => { + for pic in pics { + n += 1; + if let Some(o) = out.as_mut() { + for pl in [&pic.y, &pic.u, &pic.v] { + o.write_all(&pl.to_le_bytes()).unwrap(); + } + } + } + } + Err(e) => eprintln!("chunk {i}: {e}"), + } + i += 1; + } + eprintln!("{n} pictures in {:.3}s", t0.elapsed().as_secs_f64()); + eprintln!("{:#?}", dec.stats()); +} diff --git a/crates/vp9/src/boolcoder.rs b/crates/vp9/src/boolcoder.rs index 7980f2940..da8cb5967 100644 --- a/crates/vp9/src/boolcoder.rs +++ b/crates/vp9/src/boolcoder.rs @@ -13,15 +13,13 @@ pub struct BoolDecoder<'a> { value: u64, count: i32, range: u32, - /// Number of zero bytes appended after the end of the data (detects runaway reads). - overrun: u32, } impl<'a> BoolDecoder<'a> { /// init_bool (9.2.1): the marker bit is read and returned in `Err` position when non-zero is /// not treated as fatal (libvpx ignores it too), so this only returns the decoder. pub fn new(data: &'a [u8]) -> Self { - let mut d = BoolDecoder { data, pos: 0, value: 0, count: -8, range: 255, overrun: 0 }; + let mut d = BoolDecoder { data, pos: 0, value: 0, count: -8, range: 255 }; d.fill(); d.read_bool(128); d @@ -49,7 +47,6 @@ impl<'a> BoolDecoder<'a> { self.pos += 1; b } else { - self.overrun = self.overrun.saturating_add(1); 0 }; self.value |= (b as u64) << shift; @@ -101,11 +98,6 @@ impl<'a> BoolDecoder<'a> { } } } - - /// True when the decoder has consumed far more bits than the data holds (a damaged stream). - pub fn overrun(&self) -> bool { - self.overrun > 16 - } } #[cfg(test)] diff --git a/crates/vp9/src/tile.rs b/crates/vp9/src/tile.rs index 87a25ec14..bf117672a 100644 --- a/crates/vp9/src/tile.rs +++ b/crates/vp9/src/tile.rs @@ -197,9 +197,6 @@ impl<'a> TileDecoder<'a> { for c in (cs..ce).step_by(8) { self.decode_partition(&mut bd, r, c, BLOCK_64X64); } - if bd.overrun() { - return false; - } } true } diff --git a/crates/vp9/src/transform.rs b/crates/vp9/src/transform.rs index 83d590066..3792a81b6 100644 --- a/crates/vp9/src/transform.rs +++ b/crates/vp9/src/transform.rs @@ -15,21 +15,21 @@ macro_rules! adst4 { #[inline(always)] fn $name(x: [$t; 4]) -> [$t; 4] { let (s1_9, s2_9, s3_9, s4_9) = (SINPI_1_9 as $t, SINPI_2_9 as $t, SINPI_3_9 as $t, SINPI_4_9 as $t); - let s0 = s1_9 * x[0]; - let s1 = s2_9 * x[0]; - let s2 = s3_9 * x[1]; - let s3 = s4_9 * x[2]; - let s4 = s1_9 * x[2]; - let s5 = s2_9 * x[3]; - let s6 = s4_9 * x[3]; - let v = x[0] - x[2] + x[3]; - let s7 = s3_9 * v; - let x0 = s0 + s3 + s5; - let x1 = s1 - s4 - s6; + let s0 = s1_9.wrapping_mul(x[0]); + let s1 = s2_9.wrapping_mul(x[0]); + let s2 = s3_9.wrapping_mul(x[1]); + let s3 = s4_9.wrapping_mul(x[2]); + let s4 = s1_9.wrapping_mul(x[2]); + let s5 = s2_9.wrapping_mul(x[3]); + let s6 = s4_9.wrapping_mul(x[3]); + let v = x[0].wrapping_sub(x[2]).wrapping_add(x[3]); + let s7 = s3_9.wrapping_mul(v); + let x0 = s0.wrapping_add(s3).wrapping_add(s5); + let x1 = s1.wrapping_sub(s4).wrapping_sub(s6); let x2 = s7; let x3 = s2; - let r = |v: $t| (v + (1 << 13)) >> 14; - [r(x0 + x3), r(x1 + x3), r(x2), r(x0 + x1 - x3)] + let r = |v: $t| v.wrapping_add(1 << 13) >> 14; + [r(x0.wrapping_add(x3)), r(x1.wrapping_add(x3)), r(x2), r(x0.wrapping_add(x1).wrapping_sub(x3))] } }; } @@ -42,13 +42,13 @@ fn iwht4(x: [i32; 4], shift: u32) -> [i32; 4] { let mut c = x[1] >> shift; let mut d = x[2] >> shift; let mut b = x[3] >> shift; - a += c; - d -= b; - let e = (a - d) >> 1; - b = e - b; - c = e - c; - a -= b; - d += c; + a = a.wrapping_add(c); + d = d.wrapping_sub(b); + let e = a.wrapping_sub(d) >> 1; + b = e.wrapping_sub(b); + c = e.wrapping_sub(c); + a = a.wrapping_sub(b); + d = d.wrapping_add(c); [a, b, c, d] } @@ -144,7 +144,7 @@ pub fn inverse_transform_add(coefs: &[i32], tx_size: u8, tx_type: u8, lossless: let r = iwht4([t[j], t[4 + j], t[8 + j], t[12 + j]], 0); for i in 0..4 { let p = &mut dst[i * stride + j]; - *p = (*p as i32 + r[i]).clamp(0, max) as u16; + *p = (*p as i32).saturating_add(r[i]).clamp(0, max) as u16; } } return; @@ -188,7 +188,7 @@ pub fn inverse_transform_add(coefs: &[i32], tx_size: u8, tx_type: u8, lossless: tx1d_narrow(&mut col[..n], n, col_adst); for i in 0..n { let p = &mut dst[i * stride + j]; - *p = (*p as i32 + ((col[i] + round) >> shift)).clamp(0, max) as u16; + *p = (*p as i32 + (col[i].wrapping_add(round) >> shift).clamp(-(1 << 20), 1 << 20)).clamp(0, max) as u16; } } } else { diff --git a/crates/vp9/src/transform_gen.rs b/crates/vp9/src/transform_gen.rs index 34a7e719d..6d2136b48 100644 --- a/crates/vp9/src/transform_gen.rs +++ b/crates/vp9/src/transform_gen.rs @@ -5,466 +5,466 @@ macro_rules! transforms_1d { ($t:ty) => { #[inline(always)] fn r14(x: $t) -> $t { - (x + (1 << 13)) >> 14 + x.wrapping_add(1 << 13) >> 14 } #[inline(always)] pub fn idct4(x: [$t; 4]) -> [$t; 4] { - let v0 = r14(x[0] * 11585 - x[2] * 11585); - let v1 = r14(x[0] * 11585 + x[2] * 11585); - let v2 = r14(x[1] * 6270 - x[3] * 15137); - let v3 = r14(x[1] * 15137 + x[3] * 6270); - let v4 = v1 + v3; - let v5 = v1 - v3; - let v6 = v0 + v2; - let v7 = v0 - v2; + let v0 = r14(x[0].wrapping_mul(11585).wrapping_add(x[2].wrapping_mul(-11585))); + let v1 = r14(x[0].wrapping_mul(11585).wrapping_add(x[2].wrapping_mul(11585))); + let v2 = r14(x[1].wrapping_mul(6270).wrapping_add(x[3].wrapping_mul(-15137))); + let v3 = r14(x[1].wrapping_mul(15137).wrapping_add(x[3].wrapping_mul(6270))); + let v4 = v1.wrapping_add(v3); + let v5 = v1.wrapping_sub(v3); + let v6 = v0.wrapping_add(v2); + let v7 = v0.wrapping_sub(v2); [v4, v6, v7, v5] } #[inline(always)] pub fn idct8(x: [$t; 8]) -> [$t; 8] { - let v0 = r14(x[0] * 11585 - x[4] * 11585); - let v1 = r14(x[0] * 11585 + x[4] * 11585); - let v2 = r14(x[2] * 6270 - x[6] * 15137); - let v3 = r14(x[2] * 15137 + x[6] * 6270); - let v4 = v1 + v3; - let v5 = v1 - v3; - let v6 = v0 + v2; - let v7 = v0 - v2; - let v8 = r14(x[1] * 3196 - x[7] * 16069); - let v9 = r14(x[1] * 16069 + x[7] * 3196); - let v10 = r14(x[5] * 13623 - x[3] * 9102); - let v11 = r14(x[5] * 9102 + x[3] * 13623); - let v12 = v8 + v10; - let v13 = v8 - v10; - let v14 = v9 + v11; - let v15 = v9 - v11; - let v16 = r14(v15 * 11585 - v13 * 11585); - let v17 = r14(v15 * 11585 + v13 * 11585); - let v18 = v4 + v14; - let v19 = v4 - v14; - let v20 = v6 + v17; - let v21 = v6 - v17; - let v22 = v7 + v16; - let v23 = v7 - v16; - let v24 = v5 + v12; - let v25 = v5 - v12; + let v0 = r14(x[0].wrapping_mul(11585).wrapping_add(x[4].wrapping_mul(-11585))); + let v1 = r14(x[0].wrapping_mul(11585).wrapping_add(x[4].wrapping_mul(11585))); + let v2 = r14(x[2].wrapping_mul(6270).wrapping_add(x[6].wrapping_mul(-15137))); + let v3 = r14(x[2].wrapping_mul(15137).wrapping_add(x[6].wrapping_mul(6270))); + let v4 = v1.wrapping_add(v3); + let v5 = v1.wrapping_sub(v3); + let v6 = v0.wrapping_add(v2); + let v7 = v0.wrapping_sub(v2); + let v8 = r14(x[1].wrapping_mul(3196).wrapping_add(x[7].wrapping_mul(-16069))); + let v9 = r14(x[1].wrapping_mul(16069).wrapping_add(x[7].wrapping_mul(3196))); + let v10 = r14(x[5].wrapping_mul(13623).wrapping_add(x[3].wrapping_mul(-9102))); + let v11 = r14(x[5].wrapping_mul(9102).wrapping_add(x[3].wrapping_mul(13623))); + let v12 = v8.wrapping_add(v10); + let v13 = v8.wrapping_sub(v10); + let v14 = v9.wrapping_add(v11); + let v15 = v9.wrapping_sub(v11); + let v16 = r14(v15.wrapping_mul(11585).wrapping_add(v13.wrapping_mul(-11585))); + let v17 = r14(v15.wrapping_mul(11585).wrapping_add(v13.wrapping_mul(11585))); + let v18 = v4.wrapping_add(v14); + let v19 = v4.wrapping_sub(v14); + let v20 = v6.wrapping_add(v17); + let v21 = v6.wrapping_sub(v17); + let v22 = v7.wrapping_add(v16); + let v23 = v7.wrapping_sub(v16); + let v24 = v5.wrapping_add(v12); + let v25 = v5.wrapping_sub(v12); [v18, v20, v22, v24, v25, v23, v21, v19] } #[inline(always)] pub fn idct16(x: [$t; 16]) -> [$t; 16] { - let v0 = r14(x[0] * 11585 - x[8] * 11585); - let v1 = r14(x[0] * 11585 + x[8] * 11585); - let v2 = r14(x[4] * 6270 - x[12] * 15137); - let v3 = r14(x[4] * 15137 + x[12] * 6270); - let v4 = v1 + v3; - let v5 = v1 - v3; - let v6 = v0 + v2; - let v7 = v0 - v2; - let v8 = r14(x[2] * 3196 - x[14] * 16069); - let v9 = r14(x[2] * 16069 + x[14] * 3196); - let v10 = r14(x[10] * 13623 - x[6] * 9102); - let v11 = r14(x[10] * 9102 + x[6] * 13623); - let v12 = v8 + v10; - let v13 = v8 - v10; - let v14 = v9 + v11; - let v15 = v9 - v11; - let v16 = r14(v15 * 11585 - v13 * 11585); - let v17 = r14(v15 * 11585 + v13 * 11585); - let v18 = v4 + v14; - let v19 = v4 - v14; - let v20 = v6 + v17; - let v21 = v6 - v17; - let v22 = v7 + v16; - let v23 = v7 - v16; - let v24 = v5 + v12; - let v25 = v5 - v12; - let v26 = r14(x[1] * 1606 - x[15] * 16305); - let v27 = r14(x[1] * 16305 + x[15] * 1606); - let v28 = r14(x[9] * 12665 - x[7] * 10394); - let v29 = r14(x[9] * 10394 + x[7] * 12665); - let v30 = r14(x[5] * 7723 - x[11] * 14449); - let v31 = r14(x[5] * 14449 + x[11] * 7723); - let v32 = r14(x[13] * 15679 - x[3] * 4756); - let v33 = r14(x[13] * 4756 + x[3] * 15679); - let v34 = v26 + v28; - let v35 = v26 - v28; - let v36 = v32 + v30; - let v37 = v32 - v30; - let v38 = v33 + v31; - let v39 = v33 - v31; - let v40 = v27 + v29; - let v41 = v27 - v29; - let v42 = r14(v41 * 6270 - v35 * 15137); - let v43 = r14(v41 * 15137 + v35 * 6270); - let v44 = r14(-v37 * 15137 + v39 * 6270); - let v45 = r14(-v37 * 6270 - v39 * 15137); - let v46 = v34 + v36; - let v47 = v34 - v36; - let v48 = v40 + v38; - let v49 = v40 - v38; - let v50 = v42 + v45; - let v51 = v42 - v45; - let v52 = v43 + v44; - let v53 = v43 - v44; - let v54 = r14(v53 * 11585 - v51 * 11585); - let v55 = r14(v53 * 11585 + v51 * 11585); - let v56 = r14(v49 * 11585 - v47 * 11585); - let v57 = r14(v49 * 11585 + v47 * 11585); - let v58 = v18 + v48; - let v59 = v18 - v48; - let v60 = v20 + v52; - let v61 = v20 - v52; - let v62 = v22 + v55; - let v63 = v22 - v55; - let v64 = v24 + v57; - let v65 = v24 - v57; - let v66 = v25 + v56; - let v67 = v25 - v56; - let v68 = v23 + v54; - let v69 = v23 - v54; - let v70 = v21 + v50; - let v71 = v21 - v50; - let v72 = v19 + v46; - let v73 = v19 - v46; + let v0 = r14(x[0].wrapping_mul(11585).wrapping_add(x[8].wrapping_mul(-11585))); + let v1 = r14(x[0].wrapping_mul(11585).wrapping_add(x[8].wrapping_mul(11585))); + let v2 = r14(x[4].wrapping_mul(6270).wrapping_add(x[12].wrapping_mul(-15137))); + let v3 = r14(x[4].wrapping_mul(15137).wrapping_add(x[12].wrapping_mul(6270))); + let v4 = v1.wrapping_add(v3); + let v5 = v1.wrapping_sub(v3); + let v6 = v0.wrapping_add(v2); + let v7 = v0.wrapping_sub(v2); + let v8 = r14(x[2].wrapping_mul(3196).wrapping_add(x[14].wrapping_mul(-16069))); + let v9 = r14(x[2].wrapping_mul(16069).wrapping_add(x[14].wrapping_mul(3196))); + let v10 = r14(x[10].wrapping_mul(13623).wrapping_add(x[6].wrapping_mul(-9102))); + let v11 = r14(x[10].wrapping_mul(9102).wrapping_add(x[6].wrapping_mul(13623))); + let v12 = v8.wrapping_add(v10); + let v13 = v8.wrapping_sub(v10); + let v14 = v9.wrapping_add(v11); + let v15 = v9.wrapping_sub(v11); + let v16 = r14(v15.wrapping_mul(11585).wrapping_add(v13.wrapping_mul(-11585))); + let v17 = r14(v15.wrapping_mul(11585).wrapping_add(v13.wrapping_mul(11585))); + let v18 = v4.wrapping_add(v14); + let v19 = v4.wrapping_sub(v14); + let v20 = v6.wrapping_add(v17); + let v21 = v6.wrapping_sub(v17); + let v22 = v7.wrapping_add(v16); + let v23 = v7.wrapping_sub(v16); + let v24 = v5.wrapping_add(v12); + let v25 = v5.wrapping_sub(v12); + let v26 = r14(x[1].wrapping_mul(1606).wrapping_add(x[15].wrapping_mul(-16305))); + let v27 = r14(x[1].wrapping_mul(16305).wrapping_add(x[15].wrapping_mul(1606))); + let v28 = r14(x[9].wrapping_mul(12665).wrapping_add(x[7].wrapping_mul(-10394))); + let v29 = r14(x[9].wrapping_mul(10394).wrapping_add(x[7].wrapping_mul(12665))); + let v30 = r14(x[5].wrapping_mul(7723).wrapping_add(x[11].wrapping_mul(-14449))); + let v31 = r14(x[5].wrapping_mul(14449).wrapping_add(x[11].wrapping_mul(7723))); + let v32 = r14(x[13].wrapping_mul(15679).wrapping_add(x[3].wrapping_mul(-4756))); + let v33 = r14(x[13].wrapping_mul(4756).wrapping_add(x[3].wrapping_mul(15679))); + let v34 = v26.wrapping_add(v28); + let v35 = v26.wrapping_sub(v28); + let v36 = v32.wrapping_add(v30); + let v37 = v32.wrapping_sub(v30); + let v38 = v33.wrapping_add(v31); + let v39 = v33.wrapping_sub(v31); + let v40 = v27.wrapping_add(v29); + let v41 = v27.wrapping_sub(v29); + let v42 = r14(v41.wrapping_mul(6270).wrapping_add(v35.wrapping_mul(-15137))); + let v43 = r14(v41.wrapping_mul(15137).wrapping_add(v35.wrapping_mul(6270))); + let v44 = r14(v37.wrapping_mul(-15137).wrapping_add(v39.wrapping_mul(6270))); + let v45 = r14(v37.wrapping_mul(-6270).wrapping_add(v39.wrapping_mul(-15137))); + let v46 = v34.wrapping_add(v36); + let v47 = v34.wrapping_sub(v36); + let v48 = v40.wrapping_add(v38); + let v49 = v40.wrapping_sub(v38); + let v50 = v42.wrapping_add(v45); + let v51 = v42.wrapping_sub(v45); + let v52 = v43.wrapping_add(v44); + let v53 = v43.wrapping_sub(v44); + let v54 = r14(v53.wrapping_mul(11585).wrapping_add(v51.wrapping_mul(-11585))); + let v55 = r14(v53.wrapping_mul(11585).wrapping_add(v51.wrapping_mul(11585))); + let v56 = r14(v49.wrapping_mul(11585).wrapping_add(v47.wrapping_mul(-11585))); + let v57 = r14(v49.wrapping_mul(11585).wrapping_add(v47.wrapping_mul(11585))); + let v58 = v18.wrapping_add(v48); + let v59 = v18.wrapping_sub(v48); + let v60 = v20.wrapping_add(v52); + let v61 = v20.wrapping_sub(v52); + let v62 = v22.wrapping_add(v55); + let v63 = v22.wrapping_sub(v55); + let v64 = v24.wrapping_add(v57); + let v65 = v24.wrapping_sub(v57); + let v66 = v25.wrapping_add(v56); + let v67 = v25.wrapping_sub(v56); + let v68 = v23.wrapping_add(v54); + let v69 = v23.wrapping_sub(v54); + let v70 = v21.wrapping_add(v50); + let v71 = v21.wrapping_sub(v50); + let v72 = v19.wrapping_add(v46); + let v73 = v19.wrapping_sub(v46); [v58, v60, v62, v64, v66, v68, v70, v72, v73, v71, v69, v67, v65, v63, v61, v59] } #[inline(always)] pub fn idct32(x: [$t; 32]) -> [$t; 32] { - let v0 = r14(x[0] * 11585 - x[16] * 11585); - let v1 = r14(x[0] * 11585 + x[16] * 11585); - let v2 = r14(x[8] * 6270 - x[24] * 15137); - let v3 = r14(x[8] * 15137 + x[24] * 6270); - let v4 = v1 + v3; - let v5 = v1 - v3; - let v6 = v0 + v2; - let v7 = v0 - v2; - let v8 = r14(x[4] * 3196 - x[28] * 16069); - let v9 = r14(x[4] * 16069 + x[28] * 3196); - let v10 = r14(x[20] * 13623 - x[12] * 9102); - let v11 = r14(x[20] * 9102 + x[12] * 13623); - let v12 = v8 + v10; - let v13 = v8 - v10; - let v14 = v9 + v11; - let v15 = v9 - v11; - let v16 = r14(v15 * 11585 - v13 * 11585); - let v17 = r14(v15 * 11585 + v13 * 11585); - let v18 = v4 + v14; - let v19 = v4 - v14; - let v20 = v6 + v17; - let v21 = v6 - v17; - let v22 = v7 + v16; - let v23 = v7 - v16; - let v24 = v5 + v12; - let v25 = v5 - v12; - let v26 = r14(x[2] * 1606 - x[30] * 16305); - let v27 = r14(x[2] * 16305 + x[30] * 1606); - let v28 = r14(x[18] * 12665 - x[14] * 10394); - let v29 = r14(x[18] * 10394 + x[14] * 12665); - let v30 = r14(x[10] * 7723 - x[22] * 14449); - let v31 = r14(x[10] * 14449 + x[22] * 7723); - let v32 = r14(x[26] * 15679 - x[6] * 4756); - let v33 = r14(x[26] * 4756 + x[6] * 15679); - let v34 = v26 + v28; - let v35 = v26 - v28; - let v36 = v32 + v30; - let v37 = v32 - v30; - let v38 = v33 + v31; - let v39 = v33 - v31; - let v40 = v27 + v29; - let v41 = v27 - v29; - let v42 = r14(v41 * 6270 - v35 * 15137); - let v43 = r14(v41 * 15137 + v35 * 6270); - let v44 = r14(-v37 * 15137 + v39 * 6270); - let v45 = r14(-v37 * 6270 - v39 * 15137); - let v46 = v34 + v36; - let v47 = v34 - v36; - let v48 = v40 + v38; - let v49 = v40 - v38; - let v50 = v42 + v45; - let v51 = v42 - v45; - let v52 = v43 + v44; - let v53 = v43 - v44; - let v54 = r14(v53 * 11585 - v51 * 11585); - let v55 = r14(v53 * 11585 + v51 * 11585); - let v56 = r14(v49 * 11585 - v47 * 11585); - let v57 = r14(v49 * 11585 + v47 * 11585); - let v58 = v18 + v48; - let v59 = v18 - v48; - let v60 = v20 + v52; - let v61 = v20 - v52; - let v62 = v22 + v55; - let v63 = v22 - v55; - let v64 = v24 + v57; - let v65 = v24 - v57; - let v66 = v25 + v56; - let v67 = v25 - v56; - let v68 = v23 + v54; - let v69 = v23 - v54; - let v70 = v21 + v50; - let v71 = v21 - v50; - let v72 = v19 + v46; - let v73 = v19 - v46; - let v74 = r14(x[1] * 804 - x[31] * 16364); - let v75 = r14(x[1] * 16364 + x[31] * 804); - let v76 = r14(x[17] * 12140 - x[15] * 11003); - let v77 = r14(x[17] * 11003 + x[15] * 12140); - let v78 = r14(x[9] * 7005 - x[23] * 14811); - let v79 = r14(x[9] * 14811 + x[23] * 7005); - let v80 = r14(x[25] * 15426 - x[7] * 5520); - let v81 = r14(x[25] * 5520 + x[7] * 15426); - let v82 = r14(x[5] * 3981 - x[27] * 15893); - let v83 = r14(x[5] * 15893 + x[27] * 3981); - let v84 = r14(x[21] * 14053 - x[11] * 8423); - let v85 = r14(x[21] * 8423 + x[11] * 14053); - let v86 = r14(x[13] * 9760 - x[19] * 13160); - let v87 = r14(x[13] * 13160 + x[19] * 9760); - let v88 = r14(x[29] * 16207 - x[3] * 2404); - let v89 = r14(x[29] * 2404 + x[3] * 16207); - let v90 = v74 + v76; - let v91 = v74 - v76; - let v92 = v80 + v78; - let v93 = v80 - v78; - let v94 = v82 + v84; - let v95 = v82 - v84; - let v96 = v88 + v86; - let v97 = v88 - v86; - let v98 = v89 + v87; - let v99 = v89 - v87; - let v100 = v83 + v85; - let v101 = v83 - v85; - let v102 = v81 + v79; - let v103 = v81 - v79; - let v104 = v75 + v77; - let v105 = v75 - v77; - let v106 = r14(v105 * 3196 - v91 * 16069); - let v107 = r14(v105 * 16069 + v91 * 3196); - let v108 = r14(-v97 * 9102 + v99 * 13623); - let v109 = r14(-v97 * 13623 - v99 * 9102); - let v110 = r14(v101 * 13623 - v95 * 9102); - let v111 = r14(v101 * 9102 + v95 * 13623); - let v112 = r14(-v93 * 16069 + v103 * 3196); - let v113 = r14(-v93 * 3196 - v103 * 16069); - let v114 = v90 + v92; - let v115 = v90 - v92; - let v116 = v96 + v94; - let v117 = v96 - v94; - let v118 = v98 + v100; - let v119 = v98 - v100; - let v120 = v104 + v102; - let v121 = v104 - v102; - let v122 = v106 + v113; - let v123 = v106 - v113; - let v124 = v109 + v110; - let v125 = v109 - v110; - let v126 = v108 + v111; - let v127 = v108 - v111; - let v128 = v107 + v112; - let v129 = v107 - v112; - let v130 = r14(v129 * 6270 - v123 * 15137); - let v131 = r14(v129 * 15137 + v123 * 6270); - let v132 = r14(-v125 * 15137 + v127 * 6270); - let v133 = r14(-v125 * 6270 - v127 * 15137); - let v134 = r14(v121 * 6270 - v115 * 15137); - let v135 = r14(v121 * 15137 + v115 * 6270); - let v136 = r14(-v117 * 15137 + v119 * 6270); - let v137 = r14(-v117 * 6270 - v119 * 15137); - let v138 = v114 + v116; - let v139 = v114 - v116; - let v140 = v120 + v118; - let v141 = v120 - v118; - let v142 = v122 + v124; - let v143 = v122 - v124; - let v144 = v128 + v126; - let v145 = v128 - v126; - let v146 = v130 + v133; - let v147 = v130 - v133; - let v148 = v131 + v132; - let v149 = v131 - v132; - let v150 = v134 + v137; - let v151 = v134 - v137; - let v152 = v135 + v136; - let v153 = v135 - v136; - let v154 = r14(v153 * 11585 - v151 * 11585); - let v155 = r14(v153 * 11585 + v151 * 11585); - let v156 = r14(v149 * 11585 - v147 * 11585); - let v157 = r14(v149 * 11585 + v147 * 11585); - let v158 = r14(v145 * 11585 - v143 * 11585); - let v159 = r14(v145 * 11585 + v143 * 11585); - let v160 = r14(v141 * 11585 - v139 * 11585); - let v161 = r14(v141 * 11585 + v139 * 11585); - let v162 = v58 + v140; - let v163 = v58 - v140; - let v164 = v60 + v144; - let v165 = v60 - v144; - let v166 = v62 + v148; - let v167 = v62 - v148; - let v168 = v64 + v152; - let v169 = v64 - v152; - let v170 = v66 + v155; - let v171 = v66 - v155; - let v172 = v68 + v157; - let v173 = v68 - v157; - let v174 = v70 + v159; - let v175 = v70 - v159; - let v176 = v72 + v161; - let v177 = v72 - v161; - let v178 = v73 + v160; - let v179 = v73 - v160; - let v180 = v71 + v158; - let v181 = v71 - v158; - let v182 = v69 + v156; - let v183 = v69 - v156; - let v184 = v67 + v154; - let v185 = v67 - v154; - let v186 = v65 + v150; - let v187 = v65 - v150; - let v188 = v63 + v146; - let v189 = v63 - v146; - let v190 = v61 + v142; - let v191 = v61 - v142; - let v192 = v59 + v138; - let v193 = v59 - v138; + let v0 = r14(x[0].wrapping_mul(11585).wrapping_add(x[16].wrapping_mul(-11585))); + let v1 = r14(x[0].wrapping_mul(11585).wrapping_add(x[16].wrapping_mul(11585))); + let v2 = r14(x[8].wrapping_mul(6270).wrapping_add(x[24].wrapping_mul(-15137))); + let v3 = r14(x[8].wrapping_mul(15137).wrapping_add(x[24].wrapping_mul(6270))); + let v4 = v1.wrapping_add(v3); + let v5 = v1.wrapping_sub(v3); + let v6 = v0.wrapping_add(v2); + let v7 = v0.wrapping_sub(v2); + let v8 = r14(x[4].wrapping_mul(3196).wrapping_add(x[28].wrapping_mul(-16069))); + let v9 = r14(x[4].wrapping_mul(16069).wrapping_add(x[28].wrapping_mul(3196))); + let v10 = r14(x[20].wrapping_mul(13623).wrapping_add(x[12].wrapping_mul(-9102))); + let v11 = r14(x[20].wrapping_mul(9102).wrapping_add(x[12].wrapping_mul(13623))); + let v12 = v8.wrapping_add(v10); + let v13 = v8.wrapping_sub(v10); + let v14 = v9.wrapping_add(v11); + let v15 = v9.wrapping_sub(v11); + let v16 = r14(v15.wrapping_mul(11585).wrapping_add(v13.wrapping_mul(-11585))); + let v17 = r14(v15.wrapping_mul(11585).wrapping_add(v13.wrapping_mul(11585))); + let v18 = v4.wrapping_add(v14); + let v19 = v4.wrapping_sub(v14); + let v20 = v6.wrapping_add(v17); + let v21 = v6.wrapping_sub(v17); + let v22 = v7.wrapping_add(v16); + let v23 = v7.wrapping_sub(v16); + let v24 = v5.wrapping_add(v12); + let v25 = v5.wrapping_sub(v12); + let v26 = r14(x[2].wrapping_mul(1606).wrapping_add(x[30].wrapping_mul(-16305))); + let v27 = r14(x[2].wrapping_mul(16305).wrapping_add(x[30].wrapping_mul(1606))); + let v28 = r14(x[18].wrapping_mul(12665).wrapping_add(x[14].wrapping_mul(-10394))); + let v29 = r14(x[18].wrapping_mul(10394).wrapping_add(x[14].wrapping_mul(12665))); + let v30 = r14(x[10].wrapping_mul(7723).wrapping_add(x[22].wrapping_mul(-14449))); + let v31 = r14(x[10].wrapping_mul(14449).wrapping_add(x[22].wrapping_mul(7723))); + let v32 = r14(x[26].wrapping_mul(15679).wrapping_add(x[6].wrapping_mul(-4756))); + let v33 = r14(x[26].wrapping_mul(4756).wrapping_add(x[6].wrapping_mul(15679))); + let v34 = v26.wrapping_add(v28); + let v35 = v26.wrapping_sub(v28); + let v36 = v32.wrapping_add(v30); + let v37 = v32.wrapping_sub(v30); + let v38 = v33.wrapping_add(v31); + let v39 = v33.wrapping_sub(v31); + let v40 = v27.wrapping_add(v29); + let v41 = v27.wrapping_sub(v29); + let v42 = r14(v41.wrapping_mul(6270).wrapping_add(v35.wrapping_mul(-15137))); + let v43 = r14(v41.wrapping_mul(15137).wrapping_add(v35.wrapping_mul(6270))); + let v44 = r14(v37.wrapping_mul(-15137).wrapping_add(v39.wrapping_mul(6270))); + let v45 = r14(v37.wrapping_mul(-6270).wrapping_add(v39.wrapping_mul(-15137))); + let v46 = v34.wrapping_add(v36); + let v47 = v34.wrapping_sub(v36); + let v48 = v40.wrapping_add(v38); + let v49 = v40.wrapping_sub(v38); + let v50 = v42.wrapping_add(v45); + let v51 = v42.wrapping_sub(v45); + let v52 = v43.wrapping_add(v44); + let v53 = v43.wrapping_sub(v44); + let v54 = r14(v53.wrapping_mul(11585).wrapping_add(v51.wrapping_mul(-11585))); + let v55 = r14(v53.wrapping_mul(11585).wrapping_add(v51.wrapping_mul(11585))); + let v56 = r14(v49.wrapping_mul(11585).wrapping_add(v47.wrapping_mul(-11585))); + let v57 = r14(v49.wrapping_mul(11585).wrapping_add(v47.wrapping_mul(11585))); + let v58 = v18.wrapping_add(v48); + let v59 = v18.wrapping_sub(v48); + let v60 = v20.wrapping_add(v52); + let v61 = v20.wrapping_sub(v52); + let v62 = v22.wrapping_add(v55); + let v63 = v22.wrapping_sub(v55); + let v64 = v24.wrapping_add(v57); + let v65 = v24.wrapping_sub(v57); + let v66 = v25.wrapping_add(v56); + let v67 = v25.wrapping_sub(v56); + let v68 = v23.wrapping_add(v54); + let v69 = v23.wrapping_sub(v54); + let v70 = v21.wrapping_add(v50); + let v71 = v21.wrapping_sub(v50); + let v72 = v19.wrapping_add(v46); + let v73 = v19.wrapping_sub(v46); + let v74 = r14(x[1].wrapping_mul(804).wrapping_add(x[31].wrapping_mul(-16364))); + let v75 = r14(x[1].wrapping_mul(16364).wrapping_add(x[31].wrapping_mul(804))); + let v76 = r14(x[17].wrapping_mul(12140).wrapping_add(x[15].wrapping_mul(-11003))); + let v77 = r14(x[17].wrapping_mul(11003).wrapping_add(x[15].wrapping_mul(12140))); + let v78 = r14(x[9].wrapping_mul(7005).wrapping_add(x[23].wrapping_mul(-14811))); + let v79 = r14(x[9].wrapping_mul(14811).wrapping_add(x[23].wrapping_mul(7005))); + let v80 = r14(x[25].wrapping_mul(15426).wrapping_add(x[7].wrapping_mul(-5520))); + let v81 = r14(x[25].wrapping_mul(5520).wrapping_add(x[7].wrapping_mul(15426))); + let v82 = r14(x[5].wrapping_mul(3981).wrapping_add(x[27].wrapping_mul(-15893))); + let v83 = r14(x[5].wrapping_mul(15893).wrapping_add(x[27].wrapping_mul(3981))); + let v84 = r14(x[21].wrapping_mul(14053).wrapping_add(x[11].wrapping_mul(-8423))); + let v85 = r14(x[21].wrapping_mul(8423).wrapping_add(x[11].wrapping_mul(14053))); + let v86 = r14(x[13].wrapping_mul(9760).wrapping_add(x[19].wrapping_mul(-13160))); + let v87 = r14(x[13].wrapping_mul(13160).wrapping_add(x[19].wrapping_mul(9760))); + let v88 = r14(x[29].wrapping_mul(16207).wrapping_add(x[3].wrapping_mul(-2404))); + let v89 = r14(x[29].wrapping_mul(2404).wrapping_add(x[3].wrapping_mul(16207))); + let v90 = v74.wrapping_add(v76); + let v91 = v74.wrapping_sub(v76); + let v92 = v80.wrapping_add(v78); + let v93 = v80.wrapping_sub(v78); + let v94 = v82.wrapping_add(v84); + let v95 = v82.wrapping_sub(v84); + let v96 = v88.wrapping_add(v86); + let v97 = v88.wrapping_sub(v86); + let v98 = v89.wrapping_add(v87); + let v99 = v89.wrapping_sub(v87); + let v100 = v83.wrapping_add(v85); + let v101 = v83.wrapping_sub(v85); + let v102 = v81.wrapping_add(v79); + let v103 = v81.wrapping_sub(v79); + let v104 = v75.wrapping_add(v77); + let v105 = v75.wrapping_sub(v77); + let v106 = r14(v105.wrapping_mul(3196).wrapping_add(v91.wrapping_mul(-16069))); + let v107 = r14(v105.wrapping_mul(16069).wrapping_add(v91.wrapping_mul(3196))); + let v108 = r14(v97.wrapping_mul(-9102).wrapping_add(v99.wrapping_mul(13623))); + let v109 = r14(v97.wrapping_mul(-13623).wrapping_add(v99.wrapping_mul(-9102))); + let v110 = r14(v101.wrapping_mul(13623).wrapping_add(v95.wrapping_mul(-9102))); + let v111 = r14(v101.wrapping_mul(9102).wrapping_add(v95.wrapping_mul(13623))); + let v112 = r14(v93.wrapping_mul(-16069).wrapping_add(v103.wrapping_mul(3196))); + let v113 = r14(v93.wrapping_mul(-3196).wrapping_add(v103.wrapping_mul(-16069))); + let v114 = v90.wrapping_add(v92); + let v115 = v90.wrapping_sub(v92); + let v116 = v96.wrapping_add(v94); + let v117 = v96.wrapping_sub(v94); + let v118 = v98.wrapping_add(v100); + let v119 = v98.wrapping_sub(v100); + let v120 = v104.wrapping_add(v102); + let v121 = v104.wrapping_sub(v102); + let v122 = v106.wrapping_add(v113); + let v123 = v106.wrapping_sub(v113); + let v124 = v109.wrapping_add(v110); + let v125 = v109.wrapping_sub(v110); + let v126 = v108.wrapping_add(v111); + let v127 = v108.wrapping_sub(v111); + let v128 = v107.wrapping_add(v112); + let v129 = v107.wrapping_sub(v112); + let v130 = r14(v129.wrapping_mul(6270).wrapping_add(v123.wrapping_mul(-15137))); + let v131 = r14(v129.wrapping_mul(15137).wrapping_add(v123.wrapping_mul(6270))); + let v132 = r14(v125.wrapping_mul(-15137).wrapping_add(v127.wrapping_mul(6270))); + let v133 = r14(v125.wrapping_mul(-6270).wrapping_add(v127.wrapping_mul(-15137))); + let v134 = r14(v121.wrapping_mul(6270).wrapping_add(v115.wrapping_mul(-15137))); + let v135 = r14(v121.wrapping_mul(15137).wrapping_add(v115.wrapping_mul(6270))); + let v136 = r14(v117.wrapping_mul(-15137).wrapping_add(v119.wrapping_mul(6270))); + let v137 = r14(v117.wrapping_mul(-6270).wrapping_add(v119.wrapping_mul(-15137))); + let v138 = v114.wrapping_add(v116); + let v139 = v114.wrapping_sub(v116); + let v140 = v120.wrapping_add(v118); + let v141 = v120.wrapping_sub(v118); + let v142 = v122.wrapping_add(v124); + let v143 = v122.wrapping_sub(v124); + let v144 = v128.wrapping_add(v126); + let v145 = v128.wrapping_sub(v126); + let v146 = v130.wrapping_add(v133); + let v147 = v130.wrapping_sub(v133); + let v148 = v131.wrapping_add(v132); + let v149 = v131.wrapping_sub(v132); + let v150 = v134.wrapping_add(v137); + let v151 = v134.wrapping_sub(v137); + let v152 = v135.wrapping_add(v136); + let v153 = v135.wrapping_sub(v136); + let v154 = r14(v153.wrapping_mul(11585).wrapping_add(v151.wrapping_mul(-11585))); + let v155 = r14(v153.wrapping_mul(11585).wrapping_add(v151.wrapping_mul(11585))); + let v156 = r14(v149.wrapping_mul(11585).wrapping_add(v147.wrapping_mul(-11585))); + let v157 = r14(v149.wrapping_mul(11585).wrapping_add(v147.wrapping_mul(11585))); + let v158 = r14(v145.wrapping_mul(11585).wrapping_add(v143.wrapping_mul(-11585))); + let v159 = r14(v145.wrapping_mul(11585).wrapping_add(v143.wrapping_mul(11585))); + let v160 = r14(v141.wrapping_mul(11585).wrapping_add(v139.wrapping_mul(-11585))); + let v161 = r14(v141.wrapping_mul(11585).wrapping_add(v139.wrapping_mul(11585))); + let v162 = v58.wrapping_add(v140); + let v163 = v58.wrapping_sub(v140); + let v164 = v60.wrapping_add(v144); + let v165 = v60.wrapping_sub(v144); + let v166 = v62.wrapping_add(v148); + let v167 = v62.wrapping_sub(v148); + let v168 = v64.wrapping_add(v152); + let v169 = v64.wrapping_sub(v152); + let v170 = v66.wrapping_add(v155); + let v171 = v66.wrapping_sub(v155); + let v172 = v68.wrapping_add(v157); + let v173 = v68.wrapping_sub(v157); + let v174 = v70.wrapping_add(v159); + let v175 = v70.wrapping_sub(v159); + let v176 = v72.wrapping_add(v161); + let v177 = v72.wrapping_sub(v161); + let v178 = v73.wrapping_add(v160); + let v179 = v73.wrapping_sub(v160); + let v180 = v71.wrapping_add(v158); + let v181 = v71.wrapping_sub(v158); + let v182 = v69.wrapping_add(v156); + let v183 = v69.wrapping_sub(v156); + let v184 = v67.wrapping_add(v154); + let v185 = v67.wrapping_sub(v154); + let v186 = v65.wrapping_add(v150); + let v187 = v65.wrapping_sub(v150); + let v188 = v63.wrapping_add(v146); + let v189 = v63.wrapping_sub(v146); + let v190 = v61.wrapping_add(v142); + let v191 = v61.wrapping_sub(v142); + let v192 = v59.wrapping_add(v138); + let v193 = v59.wrapping_sub(v138); [v162, v164, v166, v168, v170, v172, v174, v176, v178, v180, v182, v184, v186, v188, v190, v192, v193, v191, v189, v187, v185, v183, v181, v179, v177, v175, v173, v171, v169, v167, v165, v163] } #[inline(always)] pub fn iadst8(x: [$t; 8]) -> [$t; 8] { - let v0 = x[7] * 1606 - x[0] * 16305; - let v1 = x[7] * 16305 + x[0] * 1606; - let v2 = x[5] * 7723 - x[2] * 14449; - let v3 = x[5] * 14449 + x[2] * 7723; - let v4 = x[3] * 12665 - x[4] * 10394; - let v5 = x[3] * 10394 + x[4] * 12665; - let v6 = x[1] * 15679 - x[6] * 4756; - let v7 = x[1] * 4756 + x[6] * 15679; - let v8 = r14(v1 + v5); - let v9 = r14(v1 - v5); - let v10 = r14(v0 + v4); - let v11 = r14(v0 - v4); - let v12 = r14(v3 + v7); - let v13 = r14(v3 - v7); - let v14 = r14(v2 + v6); - let v15 = r14(v2 - v6); - let v16 = v9 * 6270 - v11 * 15137; - let v17 = v9 * 15137 + v11 * 6270; - let v18 = v15 * 15137 - v13 * 6270; - let v19 = v15 * 6270 + v13 * 15137; - let v20 = r14(v17 + v18); - let v21 = r14(v17 - v18); - let v22 = r14(v16 + v19); - let v23 = r14(v16 - v19); - let v24 = v8 + v12; - let v25 = v8 - v12; - let v26 = v10 + v14; - let v27 = v10 - v14; - let v28 = r14(v25 * 11585 - v27 * 11585); - let v29 = r14(v25 * 11585 + v27 * 11585); - let v30 = r14(v21 * 11585 - v23 * 11585); - let v31 = r14(v21 * 11585 + v23 * 11585); - let v32 = -v20; - let v33 = -v29; - let v34 = -v30; - let v35 = -v26; + let v0 = x[7].wrapping_mul(1606).wrapping_add(x[0].wrapping_mul(-16305)); + let v1 = x[7].wrapping_mul(16305).wrapping_add(x[0].wrapping_mul(1606)); + let v2 = x[5].wrapping_mul(7723).wrapping_add(x[2].wrapping_mul(-14449)); + let v3 = x[5].wrapping_mul(14449).wrapping_add(x[2].wrapping_mul(7723)); + let v4 = x[3].wrapping_mul(12665).wrapping_add(x[4].wrapping_mul(-10394)); + let v5 = x[3].wrapping_mul(10394).wrapping_add(x[4].wrapping_mul(12665)); + let v6 = x[1].wrapping_mul(15679).wrapping_add(x[6].wrapping_mul(-4756)); + let v7 = x[1].wrapping_mul(4756).wrapping_add(x[6].wrapping_mul(15679)); + let v8 = r14(v1.wrapping_add(v5)); + let v9 = r14(v1.wrapping_sub(v5)); + let v10 = r14(v0.wrapping_add(v4)); + let v11 = r14(v0.wrapping_sub(v4)); + let v12 = r14(v3.wrapping_add(v7)); + let v13 = r14(v3.wrapping_sub(v7)); + let v14 = r14(v2.wrapping_add(v6)); + let v15 = r14(v2.wrapping_sub(v6)); + let v16 = v9.wrapping_mul(6270).wrapping_add(v11.wrapping_mul(-15137)); + let v17 = v9.wrapping_mul(15137).wrapping_add(v11.wrapping_mul(6270)); + let v18 = v15.wrapping_mul(15137).wrapping_add(v13.wrapping_mul(-6270)); + let v19 = v15.wrapping_mul(6270).wrapping_add(v13.wrapping_mul(15137)); + let v20 = r14(v17.wrapping_add(v18)); + let v21 = r14(v17.wrapping_sub(v18)); + let v22 = r14(v16.wrapping_add(v19)); + let v23 = r14(v16.wrapping_sub(v19)); + let v24 = v8.wrapping_add(v12); + let v25 = v8.wrapping_sub(v12); + let v26 = v10.wrapping_add(v14); + let v27 = v10.wrapping_sub(v14); + let v28 = r14(v25.wrapping_mul(11585).wrapping_add(v27.wrapping_mul(-11585))); + let v29 = r14(v25.wrapping_mul(11585).wrapping_add(v27.wrapping_mul(11585))); + let v30 = r14(v21.wrapping_mul(11585).wrapping_add(v23.wrapping_mul(-11585))); + let v31 = r14(v21.wrapping_mul(11585).wrapping_add(v23.wrapping_mul(11585))); + let v32 = v20.wrapping_neg(); + let v33 = v29.wrapping_neg(); + let v34 = v30.wrapping_neg(); + let v35 = v26.wrapping_neg(); [v24, v32, v31, v33, v28, v34, v22, v35] } #[inline(always)] pub fn iadst16(x: [$t; 16]) -> [$t; 16] { - let v0 = x[15] * 804 - x[0] * 16364; - let v1 = x[15] * 16364 + x[0] * 804; - let v2 = x[13] * 3981 - x[2] * 15893; - let v3 = x[13] * 15893 + x[2] * 3981; - let v4 = x[11] * 7005 - x[4] * 14811; - let v5 = x[11] * 14811 + x[4] * 7005; - let v6 = x[9] * 9760 - x[6] * 13160; - let v7 = x[9] * 13160 + x[6] * 9760; - let v8 = x[7] * 12140 - x[8] * 11003; - let v9 = x[7] * 11003 + x[8] * 12140; - let v10 = x[5] * 14053 - x[10] * 8423; - let v11 = x[5] * 8423 + x[10] * 14053; - let v12 = x[3] * 15426 - x[12] * 5520; - let v13 = x[3] * 5520 + x[12] * 15426; - let v14 = x[1] * 16207 - x[14] * 2404; - let v15 = x[1] * 2404 + x[14] * 16207; - let v16 = r14(v1 + v9); - let v17 = r14(v1 - v9); - let v18 = r14(v0 + v8); - let v19 = r14(v0 - v8); - let v20 = r14(v3 + v11); - let v21 = r14(v3 - v11); - let v22 = r14(v2 + v10); - let v23 = r14(v2 - v10); - let v24 = r14(v5 + v13); - let v25 = r14(v5 - v13); - let v26 = r14(v4 + v12); - let v27 = r14(v4 - v12); - let v28 = r14(v7 + v15); - let v29 = r14(v7 - v15); - let v30 = r14(v6 + v14); - let v31 = r14(v6 - v14); - let v32 = v17 * 3196 - v19 * 16069; - let v33 = v17 * 16069 + v19 * 3196; - let v34 = v21 * 13623 - v23 * 9102; - let v35 = v21 * 9102 + v23 * 13623; - let v36 = v25 * 16069 + v27 * 3196; - let v37 = -v25 * 3196 + v27 * 16069; - let v38 = v29 * 9102 + v31 * 13623; - let v39 = -v29 * 13623 + v31 * 9102; - let v40 = r14(v33 + v37); - let v41 = r14(v33 - v37); - let v42 = r14(v32 + v36); - let v43 = r14(v32 - v36); - let v44 = r14(v35 + v39); - let v45 = r14(v35 - v39); - let v46 = r14(v34 + v38); - let v47 = r14(v34 - v38); - let v48 = v16 + v24; - let v49 = v16 - v24; - let v50 = v18 + v26; - let v51 = v18 - v26; - let v52 = v20 + v28; - let v53 = v20 - v28; - let v54 = v22 + v30; - let v55 = v22 - v30; - let v56 = v49 * 6270 - v51 * 15137; - let v57 = v49 * 15137 + v51 * 6270; - let v58 = v55 * 15137 - v53 * 6270; - let v59 = v55 * 6270 + v53 * 15137; - let v60 = v41 * 6270 - v43 * 15137; - let v61 = v41 * 15137 + v43 * 6270; - let v62 = v47 * 15137 - v45 * 6270; - let v63 = v47 * 6270 + v45 * 15137; - let v64 = r14(v57 + v58); - let v65 = r14(v57 - v58); - let v66 = r14(v61 + v62); - let v67 = r14(v61 - v62); - let v68 = r14(v56 + v59); - let v69 = r14(v56 - v59); - let v70 = r14(v60 + v63); - let v71 = r14(v60 - v63); - let v72 = v48 + v52; - let v73 = v48 - v52; - let v74 = v40 + v44; - let v75 = v40 - v44; - let v76 = v50 + v54; - let v77 = v50 - v54; - let v78 = v42 + v46; - let v79 = v42 - v46; - let v80 = r14(-v73 * 11585 - v77 * 11585); - let v81 = r14(v73 * 11585 - v77 * 11585); - let v82 = r14(v65 * 11585 + v69 * 11585); - let v83 = r14(-v65 * 11585 + v69 * 11585); - let v84 = r14(v75 * 11585 + v79 * 11585); - let v85 = r14(-v75 * 11585 + v79 * 11585); - let v86 = r14(-v67 * 11585 - v71 * 11585); - let v87 = r14(v67 * 11585 - v71 * 11585); - let v88 = -v74; - let v89 = -v70; - let v90 = -v64; - let v91 = -v76; + let v0 = x[15].wrapping_mul(804).wrapping_add(x[0].wrapping_mul(-16364)); + let v1 = x[15].wrapping_mul(16364).wrapping_add(x[0].wrapping_mul(804)); + let v2 = x[13].wrapping_mul(3981).wrapping_add(x[2].wrapping_mul(-15893)); + let v3 = x[13].wrapping_mul(15893).wrapping_add(x[2].wrapping_mul(3981)); + let v4 = x[11].wrapping_mul(7005).wrapping_add(x[4].wrapping_mul(-14811)); + let v5 = x[11].wrapping_mul(14811).wrapping_add(x[4].wrapping_mul(7005)); + let v6 = x[9].wrapping_mul(9760).wrapping_add(x[6].wrapping_mul(-13160)); + let v7 = x[9].wrapping_mul(13160).wrapping_add(x[6].wrapping_mul(9760)); + let v8 = x[7].wrapping_mul(12140).wrapping_add(x[8].wrapping_mul(-11003)); + let v9 = x[7].wrapping_mul(11003).wrapping_add(x[8].wrapping_mul(12140)); + let v10 = x[5].wrapping_mul(14053).wrapping_add(x[10].wrapping_mul(-8423)); + let v11 = x[5].wrapping_mul(8423).wrapping_add(x[10].wrapping_mul(14053)); + let v12 = x[3].wrapping_mul(15426).wrapping_add(x[12].wrapping_mul(-5520)); + let v13 = x[3].wrapping_mul(5520).wrapping_add(x[12].wrapping_mul(15426)); + let v14 = x[1].wrapping_mul(16207).wrapping_add(x[14].wrapping_mul(-2404)); + let v15 = x[1].wrapping_mul(2404).wrapping_add(x[14].wrapping_mul(16207)); + let v16 = r14(v1.wrapping_add(v9)); + let v17 = r14(v1.wrapping_sub(v9)); + let v18 = r14(v0.wrapping_add(v8)); + let v19 = r14(v0.wrapping_sub(v8)); + let v20 = r14(v3.wrapping_add(v11)); + let v21 = r14(v3.wrapping_sub(v11)); + let v22 = r14(v2.wrapping_add(v10)); + let v23 = r14(v2.wrapping_sub(v10)); + let v24 = r14(v5.wrapping_add(v13)); + let v25 = r14(v5.wrapping_sub(v13)); + let v26 = r14(v4.wrapping_add(v12)); + let v27 = r14(v4.wrapping_sub(v12)); + let v28 = r14(v7.wrapping_add(v15)); + let v29 = r14(v7.wrapping_sub(v15)); + let v30 = r14(v6.wrapping_add(v14)); + let v31 = r14(v6.wrapping_sub(v14)); + let v32 = v17.wrapping_mul(3196).wrapping_add(v19.wrapping_mul(-16069)); + let v33 = v17.wrapping_mul(16069).wrapping_add(v19.wrapping_mul(3196)); + let v34 = v21.wrapping_mul(13623).wrapping_add(v23.wrapping_mul(-9102)); + let v35 = v21.wrapping_mul(9102).wrapping_add(v23.wrapping_mul(13623)); + let v36 = v25.wrapping_mul(16069).wrapping_add(v27.wrapping_mul(3196)); + let v37 = v25.wrapping_mul(-3196).wrapping_add(v27.wrapping_mul(16069)); + let v38 = v29.wrapping_mul(9102).wrapping_add(v31.wrapping_mul(13623)); + let v39 = v29.wrapping_mul(-13623).wrapping_add(v31.wrapping_mul(9102)); + let v40 = r14(v33.wrapping_add(v37)); + let v41 = r14(v33.wrapping_sub(v37)); + let v42 = r14(v32.wrapping_add(v36)); + let v43 = r14(v32.wrapping_sub(v36)); + let v44 = r14(v35.wrapping_add(v39)); + let v45 = r14(v35.wrapping_sub(v39)); + let v46 = r14(v34.wrapping_add(v38)); + let v47 = r14(v34.wrapping_sub(v38)); + let v48 = v16.wrapping_add(v24); + let v49 = v16.wrapping_sub(v24); + let v50 = v18.wrapping_add(v26); + let v51 = v18.wrapping_sub(v26); + let v52 = v20.wrapping_add(v28); + let v53 = v20.wrapping_sub(v28); + let v54 = v22.wrapping_add(v30); + let v55 = v22.wrapping_sub(v30); + let v56 = v49.wrapping_mul(6270).wrapping_add(v51.wrapping_mul(-15137)); + let v57 = v49.wrapping_mul(15137).wrapping_add(v51.wrapping_mul(6270)); + let v58 = v55.wrapping_mul(15137).wrapping_add(v53.wrapping_mul(-6270)); + let v59 = v55.wrapping_mul(6270).wrapping_add(v53.wrapping_mul(15137)); + let v60 = v41.wrapping_mul(6270).wrapping_add(v43.wrapping_mul(-15137)); + let v61 = v41.wrapping_mul(15137).wrapping_add(v43.wrapping_mul(6270)); + let v62 = v47.wrapping_mul(15137).wrapping_add(v45.wrapping_mul(-6270)); + let v63 = v47.wrapping_mul(6270).wrapping_add(v45.wrapping_mul(15137)); + let v64 = r14(v57.wrapping_add(v58)); + let v65 = r14(v57.wrapping_sub(v58)); + let v66 = r14(v61.wrapping_add(v62)); + let v67 = r14(v61.wrapping_sub(v62)); + let v68 = r14(v56.wrapping_add(v59)); + let v69 = r14(v56.wrapping_sub(v59)); + let v70 = r14(v60.wrapping_add(v63)); + let v71 = r14(v60.wrapping_sub(v63)); + let v72 = v48.wrapping_add(v52); + let v73 = v48.wrapping_sub(v52); + let v74 = v40.wrapping_add(v44); + let v75 = v40.wrapping_sub(v44); + let v76 = v50.wrapping_add(v54); + let v77 = v50.wrapping_sub(v54); + let v78 = v42.wrapping_add(v46); + let v79 = v42.wrapping_sub(v46); + let v80 = r14(v73.wrapping_mul(-11585).wrapping_add(v77.wrapping_mul(-11585))); + let v81 = r14(v73.wrapping_mul(11585).wrapping_add(v77.wrapping_mul(-11585))); + let v82 = r14(v65.wrapping_mul(11585).wrapping_add(v69.wrapping_mul(11585))); + let v83 = r14(v65.wrapping_mul(-11585).wrapping_add(v69.wrapping_mul(11585))); + let v84 = r14(v75.wrapping_mul(11585).wrapping_add(v79.wrapping_mul(11585))); + let v85 = r14(v75.wrapping_mul(-11585).wrapping_add(v79.wrapping_mul(11585))); + let v86 = r14(v67.wrapping_mul(-11585).wrapping_add(v71.wrapping_mul(-11585))); + let v87 = r14(v67.wrapping_mul(11585).wrapping_add(v71.wrapping_mul(-11585))); + let v88 = v74.wrapping_neg(); + let v89 = v70.wrapping_neg(); + let v90 = v64.wrapping_neg(); + let v91 = v76.wrapping_neg(); [v72, v88, v66, v90, v82, v86, v84, v80, v81, v85, v87, v83, v68, v89, v78, v91] } diff --git a/crates/vp9/tests/common/mod.rs b/crates/vp9/tests/common/mod.rs index 420541d17..1eed03afc 100644 --- a/crates/vp9/tests/common/mod.rs +++ b/crates/vp9/tests/common/mod.rs @@ -35,38 +35,103 @@ const P420_10: &str = "yuv420p10le"; pub const FIXTURES: &[Fixture] = &[ fx!("intra_only_keyframes", "testsrc2", 352, 288, 3, NOISE, P420, ["-g", "1", "-b:v", "1M"]), - fx!("default_good", "testsrc2", 352, 288, 20, NOISE, P420, ["-b:v", "800k"]), - fx!("profile2_10bit", "testsrc2", 352, 288, 12, NOISE, P420_10, ["-b:v", "800k", "-profile:v", "2"]), - fx!("profile2_12bit", "mandelbrot", 176, 144, 8, NOISE, "yuv420p12le", ["-b:v", "500k", "-profile:v", "2"]), - fx!("profile1_444", "testsrc2", 176, 144, 8, NOISE, "yuv444p", ["-b:v", "500k", "-profile:v", "1"]), - fx!("profile1_422", "testsrc2", 176, 144, 8, NOISE, "yuv422p", ["-b:v", "500k", "-profile:v", "1"]), - fx!("profile1_440", "testsrc2", 176, 144, 8, NOISE, "yuv440p", ["-b:v", "500k", "-profile:v", "1"]), - fx!("profile3_444_10bit", "testsrc2", 176, 144, 6, NOISE, "yuv444p10le", ["-b:v", "500k", "-profile:v", "3"]), - fx!("lossless", "testsrc2", 176, 144, 5, NOISE, P420, ["-lossless", "1"]), - fx!("lossless_10bit", "mandelbrot", 176, 144, 4, NOISE, P420_10, ["-lossless", "1", "-profile:v", "2"]), - fx!("tiles_cols4", "testsrc2", 1280, 720, 6, NOISE, P420, ["-b:v", "2M", "-tile-columns", "2", "-speed", "4"]), - fx!("tiles_rows_cols", "testsrc2", 1280, 720, 6, NOISE, P420, ["-b:v", "2M", "-tile-columns", "2", "-tile-rows", "2", "-speed", "4"]), - fx!("altref_hidden", "testsrc2", 352, 288, 30, NOISE, P420, ["-b:v", "600k", "-auto-alt-ref", "1", "-lag-in-frames", "25"]), + fx!("default_good", "testsrc2", 352, 288, 20, NOISE, P420, ["-b:v", "800k", "-frame-parallel", "0"]), + fx!("profile2_10bit", "testsrc2", 352, 288, 12, NOISE, P420_10, ["-b:v", "800k", "-profile:v", "2", "-frame-parallel", "0"]), + fx!("profile2_12bit", "mandelbrot", 176, 144, 8, NOISE, "yuv420p12le", ["-b:v", "500k", "-profile:v", "2", "-frame-parallel", "0"]), + fx!("profile1_444", "testsrc2", 176, 144, 8, NOISE, "yuv444p", ["-b:v", "500k", "-profile:v", "1", "-frame-parallel", "0"]), + fx!("profile1_422", "testsrc2", 176, 144, 8, NOISE, "yuv422p", ["-b:v", "500k", "-profile:v", "1", "-frame-parallel", "0"]), + fx!("profile1_440", "testsrc2", 176, 144, 8, NOISE, "yuv440p", ["-b:v", "500k", "-profile:v", "1", "-frame-parallel", "0"]), + fx!("profile3_444_10bit", "testsrc2", 176, 144, 6, NOISE, "yuv444p10le", ["-b:v", "500k", "-profile:v", "3", "-frame-parallel", "0"]), + fx!("profile3_422_12bit", "mandelbrot", 176, 144, 6, NOISE, "yuv422p12le", ["-b:v", "500k", "-profile:v", "3", "-frame-parallel", "0"]), + fx!("lossless", "testsrc2", 176, 144, 5, NOISE, P420, ["-lossless", "1", "-frame-parallel", "0"]), + fx!("lossless_10bit", "mandelbrot", 176, 144, 4, NOISE, P420_10, ["-lossless", "1", "-profile:v", "2", "-frame-parallel", "0"]), + fx!("tiles_cols4", "testsrc2", 1280, 720, 6, NOISE, P420, ["-b:v", "2M", "-tile-columns", "2", "-speed", "4", "-frame-parallel", "0"]), + fx!( + "tiles_rows_cols", + "testsrc2", + 1280, + 720, + 6, + NOISE, + P420, + ["-b:v", "2M", "-tile-columns", "1", "-tile-rows", "2", "-speed", "4", "-frame-parallel", "0"] + ), + fx!("tiles_rows4", "testsrc2", 640, 480, 5, NOISE, P420, ["-b:v", "1M", "-tile-columns", "0", "-tile-rows", "2", "-frame-parallel", "0"]), + fx!( + "altref_hidden", + "testsrc2", + 352, + 288, + 30, + NOISE, + P420, + ["2pass", "-b:v", "600k", "-auto-alt-ref", "1", "-lag-in-frames", "25", "-frame-parallel", "0"] + ), + fx!( + "altref_10bit", + "mandelbrot", + 352, + 288, + 24, + NOISE, + P420_10, + ["2pass", "-b:v", "600k", "-profile:v", "2", "-auto-alt-ref", "1", "-lag-in-frames", "16", "-frame-parallel", "0"] + ), + fx!( + "altref_tiles", + "testsrc2", + 1280, + 720, + 12, + NOISE, + P420, + ["2pass", "-b:v", "2M", "-auto-alt-ref", "1", "-lag-in-frames", "10", "-tile-columns", "2", "-speed", "2", "-frame-parallel", "0"] + ), fx!("frame_parallel", "testsrc2", 352, 288, 16, NOISE, P420, ["-b:v", "600k", "-frame-parallel", "1"]), - fx!("frame_parallel_off", "testsrc2", 352, 288, 16, NOISE, P420, ["-b:v", "600k", "-frame-parallel", "0"]), fx!("error_resilient", "testsrc2", 352, 288, 16, NOISE, P420, ["-b:v", "600k", "-error-resilient", "1"]), - fx!("odd_size", "testsrc2", 347, 251, 10, NOISE, P420, ["-b:v", "600k"]), - fx!("tiny_odd", "testsrc2", 33, 17, 8, NOISE, P420, ["-b:v", "200k"]), - fx!("row_mt", "testsrc2", 640, 360, 10, NOISE, P420, ["-b:v", "1M", "-row-mt", "1", "-tile-columns", "1"]), - fx!("speed0", "mandelbrot", 176, 144, 8, NOISE, P420, ["-b:v", "300k", "-speed", "0"]), - fx!("speed2", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "2"]), - fx!("speed5", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "5", "-deadline", "realtime"]), - fx!("speed8", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "8", "-deadline", "realtime"]), - fx!("cq_low", "testsrc2", 352, 288, 8, NOISE, P420, ["-crf", "0", "-b:v", "0"]), - fx!("cq_high", "testsrc2", 352, 288, 12, NOISE, P420, ["-crf", "63", "-b:v", "0"]), - fx!("cq_10bit_low", "testsrc2", 176, 144, 6, NOISE, P420_10, ["-crf", "2", "-b:v", "0", "-profile:v", "2"]), - fx!("aq_segmentation", "testsrc2", 352, 288, 12, NOISE, P420, ["-b:v", "600k", "-aq-mode", "3"]), - fx!("aq_variance", "mandelbrot", 352, 288, 12, NOISE, P420, ["-b:v", "600k", "-aq-mode", "1"]), - fx!("sharpness", "testsrc2", 352, 288, 8, NOISE, P420, ["-b:v", "400k", "-sharpness", "5"]), - fx!("fade_intra_heavy", "testsrc2", 352, 288, 20, "fade=in:0:15", P420, ["-b:v", "400k", "-g", "8"]), + fx!("odd_size", "testsrc2", 347, 251, 10, NOISE, P420, ["-b:v", "600k", "-frame-parallel", "0"]), + fx!("tiny_odd", "testsrc2", 33, 17, 8, NOISE, P420, ["-b:v", "200k", "-frame-parallel", "0"]), + fx!("row_mt", "testsrc2", 640, 360, 10, NOISE, P420, ["-b:v", "1M", "-row-mt", "1", "-tile-columns", "1", "-frame-parallel", "0"]), + fx!("speed0", "mandelbrot", 176, 144, 8, NOISE, P420, ["2pass", "-b:v", "300k", "-speed", "0", "-frame-parallel", "0"]), + fx!("speed1", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "1", "-frame-parallel", "0"]), + fx!("speed2", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "2", "-frame-parallel", "0"]), + fx!("speed3", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "3", "-frame-parallel", "0"]), + fx!("speed4", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "4", "-frame-parallel", "0"]), + fx!("speed5", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "5", "-deadline", "realtime", "-frame-parallel", "0"]), + fx!("speed6", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "6", "-deadline", "realtime", "-frame-parallel", "0"]), + fx!("speed7", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "7", "-deadline", "realtime", "-frame-parallel", "0"]), + fx!("speed8", "testsrc2", 352, 288, 10, NOISE, P420, ["-b:v", "600k", "-speed", "8", "-deadline", "realtime", "-frame-parallel", "0"]), + fx!("cq_low", "testsrc2", 352, 288, 8, NOISE, P420, ["-crf", "0", "-b:v", "0", "-frame-parallel", "0"]), + fx!("cq_q4", "testsrc2", 352, 288, 8, NOISE, P420, ["-crf", "4", "-b:v", "0", "-frame-parallel", "0"]), + fx!("cq_high", "testsrc2", 352, 288, 12, NOISE, P420, ["-crf", "63", "-b:v", "0", "-frame-parallel", "0"]), + fx!("cq_10bit_low", "testsrc2", 176, 144, 6, NOISE, P420_10, ["-crf", "2", "-b:v", "0", "-profile:v", "2", "-frame-parallel", "0"]), + fx!("cq_12bit_high", "testsrc2", 176, 144, 6, NOISE, "yuv420p12le", ["-crf", "60", "-b:v", "0", "-profile:v", "2", "-frame-parallel", "0"]), + fx!("aq_segmentation", "testsrc2", 352, 288, 12, NOISE, P420, ["-b:v", "600k", "-aq-mode", "3", "-frame-parallel", "0"]), + fx!("aq_variance", "mandelbrot", 352, 288, 12, NOISE, P420, ["-b:v", "600k", "-aq-mode", "1", "-frame-parallel", "0"]), + fx!("aq_complexity", "testsrc2", 352, 288, 12, NOISE, P420, ["2pass", "-b:v", "600k", "-aq-mode", "2", "-frame-parallel", "0"]), + fx!("sharpness", "testsrc2", 352, 288, 8, NOISE, P420, ["-b:v", "400k", "-sharpness", "5", "-frame-parallel", "0"]), + fx!("fade_intra_heavy", "testsrc2", 352, 288, 20, "fade=in:0:15", P420, ["-b:v", "400k", "-g", "8", "-frame-parallel", "0"]), fx!("hd_1080p", "testsrc2", 1920, 1080, 3, NOISE, P420, ["-b:v", "4M", "-speed", "5", "-deadline", "realtime"]), - fx!("bench_1080p", "testsrc2", 1920, 1080, 60, "noise=alls=3:allf=t", P420, ["-b:v", "4M", "-speed", "4", "-tile-columns", "2", "-row-mt", "1"]), - fx!("bench_4k", "testsrc2", 3840, 2160, 20, "noise=alls=3:allf=t", P420, ["-b:v", "12M", "-speed", "6", "-tile-columns", "3", "-row-mt", "1"]), + fx!( + "bench_1080p", + "testsrc2", + 1920, + 1080, + 60, + "noise=alls=3:allf=t", + P420, + ["-b:v", "4M", "-speed", "4", "-tile-columns", "2", "-row-mt", "1", "-frame-parallel", "0"] + ), + fx!( + "bench_4k", + "testsrc2", + 3840, + 2160, + 20, + "noise=alls=3:allf=t", + P420, + ["-b:v", "12M", "-speed", "6", "-tile-columns", "3", "-row-mt", "1", "-frame-parallel", "0"] + ), ]; pub fn fixture(name: &str) -> &'static Fixture { @@ -123,7 +188,7 @@ pub fn reference_decode(ivf: &Path, yuv: &Path, pix_fmt: &str) -> bool { let tmp = yuv.with_extension(format!("tmp.{}.yuv", std::process::id())); let mut c = Command::new(&ff); c.args(["-hide_banner", "-loglevel", "error", "-y", "-c:v", "vp9", "-i"]).arg(ivf); - c.args(["-fps_mode", "passthrough", "-f", "rawvideo", "-pix_fmt", pix_fmt]).arg(&tmp); + c.args(["-fps_mode", "passthrough", "-noautoscale", "-f", "rawvideo", "-pix_fmt", pix_fmt]).arg(&tmp); if !run(&mut c) { return false; } @@ -146,16 +211,35 @@ pub fn ensure(f: &Fixture) -> Option<(PathBuf, PathBuf)> { vf.push(','); vf.push_str(f.filter); } - let mut c = Command::new(&ff); - c.args(["-hide_banner", "-loglevel", "error", "-y", "-f", "lavfi", "-i", &vf]); - c.args(["-frames:v", &f.frames.to_string(), "-c:v", "libvpx-vp9", "-pix_fmt", f.pix_fmt]); - c.args(f.args); - c.args(["-f", "ivf"]).arg(&tmp); + let two_pass = f.args.first() == Some(&"2pass"); + let args: Vec<&str> = f.args.iter().copied().filter(|a| *a != "2pass").collect(); + let log = dir.join(format!("{}.{}.passlog", f.name, std::process::id())); + let enc = |pass: Option, out: &Path| { + let mut c = Command::new(&ff); + c.args(["-hide_banner", "-loglevel", "error", "-y", "-f", "lavfi", "-i", &vf]); + c.args(["-frames:v", &f.frames.to_string(), "-c:v", "libvpx-vp9", "-pix_fmt", f.pix_fmt]); + c.args(&args); + if let Some(p) = pass { + c.args(["-pass", &p.to_string(), "-passlogfile"]).arg(&log); + } + if pass == Some(1) { + c.args(["-f", "null", "-"]); + } else { + c.args(["-f", "ivf"]).arg(out); + } + c + }; + if two_pass && !run(&mut enc(Some(1), &tmp)) { + eprintln!("SKIP {}: first pass failed", f.name); + return None; + } + let mut c = enc(if two_pass { Some(2) } else { None }, &tmp); if !run(&mut c) { let _ = std::fs::remove_file(&tmp); eprintln!("SKIP {}: libvpx-vp9 encode failed", f.name); return None; } + let _ = std::fs::remove_file(format!("{}-0.log", log.display())); std::fs::rename(&tmp, &ivf).unwrap(); } if !yuv.exists() { diff --git a/crates/vp9/tests/conformance.rs b/crates/vp9/tests/conformance.rs index 2ad2c0f8a..1528b6469 100644 --- a/crates/vp9/tests/conformance.rs +++ b/crates/vp9/tests/conformance.rs @@ -27,84 +27,42 @@ fixture_tests!( profile1_422, profile1_440, profile3_444_10bit, + profile3_422_12bit, lossless, lossless_10bit, tiles_cols4, tiles_rows_cols, + tiles_rows4, altref_hidden, + altref_10bit, + altref_tiles, frame_parallel, - frame_parallel_off, error_resilient, odd_size, tiny_odd, row_mt, speed0, + speed1, speed2, + speed3, + speed4, speed5, + speed6, + speed7, speed8, cq_low, + cq_q4, cq_high, cq_10bit_low, + cq_12bit_high, aq_segmentation, aq_variance, + aq_complexity, sharpness, fade_intra_heavy, hd_1080p, ); -/// Resolution changes mid-stream: libvpx's `resize_mode` (dynamic internal scaling with scaled -/// reference prediction), and concatenated streams of different sizes. -#[test] -fn resize_dynamic() { - let Some(ff) = common::ffmpeg() else { return }; - let dir = common::fixtures_dir(); - let ivf = dir.join("resize_dynamic.ivf"); - let yuv = dir.join("resize_dynamic.yuv"); - if !ivf.exists() { - // Encode with a spatial resampling switch: first 10 frames at 352x288, then the encoder - // is fed 176x144 content via a scale filter that changes size (ffmpeg reinitialises - // libvpx with a new size without a key frame when `-resize_mode` style scaling is - // unavailable, so emulate with libvpx's internal resize through the `resize-mode` knob - // of vpxenc-like options if present, otherwise concatenation below covers size changes). - let mut c = std::process::Command::new(&ff); - c.args(["-hide_banner", "-loglevel", "error", "-y", "-f", "lavfi", "-i", "testsrc2=size=352x288:rate=25,noise=alls=10:allf=t+u"]); - c.args([ - "-frames:v", - "30", - "-c:v", - "libvpx-vp9", - "-b:v", - "60k", - "-minrate", - "60k", - "-maxrate", - "60k", - "-undershoot-pct", - "0", - "-lag-in-frames", - "0", - "-deadline", - "realtime", - "-speed", - "8", - ]); - c.args(["-vpx-options", "resize-mode=3"]); - c.args(["-f", "ivf"]).arg(&ivf); - if !common::run(&mut c) { - let mut c = std::process::Command::new(&ff); - c.args(["-hide_banner", "-loglevel", "error", "-y", "-f", "lavfi", "-i", "testsrc2=size=352x288:rate=25,noise=alls=10:allf=t+u"]); - c.args(["-frames:v", "30", "-c:v", "libvpx-vp9", "-b:v", "40k", "-deadline", "realtime", "-speed", "8", "-lag-in-frames", "0"]); - c.args(["-f", "ivf"]).arg(&ivf); - assert!(common::run(&mut c)); - } - } - if !yuv.exists() { - assert!(common::reference_decode(&ivf, &yuv, "yuv420p")); - } - let reference = std::fs::read(&yuv).unwrap(); - common::check_files("resize_dynamic", &ivf, &reference, "yuv420p").unwrap(); -} - /// Two streams of different sizes concatenated into one IVF (key frame at the size change). #[test] fn resize_concatenated() { diff --git a/crates/vp9/tests/robustness.rs b/crates/vp9/tests/robustness.rs new file mode 100644 index 000000000..be63331d9 --- /dev/null +++ b/crates/vp9/tests/robustness.rs @@ -0,0 +1,106 @@ +//! Damaged, truncated and random input must never panic or hang (errors are fine). + +mod common; + +use filmcraft_vp9::Decoder; +use std::time::{Duration, Instant}; + +fn xorshift(seed: &mut u64) -> u64 { + *seed ^= *seed << 13; + *seed ^= *seed >> 7; + *seed ^= *seed << 17; + *seed +} + +fn decode_all(frames: &[Vec], threads: usize) { + let mut dec = Decoder::with_threads(threads); + for (i, f) in frames.iter().enumerate() { + let _ = dec.decode(f, i as i64); + } + let _ = dec.flush(); +} + +#[test] +fn corrupted_streams_do_not_panic() { + for name in ["default_good", "altref_hidden", "profile2_10bit", "tiles_cols4", "aq_segmentation", "lossless", "profile1_444", "tiles_rows4"] { + let f = common::fixture(name); + let Some((ivf, _)) = common::ensure(f) else { return }; + let data = std::fs::read(ivf).unwrap(); + let frames: Vec> = common::ivf_frames(&data).into_iter().map(|f| f.to_vec()).collect(); + let mut seed = 0x1234_5678_9abc_def0u64 ^ name.len() as u64; + for round in 0..10 { + let t0 = Instant::now(); + let mut d = frames.clone(); + for _ in 0..(1 + round * 4) { + let fi = (xorshift(&mut seed) as usize) % d.len(); + let fr = &mut d[fi]; + if fr.is_empty() { + continue; + } + let pos = (xorshift(&mut seed) as usize) % fr.len(); + match round % 3 { + 0 => fr[pos] ^= 1 << (xorshift(&mut seed) % 8), + 1 => fr[pos] = xorshift(&mut seed) as u8, + _ => fr.truncate(pos), + } + } + for threads in [1, 4] { + decode_all(&d, threads); + } + assert!(t0.elapsed() < Duration::from_secs(60), "{name} round {round} too slow"); + } + } +} + +#[test] +fn truncated_frames_do_not_panic() { + let f = common::fixture("default_good"); + let Some((ivf, _)) = common::ensure(f) else { return }; + let data = std::fs::read(ivf).unwrap(); + let frames: Vec> = common::ivf_frames(&data).into_iter().map(|f| f.to_vec()).collect(); + for cut in [1usize, 2, 3, 5, 8, 13, 21, 40, 100, 400] { + let d: Vec> = frames.iter().map(|f| f[..cut.min(f.len())].to_vec()).collect(); + decode_all(&d, 1); + decode_all(&d, 3); + } +} + +#[test] +fn garbage_input_is_rejected_gracefully() { + let mut seed = 42u64; + for len in [0usize, 1, 2, 5, 30, 100, 5000] { + for k in 0..40 { + let mut g: Vec = (0..len).map(|_| xorshift(&mut seed) as u8).collect(); + if len > 10 && k % 2 == 0 { + // A plausible key frame start: frame marker, profile 0, key frame, sync code. + g[0] = 0x82; + g[1] = 0x49; + g[2] = 0x83; + g[3] = 0x42; + } + let mut dec = Decoder::with_threads(1 + k % 3); + let _ = dec.decode(&g, 0); + let _ = dec.decode(&g, 1); + } + } + // Inter frame / show_existing without references. + let mut dec = Decoder::new(); + assert!(dec.decode(&[0x88], 0).is_err()); + assert!(dec.decode(&[0x86, 0, 0, 0, 0], 0).is_err()); +} + +/// Huge declared frame sizes must not allocate absurd amounts or panic. +#[test] +fn oversized_frame_is_rejected() { + // Key frame header: marker 2, profile 0, show_existing 0, key, show, no error res, + // sync, color (4 bits), width-1 = 0xffff, height-1 = 0xffff. + let bits = "10".to_string() + "00" + "0" + "0" + "1" + "0" + "010010011000001101000010" + "0000" + &"1".repeat(32); + let mut v = vec![0u8; bits.len().div_ceil(8) + 8]; + for (i, c) in bits.chars().enumerate() { + if c == '1' { + v[i / 8] |= 0x80 >> (i % 8); + } + } + let mut dec = Decoder::new(); + assert!(dec.decode(&v, 0).is_err()); +} diff --git a/crates/vp9/tests/synthetic.rs b/crates/vp9/tests/synthetic.rs new file mode 100644 index 000000000..a01c7a1b8 --- /dev/null +++ b/crates/vp9/tests/synthetic.rs @@ -0,0 +1,357 @@ +//! Streams libvpx (as driven by ffmpeg) does not produce, built by rewriting the uncompressed +//! headers of libvpx-vp9 output, all checked against ffmpeg's decoder: +//! - reference scaling: inter frames of a stream encoded at another size are spliced after a key +//! frame, with their frame size coded explicitly, so they predict from differently sized +//! references (down- and up-scaling); +//! - intra-only frames (a key frame rewritten as a hidden intra-only frame) shown with +//! show_existing_frame; +//! - show_existing_frame of hidden alt-ref frames and of arbitrary slots. + +mod common; + +use std::path::Path; + +struct Bits<'a> { + d: &'a [u8], + pos: usize, +} + +impl Bits<'_> { + fn f(&mut self, n: usize) -> u32 { + let mut v = 0; + for _ in 0..n { + v = (v << 1) | ((self.d[self.pos / 8] >> (7 - self.pos % 8)) & 1) as u32; + self.pos += 1; + } + v + } +} + +#[derive(Default)] +struct W { + bits: Vec, +} + +impl W { + fn put(&mut self, v: u32, n: usize) { + for i in (0..n).rev() { + self.bits.push((v >> i) & 1 == 1); + } + } + fn copy(&mut self, d: &[u8], from: usize, to: usize) { + let mut b = Bits { d, pos: from }; + for _ in from..to { + self.bits.push(b.f(1) == 1); + } + } + fn bytes(&self) -> Vec { + let mut out = vec![0u8; self.bits.len().div_ceil(8)]; + for (i, &b) in self.bits.iter().enumerate() { + if b { + out[i / 8] |= 0x80 >> (i % 8); + } + } + out + } +} + +/// Parse the header fields from refresh_frame_context to header_size_in_bytes (profile 0 +/// layouts); returns the bit position after header_size_in_bytes. +fn parse_tail(b: &mut Bits, error_res: bool, width: u32) -> usize { + if !error_res { + b.f(2); + } + b.f(2); // frame_context_idx + b.f(6); + b.f(3); + if b.f(1) == 1 && b.f(1) == 1 { + for _ in 0..6 { + if b.f(1) == 1 { + b.f(7); + } + } + } + b.f(8); + for _ in 0..3 { + if b.f(1) == 1 { + b.f(5); + } + } + if b.f(1) == 1 { + if b.f(1) == 1 { + for _ in 0..7 { + if b.f(1) == 1 { + b.f(8); + } + } + if b.f(1) == 1 { + for _ in 0..3 { + if b.f(1) == 1 { + b.f(8); + } + } + } + } + if b.f(1) == 1 { + b.f(1); + for _ in 0..8 { + for (bits, signed) in [(8, true), (6, true), (2, false), (0, false)] { + if b.f(1) == 1 { + b.f(bits); + if signed { + b.f(1); + } + } + } + } + } + } + let sb_cols = (width.div_ceil(8)).div_ceil(8); + let mut min_log2 = 0; + while (64 << min_log2) < sb_cols { + min_log2 += 1; + } + let mut max_log2 = 1; + while (sb_cols >> max_log2) >= 4 { + max_log2 += 1; + } + max_log2 -= 1; + let mut l = min_log2; + while l < max_log2 { + if b.f(1) == 1 { + l += 1; + } else { + break; + } + } + if b.f(1) == 1 { + b.f(1); + } + b.f(16); + b.pos +} + +/// Rewrite a profile 0 inter frame so that its frame size (`w` x `h`) is coded explicitly. +fn explicit_size(frame: &[u8], w: u32, h: u32) -> Vec { + let mut b = Bits { d: frame, pos: 0 }; + assert_eq!(b.f(2), 2); + assert_eq!(b.f(2), 0, "profile 0 only"); + assert_eq!(b.f(1), 0, "show_existing"); + assert_eq!(b.f(1), 1, "inter frame expected"); + let show = b.f(1) == 1; + let err = b.f(1) == 1; + if !show { + assert_eq!(b.f(1), 0, "intra-only"); + } + if !err { + b.f(2); + } + b.f(8 + 12); + let found_at = b.pos; + let mut found = false; + for _ in 0..3 { + if b.f(1) == 1 { + found = true; + break; + } + } + if !found { + b.f(32); + } + let after_size = b.pos; + // render_size, allow_high_precision_mv, interpolation filter + if b.f(1) == 1 { + b.f(32); + } + b.f(1); + if b.f(1) == 0 { + b.f(2); + } + let end = parse_tail(&mut b, err, w); + let mut o = W::default(); + o.copy(frame, 0, found_at); + o.put(0, 3); + o.put(w - 1, 16); + o.put(h - 1, 16); + o.copy(frame, after_size, end); + let mut out = o.bytes(); + out.extend_from_slice(&frame[end.div_ceil(8)..]); + out +} + +/// Rewrite a profile 0 key frame as a hidden intra-only frame refreshing `refresh` slots. +fn key_to_intra_only(frame: &[u8], refresh: u8, reset: u32) -> Vec { + let mut b = Bits { d: frame, pos: 0 }; + assert_eq!(b.f(2), 2); + assert_eq!(b.f(2), 0); + assert_eq!(b.f(1), 0); + assert_eq!(b.f(1), 0, "key frame expected"); + b.f(1); // show_frame + let err = b.f(1) == 1; + assert_eq!(b.f(24), 0x498342); + b.f(4); // color_space, color_range + let size_at = b.pos; + let w = b.f(16) + 1; + b.f(16); + if b.f(1) == 1 { + b.f(32); + } + let after_render = b.pos; + let end = parse_tail(&mut b, err, w); + let mut o = W::default(); + o.put(2, 2); + o.put(0, 2); + o.put(0, 1); + o.put(1, 1); // non-key + o.put(0, 1); // hidden + o.put(err as u32, 1); + o.put(1, 1); // intra_only + if !err { + o.put(reset, 2); + } + o.put(0x498342, 24); + o.put(refresh as u32, 8); + o.copy(frame, size_at, after_render); + o.copy(frame, after_render, end); + let mut out = o.bytes(); + out.extend_from_slice(&frame[end.div_ceil(8)..]); + out +} + +fn reference(ivf: &Path, pix_fmt: &str) -> Vec { + let yuv = ivf.with_extension("yuv"); + let _ = std::fs::remove_file(&yuv); + assert!(common::reference_decode(ivf, &yuv, pix_fmt), "ffmpeg failed on {}", ivf.display()); + let r = std::fs::read(&yuv).unwrap(); + let _ = std::fs::remove_file(&yuv); + r +} + +fn encode(name: &str, w: u32, h: u32, frames: u32, extra: &[&str]) -> Option>> { + let ff = common::ffmpeg()?; + let path = common::fixtures_dir().join(format!("{name}.ivf")); + if !path.exists() { + let mut c = std::process::Command::new(ff); + c.args(["-hide_banner", "-loglevel", "error", "-y", "-f", "lavfi", "-i"]); + c.arg(format!("testsrc2=size={w}x{h}:rate=25,noise=alls=8:allf=t+u")); + c.args(["-frames:v", &frames.to_string(), "-c:v", "libvpx-vp9", "-b:v", "500k", "-frame-parallel", "0"]); + c.args(extra); + c.args(["-f", "ivf"]).arg(&path); + if !common::run(&mut c) { + return None; + } + } + let d = std::fs::read(&path).unwrap(); + Some(common::ivf_frames(&d).into_iter().map(|f| f.to_vec()).collect()) +} + +fn check(name: &str, frames: &[Vec]) { + let path = common::fixtures_dir().join(format!("{name}.ivf")); + common::write_ivf(&path, 0, 0, frames); + let r = reference(&path, "yuv420p"); + common::check_files(name, &path, &r, "yuv420p").unwrap(); + let _ = std::fs::remove_file(path); +} + +/// Splice the inter frames of a `w2` x `h2` stream after frames of a 352x288 stream. +fn scaled_splice(name: &str, w2: u32, h2: u32, interp: &[&str]) -> Option>> { + let a = encode("syn_base_352", 352, 288, 6, &[])?; + let mut args = vec!["-error-resilient", "1"]; + args.extend_from_slice(interp); + let b = encode(&format!("syn_er_{w2}x{h2}{}", interp.join("")), w2, h2, 10, &args)?; + let mut frames: Vec> = a[..4].to_vec(); + for f in &b[1..] { + frames.push(explicit_size(f, w2, h2)); + } + let _ = name; + Some(frames) +} + +#[test] +fn scaled_reference_downscale() { + let Some(f) = scaled_splice("down", 256, 208, &[]) else { return }; + let mut dec = filmcraft_vp9::Decoder::with_threads(1); + for c in &f { + let _ = dec.decode(c, 0); + } + assert!(dec.stats().scaled_ref_blocks > 0, "{:?}", dec.stats()); + check("syn_scaled_down", &f); +} + +#[test] +fn splice_same_size_control() { + let Some(f) = scaled_splice("same", 352, 288, &[]) else { return }; + check("syn_same", &f); +} + +#[test] +fn scaled_reference_upscale() { + let Some(f) = scaled_splice("up", 480, 400, &[]) else { return }; + check("syn_scaled_up", &f); +} + +#[test] +fn scaled_reference_odd_sizes() { + let Some(f) = scaled_splice("odd", 301, 199, &[]) else { return }; + check("syn_scaled_odd", &f); +} + +fn build_superframe(frames: &[Vec]) -> Vec { + if frames.len() == 1 { + return frames[0].clone(); + } + let mut out = Vec::new(); + for f in frames { + out.extend_from_slice(f); + } + let marker = 0xc0 | (3 << 3) | (frames.len() as u8 - 1); + out.push(marker); + for f in frames { + out.extend((f.len() as u32).to_le_bytes()); + } + out.push(marker); + out +} + +#[test] +fn intra_only_frames() { + // Error resilient source: the frame after the intra-only frame does not use the previous + // frame's motion vectors either way, so its symbols parse as the encoder intended. + let Some(src) = encode("syn_er_g8", 352, 288, 20, &["-g", "8", "-error-resilient", "1"]) else { return }; + let keys: Vec = src.iter().enumerate().filter(|(_, f)| f[0] & 0x04 == 0 && f[0] & 0x08 == 0).map(|(i, _)| i).collect(); + assert!(keys.len() >= 2, "need a second key frame: {keys:?}"); + for (reset, refresh, show_slot) in [(3u32, 0xffu8, 0u8), (2, 0x05, 2), (0, 0x10, 4)] { + let mut frames = Vec::new(); + for (i, f) in src.iter().enumerate() { + if i == keys[1] { + frames.push(key_to_intra_only(f, refresh, reset)); + frames.push(vec![0x88 | show_slot]); + } else { + frames.push(f.clone()); + } + } + let mut dec = filmcraft_vp9::Decoder::with_threads(1); + for c in &frames { + dec.decode(c, 0).unwrap(); + } + let s = dec.stats(); + assert!(s.intra_only == 1 && s.show_existing == 1, "{s:?}"); + check(&format!("syn_intra_only_{reset}"), &frames); + } +} + +#[test] +fn show_existing_frames() { + let Some(src) = encode("syn_er_352", 352, 288, 6, &["-error-resilient", "1"]) else { return }; + let mut frames = Vec::new(); + for (i, f) in src.iter().enumerate() { + frames.push(f.clone()); + if i >= 1 { + frames.push(vec![0x88 | (i as u8 % 8)]); + } + } + // A superframe holding a frame and a show_existing_frame. + let sf = build_superframe(&[src[2].clone(), vec![0x88]]); + frames.push(sf); + check("syn_show_existing", &frames); +} diff --git a/crates/vp9/tools/gen_transforms.py b/crates/vp9/tools/gen_transforms.py index ab62ce3e4..2e016d4bc 100644 --- a/crates/vp9/tools/gen_transforms.py +++ b/crates/vp9/tools/gen_transforms.py @@ -54,24 +54,15 @@ class Gen: @staticmethod def lin(terms): - parts = [] + # Wrapping arithmetic: conformant streams never overflow (8.7.1.1), damaged ones must not + # panic in debug builds. + s = None for var, c in terms: if c == 0: continue - if c == 1: - parts.append(("+", var)) - elif c == -1: - parts.append(("-", var)) - elif c < 0: - parts.append(("-", "%s * %d" % (var, -c))) - else: - parts.append(("+", "%s * %d" % (var, c))) - if not parts: - return "0" - s = parts[0][1] if parts[0][0] == "+" else "-" + parts[0][1] - for sign, p in parts[1:]: - s += " %s %s" % (sign, p) - return s + t = "%s.wrapping_mul(%d)" % (var, c) + s = t if s is None else "%s.wrapping_add(%s)" % (s, t) + return s if s is not None else "0" def B(self, a, b, angle, flip): ta, tb = self.T[a], self.T[b] @@ -84,8 +75,8 @@ class Gen: if flip: a, b = b, a x, y = self.T[a], self.T[b] - self.T[a] = self.new("%s + %s" % (x, y)) - self.T[b] = self.new("%s - %s" % (x, y)) + self.T[a] = self.new("%s.wrapping_add(%s)" % (x, y)) + self.T[b] = self.new("%s.wrapping_sub(%s)" % (x, y)) def SB(self, a, b, angle, flip): ta, tb = self.T[a], self.T[b] @@ -96,8 +87,8 @@ class Gen: def SH(self, a, b): sa, sb = self.S[a], self.S[b] - self.T[a] = self.new("r14(%s + %s)" % (sa, sb)) - self.T[b] = self.new("r14(%s - %s)" % (sa, sb)) + self.T[a] = self.new("r14(%s.wrapping_add(%s))" % (sa, sb)) + self.T[b] = self.new("r14(%s.wrapping_sub(%s))" % (sa, sb)) def idct_steps(g, n): @@ -165,7 +156,7 @@ def adst_out_perm(g, n): def neg(g, i): - g.T[i] = g.new("-%s" % g.T[i]) + g.T[i] = g.new("%s.wrapping_neg()" % g.T[i]) def adst8(): @@ -239,7 +230,7 @@ print("macro_rules! transforms_1d {") print(" ($t:ty) => {") print(" #[inline(always)]") print(" fn r14(x: $t) -> $t {") -print(" (x + (1 << 13)) >> 14") +print(" x.wrapping_add(1 << 13) >> 14") print(" }") print() for n in range(2, 6):