123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* 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(AudioConverter_h)
- #define AudioConverter_h
- #include "MediaInfo.h"
- // Forward declaration
- typedef struct SpeexResamplerState_ SpeexResamplerState;
- namespace mozilla {
- template <AudioConfig::SampleFormat T> struct AudioDataBufferTypeChooser;
- template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_U8>
- { typedef uint8_t Type; };
- template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S16>
- { typedef int16_t Type; };
- template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24LSB>
- { typedef int32_t Type; };
- template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24>
- { typedef int32_t Type; };
- template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S32>
- { typedef int32_t Type; };
- template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_FLT>
- { typedef float Type; };
- // 'Value' is the type used externally to deal with stored value.
- // AudioDataBuffer can perform conversion between different SampleFormat content.
- template <AudioConfig::SampleFormat Format, typename Value = typename AudioDataBufferTypeChooser<Format>::Type>
- class AudioDataBuffer
- {
- public:
- AudioDataBuffer() {}
- AudioDataBuffer(Value* aBuffer, size_t aLength)
- : mBuffer(aBuffer, aLength)
- {}
- explicit AudioDataBuffer(const AudioDataBuffer& aOther)
- : mBuffer(aOther.mBuffer)
- {}
- AudioDataBuffer(AudioDataBuffer&& aOther)
- : mBuffer(Move(aOther.mBuffer))
- {}
- template <AudioConfig::SampleFormat OtherFormat, typename OtherValue>
- explicit AudioDataBuffer(const AudioDataBuffer<OtherFormat, OtherValue>& other)
- {
- // TODO: Convert from different type, may use asm routines.
- MOZ_CRASH("Conversion not implemented yet");
- }
- // A u8, s16 and float aligned buffer can only be treated as
- // FORMAT_U8, FORMAT_S16 and FORMAT_FLT respectively.
- // So allow them as copy and move constructors.
- explicit AudioDataBuffer(const AlignedByteBuffer& aBuffer)
- : mBuffer(aBuffer)
- {
- static_assert(Format == AudioConfig::FORMAT_U8,
- "Conversion not implemented yet");
- }
- explicit AudioDataBuffer(const AlignedShortBuffer& aBuffer)
- : mBuffer(aBuffer)
- {
- static_assert(Format == AudioConfig::FORMAT_S16,
- "Conversion not implemented yet");
- }
- explicit AudioDataBuffer(const AlignedFloatBuffer& aBuffer)
- : mBuffer(aBuffer)
- {
- static_assert(Format == AudioConfig::FORMAT_FLT,
- "Conversion not implemented yet");
- }
- explicit AudioDataBuffer(AlignedByteBuffer&& aBuffer)
- : mBuffer(Move(aBuffer))
- {
- static_assert(Format == AudioConfig::FORMAT_U8,
- "Conversion not implemented yet");
- }
- explicit AudioDataBuffer(AlignedShortBuffer&& aBuffer)
- : mBuffer(Move(aBuffer))
- {
- static_assert(Format == AudioConfig::FORMAT_S16,
- "Conversion not implemented yet");
- }
- explicit AudioDataBuffer(AlignedFloatBuffer&& aBuffer)
- : mBuffer(Move(aBuffer))
- {
- static_assert(Format == AudioConfig::FORMAT_FLT,
- "Conversion not implemented yet");
- }
- AudioDataBuffer& operator=(AudioDataBuffer&& aOther)
- {
- mBuffer = Move(aOther.mBuffer);
- return *this;
- }
- AudioDataBuffer& operator=(const AudioDataBuffer& aOther)
- {
- mBuffer = aOther.mBuffer;
- return *this;
- }
- Value* Data() const { return mBuffer.Data(); }
- size_t Length() const { return mBuffer.Length(); }
- size_t Size() const { return mBuffer.Size(); }
- AlignedBuffer<Value> Forget()
- {
- // Correct type -> Just give values as-is.
- return Move(mBuffer);
- }
- private:
- AlignedBuffer<Value> mBuffer;
- };
- typedef AudioDataBuffer<AudioConfig::FORMAT_DEFAULT> AudioSampleBuffer;
- class AudioConverter {
- public:
- AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut);
- ~AudioConverter();
- // Convert the AudioDataBuffer.
- // Conversion will be done in place if possible. Otherwise a new buffer will
- // be returned.
- // Providing an empty buffer and resampling is expected, the resampler
- // will be drained.
- template <AudioConfig::SampleFormat Format, typename Value>
- AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
- {
- MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
- AudioDataBuffer<Format, Value> buffer = Move(aBuffer);
- if (CanWorkInPlace()) {
- size_t frames = SamplesInToFrames(buffer.Length());
- frames = ProcessInternal(buffer.Data(), buffer.Data(), frames);
- if (frames && mIn.Rate() != mOut.Rate()) {
- frames = ResampleAudio(buffer.Data(), buffer.Data(), frames);
- }
- AlignedBuffer<Value> temp = buffer.Forget();
- temp.SetLength(FramesOutToSamples(frames));
- return AudioDataBuffer<Format, Value>(Move(temp));;
- }
- return Process(buffer);
- }
- template <AudioConfig::SampleFormat Format, typename Value>
- AudioDataBuffer<Format, Value> Process(const AudioDataBuffer<Format, Value>& aBuffer)
- {
- MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
- // Perform the downmixing / reordering in temporary buffer.
- size_t frames = SamplesInToFrames(aBuffer.Length());
- AlignedBuffer<Value> temp1;
- if (!temp1.SetLength(FramesOutToSamples(frames))) {
- return AudioDataBuffer<Format, Value>(Move(temp1));
- }
- frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
- if (mIn.Rate() == mOut.Rate()) {
- MOZ_ALWAYS_TRUE(temp1.SetLength(FramesOutToSamples(frames)));
- return AudioDataBuffer<Format, Value>(Move(temp1));
- }
- // At this point, temp1 contains the buffer reordered and downmixed.
- // If we are downsampling we can re-use it.
- AlignedBuffer<Value>* outputBuffer = &temp1;
- AlignedBuffer<Value> temp2;
- if (!frames || mOut.Rate() > mIn.Rate()) {
- // We are upsampling or about to drain, we can't work in place.
- // Allocate another temporary buffer where the upsampling will occur.
- if (!temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)))) {
- return AudioDataBuffer<Format, Value>(Move(temp2));
- }
- outputBuffer = &temp2;
- }
- if (!frames) {
- frames = DrainResampler(outputBuffer->Data());
- } else {
- frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
- }
- MOZ_ALWAYS_TRUE(outputBuffer->SetLength(FramesOutToSamples(frames)));
- return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
- }
- // Attempt to convert the AudioDataBuffer in place.
- // Will return 0 if the conversion wasn't possible.
- template <typename Value>
- size_t Process(Value* aBuffer, size_t aFrames)
- {
- MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
- if (!CanWorkInPlace()) {
- return 0;
- }
- size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
- if (frames && mIn.Rate() != mOut.Rate()) {
- frames = ResampleAudio(aBuffer, aBuffer, aFrames);
- }
- return frames;
- }
- bool CanWorkInPlace() const;
- bool CanReorderAudio() const
- {
- return mIn.Layout().MappingTable(mOut.Layout());
- }
- const AudioConfig& InputConfig() const { return mIn; }
- const AudioConfig& OutputConfig() const { return mOut; }
- private:
- const AudioConfig mIn;
- const AudioConfig mOut;
- uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS];
- /**
- * ProcessInternal
- * Parameters:
- * aOut : destination buffer where converted samples will be copied
- * aIn : source buffer
- * aSamples: number of frames in source buffer
- *
- * Return Value: number of frames converted or 0 if error
- */
- size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
- void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
- size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
- size_t UpmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
- size_t FramesOutToSamples(size_t aFrames) const;
- size_t SamplesInToFrames(size_t aSamples) const;
- size_t FramesOutToBytes(size_t aFrames) const;
- // Resampler context.
- SpeexResamplerState* mResampler;
- size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
- size_t ResampleRecipientFrames(size_t aFrames) const;
- void RecreateResampler();
- size_t DrainResampler(void* aOut);
- };
- } // namespace mozilla
- #endif /* AudioConverter_h */
|