Bug 991504 - Detect silent chunk when resampling, and properly handle them. r=roc
authorPaul Adenot <paul@paul.cx>
Mon, 07 Apr 2014 18:22:11 +0200
changeset 196776 b43f62c11005a5a8b13327ba2101c82db0a4160a
parent 196775 31dbf8a76158024d0bf33f28c494b1977c163ad0
child 196777 2f78b61616489359d4d41756035c105ca4a048aa
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs991504
milestone31.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 991504 - Detect silent chunk when resampling, and properly handle them. r=roc
content/media/AudioSampleFormat.h
content/media/AudioSegment.cpp
content/media/AudioSegment.h
--- a/content/media/AudioSampleFormat.h
+++ b/content/media/AudioSampleFormat.h
@@ -19,16 +19,18 @@ namespace mozilla {
  * produce that format only; queued AudioData always uses that format.
  */
 enum AudioSampleFormat
 {
   // Native-endian signed 16-bit audio samples
   AUDIO_FORMAT_S16,
   // Signed 32-bit float samples
   AUDIO_FORMAT_FLOAT32,
+  // Silence: format will be chosen later
+  AUDIO_FORMAT_SILENCE,
   // The format used for output by AudioStream.
 #ifdef MOZ_SAMPLE_TYPE_S16
   AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_S16
 #else
   AUDIO_OUTPUT_FORMAT = AUDIO_FORMAT_FLOAT32
 #endif
 };
 
--- a/content/media/AudioSegment.cpp
+++ b/content/media/AudioSegment.cpp
@@ -47,16 +47,19 @@ InterleaveAndConvertBuffer(const void** 
     break;
   case AUDIO_FORMAT_S16:
     InterleaveAndConvertBuffer(reinterpret_cast<const int16_t**>(aSourceChannels),
                                aLength,
                                aVolume,
                                aChannels,
                                aOutput);
     break;
+   case AUDIO_FORMAT_SILENCE:
+    // nothing to do here.
+    break;
   }
 }
 
 void
 AudioSegment::ApplyVolume(float aVolume)
 {
   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     ci->mVolume *= aVolume;
@@ -116,17 +119,28 @@ void AudioSegment::ResampleChunks(SpeexR
   uint32_t inRate, outRate;
 
   if (mChunks.IsEmpty()) {
     return;
   }
 
   speex_resampler_get_rate(aResampler, &inRate, &outRate);
 
-  switch (mChunks[0].mBufferFormat) {
+  AudioSampleFormat format = AUDIO_FORMAT_SILENCE;
+  for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
+    if (ci->mBufferFormat != AUDIO_FORMAT_SILENCE) {
+      format = ci->mBufferFormat;
+    }
+  }
+
+  switch (format) {
+    // If the format is silence at this point, all the chunks are silent. The
+    // actual function we use does not matter, it's just a matter of changing
+    // the chunks duration.
+    case AUDIO_FORMAT_SILENCE:
     case AUDIO_FORMAT_FLOAT32:
       Resample<float>(aResampler, inRate, outRate);
     break;
     case AUDIO_FORMAT_S16:
       Resample<int16_t>(aResampler, inRate, outRate);
     break;
     default:
       MOZ_ASSERT(false);
--- a/content/media/AudioSegment.h
+++ b/content/media/AudioSegment.h
@@ -105,16 +105,17 @@ struct AudioChunk {
   }
   bool IsNull() const { return mBuffer == nullptr; }
   void SetNull(TrackTicks aDuration)
   {
     mBuffer = nullptr;
     mChannelData.Clear();
     mDuration = aDuration;
     mVolume = 1.0f;
+    mBufferFormat = AUDIO_FORMAT_SILENCE;
   }
   int ChannelCount() const { return mChannelData.Length(); }
 
   TrackTicks mDuration; // in frames within the buffer
   nsRefPtr<ThreadSharedObject> mBuffer; // the buffer object whose lifetime is managed; null means data is all zeroes
   nsTArray<const void*> mChannelData; // one pointer per channel; empty if and only if mBuffer is null
   float mVolume; // volume multiplier to apply (1.0f if mBuffer is nonnull)
   SampleFormat mBufferFormat; // format of frames in mBuffer (only meaningful if mBuffer is nonnull)
@@ -139,16 +140,21 @@ public:
   void Resample(SpeexResamplerState* aResampler, uint32_t aInRate, uint32_t aOutRate)
   {
     mDuration = 0;
 
     for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
       nsAutoTArray<nsTArray<T>, GUESS_AUDIO_CHANNELS> output;
       nsAutoTArray<const T*, GUESS_AUDIO_CHANNELS> bufferPtrs;
       AudioChunk& c = *ci;
+      // If this chunk is null, don't bother resampling, just alter its duration
+      if (c.IsNull()) {
+        c.mDuration *= aOutRate / aInRate;
+        mDuration += c.mDuration;
+      }
       uint32_t channels = c.mChannelData.Length();
       output.SetLength(channels);
       bufferPtrs.SetLength(channels);
       uint32_t inFrames = c.mDuration,
       outFrames = c.mDuration * aOutRate / aInRate;
       for (uint32_t i = 0; i < channels; i++) {
         const T* in = static_cast<const T*>(c.mChannelData[i]);
         T* out = output[i].AppendElements(outFrames);