AudioCompactor.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* -*- Mode: C++; tab-width: 8; 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(AudioCompactor_h)
  6. #define AudioCompactor_h
  7. #include "MediaQueue.h"
  8. #include "MediaData.h"
  9. #include "VideoUtils.h"
  10. namespace mozilla {
  11. class AudioCompactor
  12. {
  13. public:
  14. explicit AudioCompactor(MediaQueue<AudioData>& aQueue)
  15. : mQueue(aQueue)
  16. {
  17. // Determine padding size used by AlignedBuffer.
  18. size_t paddedSize = AlignedAudioBuffer::AlignmentPaddingSize();
  19. mSamplesPadding = paddedSize / sizeof(AudioDataValue);
  20. if (mSamplesPadding * sizeof(AudioDataValue) < paddedSize) {
  21. // Round up.
  22. mSamplesPadding++;
  23. }
  24. }
  25. // Push audio data into the underlying queue with minimal heap allocation
  26. // slop. This method is responsible for allocating AudioDataValue[] buffers.
  27. // The caller must provide a functor to copy the data into the buffers. The
  28. // functor must provide the following signature:
  29. //
  30. // uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples);
  31. //
  32. // The functor must copy as many complete frames as possible to the provided
  33. // buffer given its length (in AudioDataValue elements). The number of frames
  34. // copied must be returned. This copy functor must support being called
  35. // multiple times in order to copy the audio data fully. The copy functor
  36. // must copy full frames as partial frames will be ignored.
  37. template<typename CopyFunc>
  38. bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate,
  39. uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc)
  40. {
  41. // If we are losing more than a reasonable amount to padding, try to chunk
  42. // the data.
  43. size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR;
  44. while (aFrames > 0) {
  45. uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop);
  46. if (samples / aChannels > mSamplesPadding / aChannels + 1) {
  47. samples -= mSamplesPadding;
  48. }
  49. AlignedAudioBuffer buffer(samples);
  50. if (!buffer) {
  51. return false;
  52. }
  53. // Copy audio data to buffer using caller-provided functor.
  54. uint32_t framesCopied = aCopyFunc(buffer.get(), samples);
  55. NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames");
  56. buffer.SetLength(size_t(framesCopied) * aChannels);
  57. CheckedInt64 duration = FramesToUsecs(framesCopied, aSampleRate);
  58. if (!duration.isValid()) {
  59. return false;
  60. }
  61. mQueue.Push(new AudioData(aOffset,
  62. aTime,
  63. duration.value(),
  64. framesCopied,
  65. Move(buffer),
  66. aChannels,
  67. aSampleRate));
  68. // Remove the frames we just pushed into the queue and loop if there is
  69. // more to be done.
  70. aTime += duration.value();
  71. aFrames -= framesCopied;
  72. // NOTE: No need to update aOffset as its only an approximation anyway.
  73. }
  74. return true;
  75. }
  76. // Copy functor suitable for copying audio samples already in the
  77. // AudioDataValue format/layout expected by AudioStream on this platform.
  78. class NativeCopy
  79. {
  80. public:
  81. NativeCopy(const uint8_t* aSource, size_t aSourceBytes,
  82. uint32_t aChannels)
  83. : mSource(aSource)
  84. , mSourceBytes(aSourceBytes)
  85. , mChannels(aChannels)
  86. , mNextByte(0)
  87. { }
  88. uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples);
  89. private:
  90. const uint8_t* const mSource;
  91. const size_t mSourceBytes;
  92. const uint32_t mChannels;
  93. size_t mNextByte;
  94. };
  95. // Allow 12.5% slop before chunking kicks in. Public so that the gtest can
  96. // access it.
  97. static const size_t MAX_SLOP_DIVISOR = 8;
  98. private:
  99. // Compute the number of AudioDataValue samples that will be fit the most
  100. // frames while keeping heap allocation slop less than the given threshold.
  101. static uint32_t
  102. GetChunkSamples(uint32_t aFrames, uint32_t aChannels, size_t aMaxSlop);
  103. static size_t BytesPerFrame(uint32_t aChannels)
  104. {
  105. return sizeof(AudioDataValue) * aChannels;
  106. }
  107. static size_t AudioDataSize(uint32_t aFrames, uint32_t aChannels)
  108. {
  109. return aFrames * BytesPerFrame(aChannels);
  110. }
  111. MediaQueue<AudioData> &mQueue;
  112. size_t mSamplesPadding;
  113. };
  114. } // namespace mozilla
  115. #endif // AudioCompactor_h