oximedia-codec 0.1.4

Video codec implementations for OxiMedia
Documentation
//! AV1 transform SIMD operations.
//!
//! Implements DCT, ADST, and identity transforms for AV1 encoding/decoding.
//! Supports block sizes from 4x4 to 64x64.

use crate::simd::traits::SimdOpsExt;

/// AV1 transform SIMD operations.
pub struct TransformSimd<S> {
    simd: S,
}

impl<S: SimdOpsExt> TransformSimd<S> {
    /// Create a new transform SIMD instance.
    #[inline]
    pub const fn new(simd: S) -> Self {
        Self { simd }
    }

    /// Forward DCT 4x4 transform.
    ///
    /// Input: 4x4 block of residuals (i16)
    /// Output: 4x4 block of transform coefficients (i16)
    pub fn forward_dct_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
        use crate::simd::types::I16x8;

        // Load input rows
        let mut rows = [I16x8::zero(); 4];
        for i in 0..4 {
            for j in 0..4 {
                rows[i][j] = input[i * 4 + j];
            }
        }

        // 1D DCT on rows
        self.dct_4_1d(&mut rows);

        // Transpose
        let rows = self.simd.transpose_4x4_i16(&rows);

        // 1D DCT on columns (transposed rows)
        let mut cols = rows;
        self.dct_4_1d(&mut cols);

