From 086c044dc34dfc0f74fbe41f4ecb402b2cd34884 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:13:33 +0200 Subject: Merging upstream version 125.0.1. Signed-off-by: Daniel Baumann --- dom/media/webaudio/FFTBlock.h | 290 ++++++++++++------------------------------ 1 file changed, 84 insertions(+), 206 deletions(-) (limited to 'dom/media/webaudio/FFTBlock.h') diff --git a/dom/media/webaudio/FFTBlock.h b/dom/media/webaudio/FFTBlock.h index 6af882f9af..ecce39d7b1 100644 --- a/dom/media/webaudio/FFTBlock.h +++ b/dom/media/webaudio/FFTBlock.h @@ -7,31 +7,17 @@ #ifndef FFTBlock_h_ #define FFTBlock_h_ -#ifdef BUILD_ARM_NEON -# include -# include "mozilla/arm.h" -# include "dl/sp/api/omxSP.h" -#endif - #include "AlignedTArray.h" #include "AudioNodeEngine.h" -#if defined(MOZ_LIBAV_FFT) -# include "FFmpegRDFTTypes.h" -# include "FFVPXRuntimeLinker.h" -#else -# include "kiss_fft/kiss_fftr.h" -#endif +#include "FFVPXRuntimeLinker.h" +#include "ffvpx/tx.h" namespace mozilla { // This class defines an FFT block, loosely modeled after Blink's FFTFrame // class to make sharing code with Blink easy. -// Currently it's implemented on top of KissFFT on all platforms. class FFTBlock final { union ComplexU { -#if !defined(MOZ_LIBAV_FFT) - kiss_fft_cpx c; -#endif float f[2]; struct { float r; @@ -41,28 +27,13 @@ class FFTBlock final { public: static void MainThreadInit() { -#ifdef MOZ_LIBAV_FFT FFVPXRuntimeLinker::Init(); - if (!sRDFTFuncs.init) { - FFVPXRuntimeLinker::GetRDFTFuncs(&sRDFTFuncs); + if (!sFFTFuncs.init) { + FFVPXRuntimeLinker::GetFFTFuncs(&sFFTFuncs); } -#endif } - - explicit FFTBlock(uint32_t aFFTSize) -#if defined(MOZ_LIBAV_FFT) - : mAvRDFT(nullptr), - mAvIRDFT(nullptr) -#else - : mKissFFT(nullptr), - mKissIFFT(nullptr) -# ifdef BUILD_ARM_NEON - , - mOmxFFT(nullptr), - mOmxIFFT(nullptr) -# endif -#endif - { + explicit FFTBlock(uint32_t aFFTSize, float aInverseScaling = 1.0f) + : mInverseScaling(aInverseScaling) { MOZ_COUNT_CTOR(FFTBlock); SetFFTSize(aFFTSize); } @@ -83,63 +54,33 @@ class FFTBlock final { return; } -#if defined(MOZ_LIBAV_FFT) - PodCopy(mOutputBuffer.Elements()->f, aData, mFFTSize); - sRDFTFuncs.calc(mAvRDFT, mOutputBuffer.Elements()->f); - // Recover packed Nyquist. - mOutputBuffer[mFFTSize / 2].r = mOutputBuffer[0].i; - mOutputBuffer[0].i = 0.0f; -#else -# ifdef BUILD_ARM_NEON - if (mozilla::supports_neon()) { - omxSP_FFTFwd_RToCCS_F32_Sfs(aData, mOutputBuffer.Elements()->f, mOmxFFT); - } else -# endif - { - kiss_fftr(mKissFFT, aData, &(mOutputBuffer.Elements()->c)); - } + mFn(mTxCtx, mOutputBuffer.Elements()->f, const_cast(aData), + 2 * sizeof(float)); +#ifdef DEBUG + mInversePerformed = false; #endif } - // Inverse-transform internal data and store the resulting FFTSize() - // points in aDataOut. - void GetInverse(float* aDataOut) { - GetInverseWithoutScaling(aDataOut); - AudioBufferInPlaceScale(aDataOut, 1.0f / mFFTSize, mFFTSize); - } - // Inverse-transform internal frequency data and store the resulting // FFTSize() points in |aDataOut|. If frequency data has not already been // scaled, then the output will need scaling by 1/FFTSize(). - void GetInverseWithoutScaling(float* aDataOut) { + void GetInverse(float* aDataOut) { if (!EnsureIFFT()) { std::fill_n(aDataOut, mFFTSize, 0.0f); return; }; - -#if defined(MOZ_LIBAV_FFT) - { - // Even though this function doesn't scale, the libav forward transform - // gives a value that needs scaling by 2 in order for things to turn out - // similar to how we expect from kissfft/openmax. - AudioBufferCopyWithScale(mOutputBuffer.Elements()->f, 2.0f, aDataOut, - mFFTSize); - aDataOut[1] = 2.0f * mOutputBuffer[mFFTSize / 2].r; // Packed Nyquist - sRDFTFuncs.calc(mAvIRDFT, aDataOut); - } -#else -# ifdef BUILD_ARM_NEON - if (mozilla::supports_neon()) { - omxSP_FFTInv_CCSToR_F32_Sfs_unscaled(mOutputBuffer.Elements()->f, - aDataOut, mOmxIFFT); - } else -# endif - { - kiss_fftri(mKissIFFT, &(mOutputBuffer.Elements()->c), aDataOut); - } + // When performing an inverse transform, tx overwrites the input. This + // asserts that forward / inverse transforms are interleaved to avoid having + // to keep the input around. + MOZ_ASSERT(!mInversePerformed); + mIFn(mITxCtx, aDataOut, mOutputBuffer.Elements()->f, 2 * sizeof(float)); +#ifdef DEBUG + mInversePerformed = true; #endif } void Multiply(const FFTBlock& aFrame) { + MOZ_ASSERT(!mInversePerformed); + uint32_t halfSize = mFFTSize / 2; // DFTs are not packed. MOZ_ASSERT(mOutputBuffer[0].i == 0); @@ -161,8 +102,8 @@ class FFTBlock final { MOZ_ASSERT(dataSize <= FFTSize()); AlignedTArray paddedData; paddedData.SetLength(FFTSize()); - AudioBufferCopyWithScale(aData, 1.0f / FFTSize(), paddedData.Elements(), - dataSize); + AudioBufferCopyWithScale(aData, 1.0f / AssertedCast(FFTSize()), + paddedData.Elements(), dataSize); PodZero(paddedData.Elements() + dataSize, mFFTSize - dataSize); PerformFFT(paddedData.Elements()); } @@ -180,46 +121,35 @@ class FFTBlock final { double ExtractAverageGroupDelay(); uint32_t FFTSize() const { return mFFTSize; } - float RealData(uint32_t aIndex) const { return mOutputBuffer[aIndex].r; } - float& RealData(uint32_t aIndex) { return mOutputBuffer[aIndex].r; } - float ImagData(uint32_t aIndex) const { return mOutputBuffer[aIndex].i; } - float& ImagData(uint32_t aIndex) { return mOutputBuffer[aIndex].i; } + float RealData(uint32_t aIndex) const { + MOZ_ASSERT(!mInversePerformed); + return mOutputBuffer[aIndex].r; + } + float& RealData(uint32_t aIndex) { + MOZ_ASSERT(!mInversePerformed); + return mOutputBuffer[aIndex].r; + } + float ImagData(uint32_t aIndex) const { + MOZ_ASSERT(!mInversePerformed); + return mOutputBuffer[aIndex].i; + } + float& ImagData(uint32_t aIndex) { + MOZ_ASSERT(!mInversePerformed); + return mOutputBuffer[aIndex].i; + } size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { size_t amount = 0; -#if defined(MOZ_LIBAV_FFT) - auto ComputedSizeOfContextIfSet = [this](void* aContext) -> size_t { - if (!aContext) { - return 0; - } - // RDFTContext is only forward declared in public headers, but this is - // an estimate based on a value of 231 seen requested from - // _aligned_alloc on Win64. Don't use malloc_usable_size() because the - // context pointer is not necessarily from malloc. - size_t amount = 232; - // Add size of allocations performed in ff_fft_init(). - // The maximum FFT size used is 32768 = 2^15 and so revtab32 is not - // allocated. - MOZ_ASSERT(mFFTSize <= 32768); - amount += mFFTSize * (sizeof(uint16_t) + 2 * sizeof(float)); - - return amount; - }; + // malloc_usable_size can't be used here because the pointer isn't + // necessarily from malloc. This value has been manually checked. + if (mTxCtx) { + amount += 711; + } + if (mTxCtx) { + amount += 711; + } - amount += ComputedSizeOfContextIfSet(mAvRDFT); - amount += ComputedSizeOfContextIfSet(mAvIRDFT); -#else -# ifdef BUILD_ARM_NEON - amount += aMallocSizeOf(mOmxFFT); - amount += aMallocSizeOf(mOmxIFFT); -# endif -# ifdef USE_SIMD -# error kiss fft uses malloc only when USE_SIMD is not defined -# endif - amount += aMallocSizeOf(mKissFFT); - amount += aMallocSizeOf(mKissIFFT); -#endif amount += mOutputBuffer.ShallowSizeOfExcludingThis(aMallocSizeOf); return amount; } @@ -228,119 +158,67 @@ class FFTBlock final { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } - private: FFTBlock(const FFTBlock& other) = delete; void operator=(const FFTBlock& other) = delete; + private: bool EnsureFFT() { -#if defined(MOZ_LIBAV_FFT) - if (!mAvRDFT) { - if (!sRDFTFuncs.init) { + if (!mTxCtx) { + if (!sFFTFuncs.init) { return false; } - - mAvRDFT = sRDFTFuncs.init(FloorLog2(mFFTSize), DFT_R2C); - } -#else -# ifdef BUILD_ARM_NEON - if (mozilla::supports_neon()) { - if (!mOmxFFT) { - mOmxFFT = createOmxFFT(mFFTSize); - } - } else -# endif - { - if (!mKissFFT) { - mKissFFT = kiss_fftr_alloc(mFFTSize, 0, nullptr, nullptr); - } + // Forward transform is always unscaled for our purpose. + float scale = 1.0f; + int rv = sFFTFuncs.init(&mTxCtx, &mFn, AV_TX_FLOAT_RDFT, 0 /* forward */, + AssertedCast(mFFTSize), &scale, 0); + MOZ_ASSERT(!rv, "av_tx_init: invalid parameters (forward)"); + return !rv; } -#endif return true; } - bool EnsureIFFT() { -#if defined(MOZ_LIBAV_FFT) - if (!mAvIRDFT) { - if (!sRDFTFuncs.init) { + if (!mITxCtx) { + if (!sFFTFuncs.init) { return false; } - - mAvIRDFT = sRDFTFuncs.init(FloorLog2(mFFTSize), IDFT_C2R); - } -#else -# ifdef BUILD_ARM_NEON - if (mozilla::supports_neon()) { - if (!mOmxIFFT) { - mOmxIFFT = createOmxFFT(mFFTSize); - } - } else -# endif - { - if (!mKissIFFT) { - mKissIFFT = kiss_fftr_alloc(mFFTSize, 1, nullptr, nullptr); - } + int rv = + sFFTFuncs.init(&mITxCtx, &mIFn, AV_TX_FLOAT_RDFT, 1 /* inverse */, + AssertedCast(mFFTSize), &mInverseScaling, 0); + MOZ_ASSERT(!rv, "av_tx_init: invalid parameters (inverse)"); + return !rv; } -#endif return true; } - -#ifdef BUILD_ARM_NEON - static OMXFFTSpec_R_F32* createOmxFFT(uint32_t aFFTSize) { - MOZ_ASSERT((aFFTSize & (aFFTSize - 1)) == 0); - OMX_INT bufSize; - OMX_INT order = FloorLog2(aFFTSize); - MOZ_ASSERT(aFFTSize >> order == 1); - OMXResult status = omxSP_FFTGetBufSize_R_F32(order, &bufSize); - if (status == OMX_Sts_NoErr) { - OMXFFTSpec_R_F32* context = - static_cast(malloc(bufSize)); - if (omxSP_FFTInit_R_F32(context, order) != OMX_Sts_NoErr) { - return nullptr; - } - return context; - } - return nullptr; - } -#endif - void Clear() { -#if defined(MOZ_LIBAV_FFT) - if (mAvRDFT) { - sRDFTFuncs.end(mAvRDFT); - mAvRDFT = nullptr; + if (mTxCtx) { + sFFTFuncs.uninit(&mTxCtx); + mTxCtx = nullptr; + mFn = nullptr; } - if (mAvIRDFT) { - sRDFTFuncs.end(mAvIRDFT); - mAvIRDFT = nullptr; + if (mITxCtx) { + sFFTFuncs.uninit(&mITxCtx); + mITxCtx = nullptr; + mIFn = nullptr; } -#else -# ifdef BUILD_ARM_NEON - free(mOmxFFT); - free(mOmxIFFT); - mOmxFFT = mOmxIFFT = nullptr; -# endif - free(mKissFFT); - free(mKissIFFT); - mKissFFT = mKissIFFT = nullptr; -#endif } void AddConstantGroupDelay(double sampleFrameDelay); void InterpolateFrequencyComponents(const FFTBlock& block0, const FFTBlock& block1, double interp); -#if defined(MOZ_LIBAV_FFT) - static FFmpegRDFTFuncs sRDFTFuncs; - RDFTContext* mAvRDFT; - RDFTContext* mAvIRDFT; -#else - kiss_fftr_cfg mKissFFT; - kiss_fftr_cfg mKissIFFT; -# ifdef BUILD_ARM_NEON - OMXFFTSpec_R_F32* mOmxFFT; - OMXFFTSpec_R_F32* mOmxIFFT; -# endif -#endif + static FFmpegFFTFuncs sFFTFuncs; + // Context and function pointer for forward transform + AVTXContext* mTxCtx{}; + av_tx_fn mFn{}; + // Context and function pointer for inverse transform + AVTXContext* mITxCtx{}; + av_tx_fn mIFn{}; AlignedTArray mOutputBuffer; - uint32_t mFFTSize; + uint32_t mFFTSize{}; + // A scaling that is performed when doing an inverse transform. The forward + // transform is always unscaled. + float mInverseScaling; +#ifdef DEBUG + bool mInversePerformed = false; +#endif }; } // namespace mozilla -- cgit v1.2.3