AudioConverter.h 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #if !defined(AudioConverter_h)
  6. #define AudioConverter_h
  7. #include "MediaInfo.h"
  8. // Forward declaration
  9. typedef struct SpeexResamplerState_ SpeexResamplerState;
  10. namespace mozilla {
  11. template <AudioConfig::SampleFormat T> struct AudioDataBufferTypeChooser;
  12. template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_U8>
  13. { typedef uint8_t Type; };
  14. template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S16>
  15. { typedef int16_t Type; };
  16. template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24LSB>
  17. { typedef int32_t Type; };
  18. template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24>
  19. { typedef int32_t Type; };
  20. template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S32>
  21. { typedef int32_t Type; };
  22. template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_FLT>
  23. { typedef float Type; };
  24. // 'Value' is the type used externally to deal with stored value.
  25. // AudioDataBuffer can perform conversion between different SampleFormat content.
  26. template <AudioConfig::SampleFormat Format, typename Value = typename AudioDataBufferTypeChooser<Format>::Type>
  27. class AudioDataBuffer
  28. {
  29. public:
  30. AudioDataBuffer() {}
  31. AudioDataBuffer(Value* aBuffer, size_t aLength)
  32. : mBuffer(aBuffer, aLength)
  33. {}
  34. explicit AudioDataBuffer(const AudioDataBuffer& aOther)
  35. : mBuffer(aOther.mBuffer)
  36. {}
  37. AudioDataBuffer(AudioDataBuffer&& aOther)
  38. : mBuffer(Move(aOther.mBuffer))
  39. {}
  40. template <AudioConfig::SampleFormat OtherFormat, typename OtherValue>
  41. explicit AudioDataBuffer(const AudioDataBuffer<OtherFormat, OtherValue>& other)
  42. {
  43. // TODO: Convert from different type, may use asm routines.
  44. MOZ_CRASH("Conversion not implemented yet");
  45. }
  46. // A u8, s16 and float aligned buffer can only be treated as
  47. // FORMAT_U8, FORMAT_S16 and FORMAT_FLT respectively.
  48. // So allow them as copy and move constructors.
  49. explicit AudioDataBuffer(const AlignedByteBuffer& aBuffer)
  50. : mBuffer(aBuffer)
  51. {
  52. static_assert(Format == AudioConfig::FORMAT_U8,
  53. "Conversion not implemented yet");
  54. }
  55. explicit AudioDataBuffer(const AlignedShortBuffer& aBuffer)
  56. : mBuffer(aBuffer)
  57. {
  58. static_assert(Format == AudioConfig::FORMAT_S16,
  59. "Conversion not implemented yet");
  60. }
  61. explicit AudioDataBuffer(const AlignedFloatBuffer& aBuffer)
  62. : mBuffer(aBuffer)
  63. {
  64. static_assert(Format == AudioConfig::FORMAT_FLT,
  65. "Conversion not implemented yet");
  66. }
  67. explicit AudioDataBuffer(AlignedByteBuffer&& aBuffer)
  68. : mBuffer(Move(aBuffer))
  69. {
  70. static_assert(Format == AudioConfig::FORMAT_U8,
  71. "Conversion not implemented yet");
  72. }
  73. explicit AudioDataBuffer(AlignedShortBuffer&& aBuffer)
  74. : mBuffer(Move(aBuffer))
  75. {
  76. static_assert(Format == AudioConfig::FORMAT_S16,
  77. "Conversion not implemented yet");
  78. }
  79. explicit AudioDataBuffer(AlignedFloatBuffer&& aBuffer)
  80. : mBuffer(Move(aBuffer))
  81. {
  82. static_assert(Format == AudioConfig::FORMAT_FLT,
  83. "Conversion not implemented yet");
  84. }
  85. AudioDataBuffer& operator=(AudioDataBuffer&& aOther)
  86. {
  87. mBuffer = Move(aOther.mBuffer);
  88. return *this;
  89. }
  90. AudioDataBuffer& operator=(const AudioDataBuffer& aOther)
  91. {
  92. mBuffer = aOther.mBuffer;
  93. return *this;
  94. }
  95. Value* Data() const { return mBuffer.Data(); }
  96. size_t Length() const { return mBuffer.Length(); }
  97. size_t Size() const { return mBuffer.Size(); }
  98. AlignedBuffer<Value> Forget()
  99. {
  100. // Correct type -> Just give values as-is.
  101. return Move(mBuffer);
  102. }
  103. private:
  104. AlignedBuffer<Value> mBuffer;
  105. };
  106. typedef AudioDataBuffer<AudioConfig::FORMAT_DEFAULT> AudioSampleBuffer;
  107. class AudioConverter {
  108. public:
  109. AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut);
  110. ~AudioConverter();
  111. // Convert the AudioDataBuffer.
  112. // Conversion will be done in place if possible. Otherwise a new buffer will
  113. // be returned.
  114. // Providing an empty buffer and resampling is expected, the resampler
  115. // will be drained.
  116. template <AudioConfig::SampleFormat Format, typename Value>
  117. AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
  118. {
  119. MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
  120. AudioDataBuffer<Format, Value> buffer = Move(aBuffer);
  121. if (CanWorkInPlace()) {
  122. size_t frames = SamplesInToFrames(buffer.Length());
  123. frames = ProcessInternal(buffer.Data(), buffer.Data(), frames);
  124. if (frames && mIn.Rate() != mOut.Rate()) {
  125. frames = ResampleAudio(buffer.Data(), buffer.Data(), frames);
  126. }
  127. AlignedBuffer<Value> temp = buffer.Forget();
  128. temp.SetLength(FramesOutToSamples(frames));
  129. return AudioDataBuffer<Format, Value>(Move(temp));;
  130. }
  131. return Process(buffer);
  132. }
  133. template <AudioConfig::SampleFormat Format, typename Value>
  134. AudioDataBuffer<Format, Value> Process(const AudioDataBuffer<Format, Value>& aBuffer)
  135. {
  136. MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
  137. // Perform the downmixing / reordering in temporary buffer.
  138. size_t frames = SamplesInToFrames(aBuffer.Length());
  139. AlignedBuffer<Value> temp1;
  140. if (!temp1.SetLength(FramesOutToSamples(frames))) {
  141. return AudioDataBuffer<Format, Value>(Move(temp1));
  142. }
  143. frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
  144. if (mIn.Rate() == mOut.Rate()) {
  145. MOZ_ALWAYS_TRUE(temp1.SetLength(FramesOutToSamples(frames)));
  146. return AudioDataBuffer<Format, Value>(Move(temp1));
  147. }
  148. // At this point, temp1 contains the buffer reordered and downmixed.
  149. // If we are downsampling we can re-use it.
  150. AlignedBuffer<Value>* outputBuffer = &temp1;
  151. AlignedBuffer<Value> temp2;
  152. if (!frames || mOut.Rate() > mIn.Rate()) {
  153. // We are upsampling or about to drain, we can't work in place.
  154. // Allocate another temporary buffer where the upsampling will occur.
  155. if (!temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)))) {
  156. return AudioDataBuffer<Format, Value>(Move(temp2));
  157. }
  158. outputBuffer = &temp2;
  159. }
  160. if (!frames) {
  161. frames = DrainResampler(outputBuffer->Data());
  162. } else {
  163. frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
  164. }
  165. MOZ_ALWAYS_TRUE(outputBuffer->SetLength(FramesOutToSamples(frames)));
  166. return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
  167. }
  168. // Attempt to convert the AudioDataBuffer in place.
  169. // Will return 0 if the conversion wasn't possible.
  170. template <typename Value>
  171. size_t Process(Value* aBuffer, size_t aFrames)
  172. {
  173. MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
  174. if (!CanWorkInPlace()) {
  175. return 0;
  176. }
  177. size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
  178. if (frames && mIn.Rate() != mOut.Rate()) {
  179. frames = ResampleAudio(aBuffer, aBuffer, aFrames);
  180. }
  181. return frames;
  182. }
  183. bool CanWorkInPlace() const;
  184. bool CanReorderAudio() const
  185. {
  186. return mIn.Layout().MappingTable(mOut.Layout());
  187. }
  188. const AudioConfig& InputConfig() const { return mIn; }
  189. const AudioConfig& OutputConfig() const { return mOut; }
  190. private:
  191. const AudioConfig mIn;
  192. const AudioConfig mOut;
  193. uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS];
  194. /**
  195. * ProcessInternal
  196. * Parameters:
  197. * aOut : destination buffer where converted samples will be copied
  198. * aIn : source buffer
  199. * aSamples: number of frames in source buffer
  200. *
  201. * Return Value: number of frames converted or 0 if error
  202. */
  203. size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
  204. void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
  205. size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
  206. size_t UpmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
  207. size_t FramesOutToSamples(size_t aFrames) const;
  208. size_t SamplesInToFrames(size_t aSamples) const;
  209. size_t FramesOutToBytes(size_t aFrames) const;
  210. // Resampler context.
  211. SpeexResamplerState* mResampler;
  212. size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
  213. size_t ResampleRecipientFrames(size_t aFrames) const;
  214. void RecreateResampler();
  215. size_t DrainResampler(void* aOut);
  216. };
  217. } // namespace mozilla
  218. #endif /* AudioConverter_h */