aboutsummaryrefslogtreecommitdiffstats
path: root/nihav-codec-support/src/dsp/mdct.rs
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2020-02-20 11:00:24 +0100
committerKostya Shishkov <kostya.shishkov@gmail.com>2020-02-20 11:00:24 +0100
commitb4d5b8515e75383b4fc59ea2813c90c615d59a96 (patch)
treecf9ea1f458965eea90dff60a607dc90bf42887b3 /nihav-codec-support/src/dsp/mdct.rs
parent2b8bf9a03242bbd6e80091082a50ec13b1a95143 (diff)
downloadnihav-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.rs81
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;
+ }
+ }
+}