From 43a97878ce14b72f0981164f87f2e35e14151312 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:22:09 +0200 Subject: Adding upstream version 110.0.1. Signed-off-by: Daniel Baumann --- dom/media/AudioCompactor.h | 128 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 dom/media/AudioCompactor.h (limited to 'dom/media/AudioCompactor.h') diff --git a/dom/media/AudioCompactor.h b/dom/media/AudioCompactor.h new file mode 100644 index 0000000000..b058ba3755 --- /dev/null +++ b/dom/media/AudioCompactor.h @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#if !defined(AudioCompactor_h) +# define AudioCompactor_h + +# include "MediaQueue.h" +# include "MediaData.h" +# include "VideoUtils.h" + +namespace mozilla { + +class AudioCompactor { + public: + explicit AudioCompactor(MediaQueue& aQueue) : mQueue(aQueue) { + // Determine padding size used by AlignedBuffer. + size_t paddedSize = AlignedAudioBuffer::AlignmentPaddingSize(); + mSamplesPadding = paddedSize / sizeof(AudioDataValue); + if (mSamplesPadding * sizeof(AudioDataValue) < paddedSize) { + // Round up. + mSamplesPadding++; + } + } + + // Push audio data into the underlying queue with minimal heap allocation + // slop. This method is responsible for allocating AudioDataValue[] buffers. + // The caller must provide a functor to copy the data into the buffers. The + // functor must provide the following signature: + // + // uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples); + // + // The functor must copy as many complete frames as possible to the provided + // buffer given its length (in AudioDataValue elements). The number of frames + // copied must be returned. This copy functor must support being called + // multiple times in order to copy the audio data fully. The copy functor + // must copy full frames as partial frames will be ignored. + template + bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate, + uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc) { + auto time = media::TimeUnit::FromMicroseconds(aTime); + + // If we are losing more than a reasonable amount to padding, try to chunk + // the data. + size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR; + + while (aFrames > 0) { + uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop); + if (samples / aChannels > mSamplesPadding / aChannels + 1) { + samples -= mSamplesPadding; + } + AlignedAudioBuffer buffer(samples); + if (!buffer) { + return false; + } + + // Copy audio data to buffer using caller-provided functor. + uint32_t framesCopied = aCopyFunc(buffer.get(), samples); + + NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames"); + buffer.SetLength(size_t(framesCopied) * aChannels); + + auto duration = FramesToTimeUnit(framesCopied, aSampleRate); + if (!duration.IsValid()) { + return false; + } + + RefPtr data = new AudioData(aOffset, time, std::move(buffer), + aChannels, aSampleRate); + MOZ_DIAGNOSTIC_ASSERT(duration == data->mDuration, "must be equal"); + mQueue.Push(data); + + // Remove the frames we just pushed into the queue and loop if there is + // more to be done. + time += duration; + aFrames -= framesCopied; + + // NOTE: No need to update aOffset as its only an approximation anyway. + } + + return true; + } + + // Copy functor suitable for copying audio samples already in the + // AudioDataValue format/layout expected by AudioStream on this platform. + class NativeCopy { + public: + NativeCopy(const uint8_t* aSource, size_t aSourceBytes, uint32_t aChannels) + : mSource(aSource), + mSourceBytes(aSourceBytes), + mChannels(aChannels), + mNextByte(0) {} + + uint32_t operator()(AudioDataValue* aBuffer, uint32_t aSamples); + + private: + const uint8_t* const mSource; + const size_t mSourceBytes; + const uint32_t mChannels; + size_t mNextByte; + }; + + // Allow 12.5% slop before chunking kicks in. Public so that the gtest can + // access it. + static const size_t MAX_SLOP_DIVISOR = 8; + + private: + // Compute the number of AudioDataValue samples that will be fit the most + // frames while keeping heap allocation slop less than the given threshold. + static uint32_t GetChunkSamples(uint32_t aFrames, uint32_t aChannels, + size_t aMaxSlop); + + static size_t BytesPerFrame(uint32_t aChannels) { + return sizeof(AudioDataValue) * aChannels; + } + + static size_t AudioDataSize(uint32_t aFrames, uint32_t aChannels) { + return aFrames * BytesPerFrame(aChannels); + } + + MediaQueue& mQueue; + size_t mSamplesPadding; +}; + +} // namespace mozilla + +#endif // AudioCompactor_h -- cgit v1.2.3