diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2020-02-20 11:00:24 +0100 |
---|---|---|
committer | Kostya Shishkov <kostya.shishkov@gmail.com> | 2020-02-20 11:00:24 +0100 |
commit | b4d5b8515e75383b4fc59ea2813c90c615d59a96 (patch) | |
tree | cf9ea1f458965eea90dff60a607dc90bf42887b3 /nihav-codec-support/src/dsp/mdct.rs | |
parent | 2b8bf9a03242bbd6e80091082a50ec13b1a95143 (diff) | |
download | nihav-b4d5b8515e75383b4fc59ea2813c90c615d59a96.tar.gz |
split nihav-codec-support crate from nihav-core
The former is intended just for NihAV decoders, the latter is for both
NihAV crates and for the code using NihAV.
Diffstat (limited to 'nihav-codec-support/src/dsp/mdct.rs')
-rw-r--r-- | nihav-codec-support/src/dsp/mdct.rs | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/nihav-codec-support/src/dsp/mdct.rs b/nihav-codec-support/src/dsp/mdct.rs new file mode 100644 index 0000000..e6ed3dc --- /dev/null +++ b/nihav-codec-support/src/dsp/mdct.rs @@ -0,0 +1,81 @@ +//! Modified Discrete Cosine transform functionality. +use std::f32::consts; +use super::fft::*; + +/// IMDCT working context. +pub struct IMDCT { + twiddle: Vec<FFTComplex>, + fft: FFT, + size: usize, + z: Vec<FFTComplex>, +} + +/* +fn imdct(src: &[f32], dst: &mut [f32], length: usize) { + for n in 0..length*2 { + dst[n] = 0.0; + for k in 0..length { + dst[n] += src[k] * (consts::PI / (length as f32) * ((n as f32) + 0.5 + ((length/2) as f32)) * ((k as f32) + 0.5)).cos(); + } + } +}*/ + +impl IMDCT { + /// Constructs a new instance of `IMDCT` context. + pub fn new(size: usize, scaledown: bool) -> Self { + let mut twiddle: Vec<FFTComplex> = Vec::with_capacity(size / 4); + let factor = 2.0 * consts::PI / ((8 * size) as f32); + let scale = if scaledown { (1.0 / (size as f32)).sqrt() } else { 1.0 }; + for k in 0..size/4 { + twiddle.push(FFTComplex::exp(factor * ((8 * k + 1) as f32)).scale(scale)); + } + let fft = FFTBuilder::new_fft(size/4, false); + let mut z: Vec<FFTComplex> = Vec::with_capacity(size / 2); + z.resize(size / 2, FFTC_ZERO); + IMDCT { twiddle, fft, size, z } + } + /// Calculates IMDCT. + pub fn imdct(&mut self, src: &[f32], dst: &mut [f32]) { + let size2 = self.size / 2; + let size4 = self.size / 4; + let size8 = self.size / 8; + for k in 0..size4 { + let c = FFTComplex { re: src[size2 - 2 * k - 1], im: src[ 2 * k] }; + self.z[k] = c * self.twiddle[k]; + } + self.fft.do_ifft_inplace(&mut self.z); + for k in 0..size4 { + self.z[k] *= self.twiddle[k]; + } + for n in 0..size8 { + dst[ 2 * n] = -self.z[size8 + n] .im; + dst[ 2 * n + 1] = self.z[size8 - n - 1].re; + dst[ size4 + 2 * n] = -self.z[ n] .re; + dst[ size4 + 2 * n + 1] = self.z[size4 - n - 1].im; + dst[ size2 + 2 * n] = -self.z[size8 + n] .re; + dst[ size2 + 2 * n + 1] = self.z[size8 - n - 1].im; + dst[3 * size4 + 2 * n] = self.z[ n] .im; + dst[3 * size4 + 2 * n + 1] = -self.z[size4 - n - 1].re; + } + } + /// Calculates only non-mirrored part of IMDCT. + pub fn imdct_half(&mut self, src: &[f32], dst: &mut [f32]) { + let size2 = self.size / 2; + let size4 = self.size / 4; + let size8 = self.size / 8; + for k in 0..size4 { + let c = FFTComplex { re: src[size2 - 2 * k - 1], im: src[ 2 * k] }; + self.z[k] = c * self.twiddle[k]; + } + self.fft.do_ifft_inplace(&mut self.z); + for k in 0..size4 { + self.z[k] *= self.twiddle[k]; + } + for n in 0..size8 { + dst[ 2 * n] = -self.z[ n] .re; + dst[ 2 * n + 1] = self.z[size4 - n - 1].im; + dst[size4 + 2 * n] = -self.z[size8 + n] .re; + dst[size4 + 2 * n + 1] = self.z[size8 - n - 1].im; + } + } +} |