Bug 1262753: P5. Pass number of frames rather than the number of bytes. r=gerald
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 12 Apr 2016 12:16:38 +1000
changeset 333424 a610786074e762d2eb5713d658e157e21913cf29
parent 333423 35cf8fc31a77376b4893e3886970c6a6557ab931
child 333425 ed60dd41a220b728920e023443a47ffe94989917
push id1146
push userCallek@gmail.com
push dateMon, 25 Jul 2016 16:35:44 +0000
treeherdermozilla-release@a55778f9cd5a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1262753
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1262753: P5. Pass number of frames rather than the number of bytes. r=gerald The Process API was originally planned to be used to also convert data type. However, this task is now the responsibility of the AudioDataBuffer class. We can simplify the logic and use frames everywhere. MozReview-Commit-ID: KvKn1d1yHqQ
dom/media/AudioConverter.cpp
dom/media/AudioConverter.h
dom/media/AudioStream.cpp
--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -68,27 +68,27 @@ AudioConverter::CanWorkInPlace() const
   // We should be able to work in place if 1s of audio input takes less space
   // than 1s of audio output. However, as we downmix before resampling we can't
   // perform any upsampling in place (e.g. if incoming rate >= outgoing rate)
   return (!needDownmix || canDownmixInPlace) &&
          (!needResample || canResampleInPlace);
 }
 
 size_t
-AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aBytes)
+AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aFrames)
 {
   if (mIn.Channels() > mOut.Channels()) {
-    return DownmixAudio(aOut, aIn, aBytes);
+    return DownmixAudio(aOut, aIn, aFrames);
   } else if (mIn.Layout() != mOut.Layout() &&
       CanReorderAudio()) {
-    ReOrderInterleavedChannels(aOut, aIn, aBytes);
+    ReOrderInterleavedChannels(aOut, aIn, aFrames);
   } else if (aIn != aOut) {
-    memmove(aOut, aIn, aBytes);
+    memmove(aOut, aIn, FramesOutToBytes(aFrames));
   }
-  return aBytes;
+  return aFrames;
 }
 
 // Reorder interleaved channels.
 // Can work in place (e.g aOut == aIn).
 template <class AudioDataType>
 void
 _ReOrderInterleavedChannels(AudioDataType* aOut, const AudioDataType* aIn,
                             uint32_t aFrames, uint32_t aChannels,
@@ -105,95 +105,90 @@ void
     }
     aOut += aChannels;
     aIn += aChannels;
   }
 }
 
 void
 AudioConverter::ReOrderInterleavedChannels(void* aOut, const void* aIn,
-                                           size_t aDataSize) const
+                                           size_t aFrames) const
 {
   MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() == mOut.Channels());
 
   if (mOut.Layout() == mIn.Layout()) {
     return;
   }
   if (mOut.Channels() == 1) {
     // If channel count is 1, planar and non-planar formats are the same and
     // there's nothing to reorder.
     if (aOut != aIn) {
-      memmove(aOut, aIn, aDataSize);
+      memmove(aOut, aIn, FramesOutToBytes(aFrames));
     }
     return;
   }
 
   uint32_t bits = AudioConfig::FormatToBits(mOut.Format());
   switch (bits) {
     case 8:
       _ReOrderInterleavedChannels((uint8_t*)aOut, (const uint8_t*)aIn,
-                                  aDataSize/sizeof(uint8_t)/mIn.Channels(),
-                                  mIn.Channels(), mChannelOrderMap);
+                                  aFrames, mIn.Channels(), mChannelOrderMap);
       break;
     case 16:
       _ReOrderInterleavedChannels((int16_t*)aOut,(const int16_t*)aIn,
-                                  aDataSize/sizeof(int16_t)/mIn.Channels(),
-                                  mIn.Channels(), mChannelOrderMap);
+                                  aFrames, mIn.Channels(), mChannelOrderMap);
       break;
     default:
       MOZ_DIAGNOSTIC_ASSERT(AudioConfig::SampleSize(mOut.Format()) == 4);
       _ReOrderInterleavedChannels((int32_t*)aOut,(const int32_t*)aIn,
-                                  aDataSize/sizeof(int32_t)/mIn.Channels(),
-                                  mIn.Channels(), mChannelOrderMap);
+                                  aFrames, mIn.Channels(), mChannelOrderMap);
       break;
   }
 }
 
 static inline int16_t clipTo15(int32_t aX)
 {
   return aX < -32768 ? -32768 : aX <= 32767 ? aX : 32767;
 }
 
 size_t
-AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const
+AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
 {
   MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
              mIn.Format() == AudioConfig::FORMAT_FLT);
   MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
   MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
              "Can only downmix input data in SMPTE layout");
   MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
              mOut.Layout() == AudioConfig::ChannelLayout(1));
 
   uint32_t channels = mIn.Channels();