        // Transpose back and store
        let result = self.simd.transpose_4x4_i16(&cols);
        for i in 0..4 {
            for j in 0..4 {
                output[i * 4 + j] = result[i][j];
            }
        }
    }

    /// Inverse DCT 4x4 transform.
    pub fn inverse_dct_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
        use crate::simd::types::I16x8;

        let mut rows = [I16x8::zero(); 4];
        for i in 0..4 {
            for j in 0..4 {
                rows[i][j] = input[i * 4 + j];
            }
        }

        // 1D IDCT on rows
        self.idct_4_1d(&mut rows);

        // Transpose
        let rows = self.simd.transpose_4x4_i16(&rows);

        // 1D IDCT on columns
        let mut cols = rows;
        self.idct_4_1d(&mut cols);

        // Transpose back and store
        let result = self.simd.transpose_4x4_i16(&cols);
        for i in 0..4 {
            for j in 0..4 {
                output[i * 4 + j] = result[i][j];
            }
        }
    }

    /// Forward DCT 8x8 transform.
    pub fn forward_dct_8x8(&self, input: &[i16; 64], output: &mut [i16; 64]) {
        use crate::simd::types::I16x8;

        // Load input rows
        let mut rows = [I16x8::zero(); 8];
        for i in 0..8 {
            for j in 0..8 {
                rows[i][j] = input[i * 8 + j];
            }
        }

        // 1D DCT on rows
        self.dct_8_1d(&mut rows);

        // Transpose
        let rows = self.simd.transpose_8x8_i16(&rows);

        // 1D DCT on columns
        let mut cols = rows;
        self.dct_8_1d(&mut cols);

        // Transpose back and store
        let result = self.simd.transpose_8x8_i16(&cols);
        for i in 0..8 {
            for j in 0..8 {
                output[i * 8 + j] = result[i][j];
            }
        }
    }

    /// Inverse DCT 8x8 transform.
    pub fn inverse_dct_8x8(&self, input: &[i16; 64], output: &mut [i16; 64]) {
        use crate::simd::types::I16x8;

        let mut rows = [I16x8::zero(); 8];
        for i in 0..8 {
            for j in 0..8 {
                rows[i][j] = input[i * 8 + j];
            }
        }

        // 1D IDCT on rows
        self.idct_8_1d(&mut rows);

        // Transpose
        let rows = self.simd.transpose_8x8_i16(&rows);

        // 1D IDCT on columns
        let mut cols = rows;
        self.idct_8_1d(&mut cols);

        // Transpose back and store
        let result = self.simd.transpose_8x8_i16(&cols);
        for i in 0..8 {
            for j in 0..8 {
                output[i * 8 + j] = result[i][j];
            }
        }
    }

    /// Forward ADST 4x4 transform.
    ///
    /// Asymmetric Discrete Sine Transform used for directional prediction residuals.
    pub fn forward_adst_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
        use crate::simd::types::I16x8;

        let mut rows = [I16x8::zero(); 4];
        for i in 0..4 {
            for j in 0..4 {
                rows[i][j] = input[i * 4 + j];
            }
        }

        // 1D ADST on rows
        self.adst_4_1d(&mut rows);

        // Transpose
        let rows = self.simd.transpose_4x4_i16(&rows);

        // 1D ADST on columns
        let mut cols = rows;
        self.adst_4_1d(&mut cols);

        // Transpose back and store
        let result = self.simd.transpose_4x4_i16(&cols);
        for i in 0..4 {
            for j in 0..4 {
                output[i * 4 + j] = result[i][j];
            }
        }
    }

    /// Inverse ADST 4x4 transform.
    pub fn inverse_adst_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
        use crate::simd::types::I16x8;

        let mut rows = [I16x8::zero(); 4];
        for i in 0..4 {
            for j in 0..4 {
                rows[i][j] = input[i * 4 + j];
            }
        }

        // 1D inverse ADST on rows
        self.iadst_4_1d(&mut rows);

        // Transpose
        let rows = self.simd.transpose_4x4_i16(&rows);

        // 1D inverse ADST on columns
        let mut cols = rows;
        self.iadst_4_1d(&mut cols);

        // Transpose back and store
        let result = self.simd.transpose_4x4_i16(&cols);
        for i in 0..4 {
            for j in 0..4 {
                output[i * 4 + j] = result[i][j];
            }
        }
    }

    /// Identity transform (no transform, just scaling).
    pub fn identity_4x4(&self, input: &[i16; 16], output: &mut [i16; 16]) {
        // Identity transform for AV1: output = input * sqrt(2)
        // Approximated as: output = (input * 181 + 128) >> 8
        for i in 0..16 {
            let scaled = i32::from(input[i]) * 181 + 128;
            output[i] = (scaled >> 8) as i16;
        }
    }

    // ========================================================================
    // Internal 1D Transform Helpers
    // ========================================================================

    /// 1D DCT-4 on 4 vectors.
    fn dct_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
        // Simplified DCT-4 using butterfly operations
        // Stage 1: butterflies
        let (s0, s3) = self.simd.butterfly_i16x8(rows[0], rows[3]);
        let (s1, s2) = self.simd.butterfly_i16x8(rows[1], rows[2]);

        // Stage 2: butterflies and rotations
        let (x0, x1) = self.simd.butterfly_i16x8(s0, s1);
        let (x3, x2) = self.simd.butterfly_i16x8(s3, s2);

        rows[0] = x0;
        rows[1] = x2;
        rows[2] = x1;
        rows[3] = x3;
    }

    /// 1D IDCT-4 on 4 vectors.
    fn idct_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
        // Inverse DCT-4
        let t0 = rows[0];
        let t1 = rows[2];
        let t2 = rows[1];
        let t3 = rows[3];

        // Stage 1
        let (s0, s1) = self.simd.butterfly_i16x8(t0, t2);
        let (s3, s2) = self.simd.butterfly_i16x8(t3, t1);

        // Stage 2
        let (x0, x3) = self.simd.butterfly_i16x8(s0, s3);
        let (x1, x2) = self.simd.butterfly_i16x8(s1, s2);

        rows[0] = x0;
        rows[1] = x1;
        rows[2] = x2;
        rows[3] = x3;
    }

    /// 1D DCT-8 on 8 vectors.
    fn dct_8_1d(&self, rows: &mut [crate::simd::types::I16x8; 8]) {
        // Simplified DCT-8 butterfly structure
        // Stage 1
        let (s0, s7) = self.simd.butterfly_i16x8(rows[0], rows[7]);
        let (s1, s6) = self.simd.butterfly_i16x8(rows[1], rows[6]);
        let (s2, s5) = self.simd.butterfly_i16x8(rows[2], rows[5]);
        let (s3, s4) = self.simd.butterfly_i16x8(rows[3], rows[4]);

        // Stage 2
        let (t0, t3) = self.simd.butterfly_i16x8(s0, s3);
        let (t1, t2) = self.simd.butterfly_i16x8(s1, s2);
        let (t4, t7) = self.simd.butterfly_i16x8(s4, s7);
        let (t5, t6) = self.simd.butterfly_i16x8(s5, s6);

        // Stage 3
        let (u0, u1) = self.simd.butterfly_i16x8(t0, t1);
        let (u2, u3) = self.simd.butterfly_i16x8(t2, t3);
        let (u4, u5) = self.simd.butterfly_i16x8(t4, t5);
        let (u6, u7) = self.simd.butterfly_i16x8(t6, t7);

        rows[0] = u0;
        rows[1] = u4;
        rows[2] = u2;
        rows[3] = u6;
        rows[4] = u1;
        rows[5] = u5;
        rows[6] = u3;
        rows[7] = u7;
    }

    /// 1D IDCT-8 on 8 vectors.
    fn idct_8_1d(&self, rows: &mut [crate::simd::types::I16x8; 8]) {
        // Inverse DCT-8
        let t0 = rows[0];
        let t4 = rows[1];
        let t2 = rows[2];
        let t6 = rows[3];
        let t1 = rows[4];
        let t5 = rows[5];
        let t3 = rows[6];
        let t7 = rows[7];

        // Stage 1
        let (s0, s1) = self.simd.butterfly_i16x8(t0, t1);
        let (s2, s3) = self.simd.butterfly_i16x8(t2, t3);
        let (s4, s5) = self.simd.butterfly_i16x8(t4, t5);
        let (s6, s7) = self.simd.butterfly_i16x8(t6, t7);

        // Stage 2
        let (u0, u3) = self.simd.butterfly_i16x8(s0, s3);
        let (u1, u2) = self.simd.butterfly_i16x8(s1, s2);
        let (u4, u7) = self.simd.butterfly_i16x8(s4, s7);
        let (u5, u6) = self.simd.butterfly_i16x8(s5, s6);

        // Stage 3
        let (x0, x7) = self.simd.butterfly_i16x8(u0, u7);
        let (x1, x6) = self.simd.butterfly_i16x8(u1, u6);
        let (x2, x5) = self.simd.butterfly_i16x8(u2, u5);
        let (x3, x4) = self.simd.butterfly_i16x8(u3, u4);

        rows[0] = x0;
        rows[1] = x1;
        rows[2] = x2;
        rows[3] = x3;
        rows[4] = x4;
        rows[5] = x5;
        rows[6] = x6;
        rows[7] = x7;
    }

    /// 1D ADST-4 on 4 vectors.
    fn adst_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
        // ADST-4 approximation using rotations
        // This is a simplified version for demonstration
        let s0 = rows[0];
        let s1 = rows[1];
        let s2 = rows[2];
        let s3 = rows[3];

        // Apply ADST matrix (simplified)
        let t0 = self.simd.add_i16x8(s0, s3);
        let t1 = self.simd.add_i16x8(s1, s2);
        let t2 = self.simd.sub_i16x8(s1, s2);
        let t3 = self.simd.sub_i16x8(s0, s3);

        rows[0] = t0;
        rows[1] = t2;
        rows[2] = t1;
        rows[3] = t3;
    }

    /// 1D inverse ADST-4 on 4 vectors.
    fn iadst_4_1d(&self, rows: &mut [crate::simd::types::I16x8; 4]) {
        // Inverse ADST-4 (transpose of forward ADST)
        let t0 = rows[0];
        let t2 = rows[1];
        let t1 = rows[2];
        let t3 = rows[3];

        let s0 = self.simd.add_i16x8(t0, t3);
        let s1 = self.simd.add_i16x8(t1, t2);
        let s2 = self.simd.sub_i16x8(t1, t2);
        let s3 = self.simd.sub_i16x8(t0, t3);

        rows[0] = s0;
        rows[1] = s1;
        rows[2] = s2;
        rows[3] = s3;
    }
}