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 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-09-30 22:37:46 -04:00
co-authored by Claude Opus 5.5
parent 916de99fda
commit 804eb14fa9
10 changed files with 1098 additions and 575 deletions
+38
View File
@@ -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<String> = 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());
}
+1 -9
View File
@@ -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)]
-3
View File
@@ -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
}
+22 -22
View File
@@ -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 {
+431 -431
View File
@@ -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]
}
+119 -35
View File
@@ -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<u32>, 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() {
+12 -54
View File
@@ -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() {
+106
View File
@@ -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<u8>], 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<Vec<u8>> = 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<Vec<u8>> = 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<Vec<u8>> = 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<u8> = (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());
}
+357
View File
@@ -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<bool>,
}
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<u8> {
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<u8> {
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<u8> {
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<u8> {
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<Vec<Vec<u8>>> {
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<u8>]) {
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<Vec<Vec<u8>>> {
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<Vec<u8>> = 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<u8>]) -> Vec<u8> {
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<usize> = 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);
}
+12 -21
View File
@@ -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):