-  uint32_t frames =
-    aDataSize / AudioConfig::SampleSize(mOut.Format()) / channels;
 
   if (channels == 1 && mOut.Channels() == 1) {
     if (aOut != aIn) {
-      memmove(aOut, aIn, aDataSize);
+      memmove(aOut, aIn, FramesOutToBytes(aFrames));
     }
-    return aDataSize;
+    return aFrames;
   }
 
   if (channels > 2) {
     if (mIn.Format() == AudioConfig::FORMAT_FLT) {
       // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
       static const float dmatrix[6][8][2]= {
           /*3*/{{0.5858f,0},{0,0.5858f},{0.4142f,0.4142f}},
           /*4*/{{0.4226f,0},{0,0.4226f},{0.366f, 0.2114f},{0.2114f,0.366f}},
           /*5*/{{0.6510f,0},{0,0.6510f},{0.4600f,0.4600f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
           /*6*/{{0.5290f,0},{0,0.5290f},{0.3741f,0.3741f},{0.3741f,0.3741f},{0.4582f,0.2645f},{0.2645f,0.4582f}},
           /*7*/{{0.4553f,0},{0,0.4553f},{0.3220f,0.3220f},{0.3220f,0.3220f},{0.2788f,0.2788f},{0.3943f,0.2277f},{0.2277f,0.3943f}},
           /*8*/{{0.3886f,0},{0,0.3886f},{0.2748f,0.2748f},{0.2748f,0.2748f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f}},
       };
       // Re-write the buffer with downmixed data
       const float* in = static_cast<const float*>(aIn);
       float* out = static_cast<float*>(aOut);
-      for (uint32_t i = 0; i < frames; i++) {
+      for (uint32_t i = 0; i < aFrames; i++) {
         float sampL = 0.0;
         float sampR = 0.0;
         for (uint32_t j = 0; j < channels; j++) {
           sampL += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][0];
           sampR += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][1];
         }
         *out++ = sampL;
         *out++ = sampR;
@@ -207,17 +202,17 @@ AudioConverter::DownmixAudio(void* aOut,
           /*5*/{{10663,0},{0,  10663},{7540,7540},{9234,5331},{5331,9234}},
           /*6*/{{8668, 0},{0,   8668},{6129,6129},{6129,6129},{7507,4335},{4335,7507}},
           /*7*/{{7459, 0},{0,   7459},{5275,5275},{5275,5275},{4568,4568},{6460,3731},{3731,6460}},
           /*8*/{{6368, 0},{0,   6368},{4502,4502},{4502,4502},{5514,3184},{3184,5514},{5514,3184},{3184,5514}}
       };
       // Re-write the buffer with downmixed data
       const int16_t* in = static_cast<const int16_t*>(aIn);
       int16_t* out = static_cast<int16_t*>(aOut);
-      for (uint32_t i = 0; i < frames; i++) {
+      for (uint32_t i = 0; i < aFrames; i++) {
         int32_t sampL = 0;
         int32_t sampR = 0;
         for (uint32_t j = 0; j < channels; j++) {
           sampL+=in[i*channels+j]*dmatrix[channels-3][j][0];
           sampR+=in[i*channels+j]*dmatrix[channels-3][j][1];
         }
         *out++ = clipTo15((sampL + 8192)>>14);
         *out++ = clipTo15((sampR + 8192)>>14);
@@ -231,65 +226,80 @@ AudioConverter::DownmixAudio(void* aOut,
     aIn = aOut;
     channels = 2;
   }
 
   if (mOut.Channels() == 1) {
     if (mIn.Format() == AudioConfig::FORMAT_FLT) {
       const float* in = static_cast<const float*>(aIn);
       float* out = static_cast<float*>(aOut);
-      for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+      for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
         float sample = 0.0;
         // The sample of the buffer would be interleaved.
         sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
         *out++ = sample;
       }
     } else if (mIn.Format() == AudioConfig::FORMAT_S16) {
       const int16_t* in = static_cast<const int16_t*>(aIn);
       int16_t* out = static_cast<int16_t*>(aOut);
-      for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+      for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
         int32_t sample = 0.0;
         // The sample of the buffer would be interleaved.
         sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
         *out++ = sample;
       }
     } else {
       MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
     }
   }
-  return (size_t)frames * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels();
+  return aFrames;
 }
 
 size_t
-AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aDataSize)
+AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
 {
   if (!mResampler) {
     return 0;
   }
-  uint32_t frames =
-    aDataSize / AudioConfig::SampleSize(mOut.Format()) / mOut.Channels();
-  uint32_t outframes = ResampleRecipientFrames(frames);
-  uint32_t inframes = frames;
+  uint32_t outframes = ResampleRecipientFrames(aFrames);
+  uint32_t inframes = aFrames;
 
   if (mOut.Format() == AudioConfig::FORMAT_FLT) {
     const float* in = reinterpret_cast<const float*>(aIn);
     float* out = reinterpret_cast<float*>(aOut);
     speex_resampler_process_interleaved_float(mResampler, in, &inframes,
                                               out, &outframes);
   } else if (mOut.Format() == AudioConfig::FORMAT_S16) {
     const int16_t* in = reinterpret_cast<const int16_t*>(aIn);
     int16_t* out = reinterpret_cast<int16_t*>(aOut);
     speex_resampler_process_interleaved_int(mResampler, in, &inframes,
                                             out, &outframes);
   } else {
     MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
   }
-  MOZ_ASSERT(inframes == frames, "Some frames will be dropped");
-  return (size_t)outframes * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels();
+  MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
+  return outframes;
 }
 
 size_t
 AudioConverter::ResampleRecipientFrames(size_t aFrames) const
 {
   return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
 }
 
+size_t
+AudioConverter::FramesOutToSamples(size_t aFrames) const
+{
+  return aFrames * mOut.Channels();
+}
+
+size_t
+AudioConverter::SamplesInToFrames(size_t aSamples) const
+{
+  return aSamples / mIn.Channels();
+}
+
+size_t
+AudioConverter::FramesOutToBytes(size_t aFrames) const
+{
+  return FramesOutToSamples(aFrames) * AudioConfig::SampleSize(mOut.Format());
+}
 } // namespace mozilla
--- a/dom/media/AudioConverter.h
+++ b/dom/media/AudioConverter.h
@@ -124,74 +124,73 @@ public:
   // Conversion will be done in place if possible. Otherwise a new buffer will
   // be returned.
   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 bytes = ProcessInternal(buffer.Data(), buffer.Data(), buffer.Size());
-      if (bytes && mIn.Rate() != mOut.Rate()) {
-        bytes = ResampleAudio(buffer.Data(), buffer.Data(), bytes);
+      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(bytes / AudioConfig::SampleSize(mOut.Format()));
+      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.
-    uint32_t frames = aBuffer.Length() / mIn.Channels();
+    size_t frames = SamplesInToFrames(aBuffer.Length());
     AlignedBuffer<Value> temp1;
-    if (!temp1.SetLength(frames * mOut.Channels())) {
+    if (!temp1.SetLength(FramesOutToSamples(frames))) {
       return AudioDataBuffer<Format, Value>(Move(temp1));
     }
-    size_t bytes = ProcessInternal(temp1.Data(), aBuffer.Data(), aBuffer.Size());
-    if (!bytes || mIn.Rate() == mOut.Rate()) {
-      temp1.SetLength(bytes / AudioConfig::SampleSize(mOut.Format()));
+    frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
+    if (!frames || mIn.Rate() == mOut.Rate()) {
+      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 (mOut.Rate() > mIn.Rate()) {
       // We are upsampling, we can't work in place. Allocate another temporary
       // buffer where the upsampling will occur.
-      temp2.SetLength(ResampleRecipientFrames(frames) * mOut.Channels());
+      temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)));
       outputBuffer = &temp2;
     }
-    bytes = ResampleAudio(outputBuffer->Data(), temp1.Data(), bytes);
-    outputBuffer->SetLength(bytes / AudioConfig::SampleSize(mOut.Format()));
+    frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
+    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 aSamples)
+  size_t Process(Value* aBuffer, size_t aFrames)
   {
     MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
     if (!CanWorkInPlace()) {
       return 0;
     }
-    size_t bytes =
-      ProcessInternal(aBuffer, aBuffer,
-                      aSamples * AudioConfig::SampleSize(mIn.Format()));
-    if (bytes && mIn.Rate() != mOut.Rate()) {
-      bytes = ResampleAudio(aBuffer, aBuffer, bytes);
+    size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
+    if (frames && mIn.Rate() != mOut.Rate()) {
+      frames = ResampleAudio(aBuffer, aBuffer, aFrames);
     }
-    return bytes;
+    return frames;
   }
 
   bool CanWorkInPlace() const;
   bool CanReorderAudio() const
   {
     return mIn.Layout().MappingTable(mOut.Layout());
   }
 
@@ -202,25 +201,29 @@ 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
-   * aBytes: size in bytes of source buffer
+   * aSamples: number of frames in source buffer
    *
-   * Return Value: size in bytes of samples converted or 0 if error
+   * Return Value: number of frames converted or 0 if error
    */
-  size_t ProcessInternal(void* aOut, const void* aIn, size_t aBytes);
-  void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aDataSize) const;
-  size_t DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const;
+  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 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 aDataSize);
+  size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
   size_t ResampleRecipientFrames(size_t aFrames) const;
 };
 
 } // namespace mozilla
 
 #endif /* AudioConverter_h */
--- a/dom/media/AudioStream.cpp
+++ b/dom/media/AudioStream.cpp
@@ -558,18 +558,17 @@ AudioStream::Downmix(Chunk* aChunk)
   }
 
   if (aChunk->Channels() > 8) {
     return false;
   }
 
   if (aChunk->Channels() > 2) {
     MOZ_ASSERT(mAudioConverter);
-    mAudioConverter->Process(aChunk->GetWritable(),
-                             aChunk->Channels() * aChunk->Frames());
+    mAudioConverter->Process(aChunk->GetWritable(), aChunk->Frames());
   }
 
   if (aChunk->Channels() >= 2 && mIsMonoAudioEnabled) {
     DownmixStereoToMono(aChunk->GetWritable(), aChunk->Frames());
   }
 
   return true;
 }