Bug 1248861: P7. Ensure vorbis decoder channel layout is always in SMPTE order. r=rillian
☠☠ backed out by 615f67ac2823 ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 05 Apr 2016 23:14:34 +1000
changeset 330279 ddff88a6db07072fc69e256b7b22535647e2b9a5
parent 330278 0565edbead7fa107491b3ea72dca001a369a548e
child 330280 b326f17035c14bf743b80455d5cef193c82fe748
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs1248861
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 1248861: P7. Ensure vorbis decoder channel layout is always in SMPTE order. r=rillian MozReview-Commit-ID: GAqnJbQuqQU
dom/media/platforms/agnostic/VorbisDecoder.cpp
dom/media/platforms/agnostic/VorbisDecoder.h
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -185,53 +185,63 @@ VorbisDataDecoder::DoDecode(MediaRawData
                                     0,
                                     0,
                                     AlignedAudioBuffer(),
                                     mVorbisDsp.vi->channels,
                                     mVorbisDsp.vi->rate));
   }
   while (frames > 0) {
     uint32_t channels = mVorbisDsp.vi->channels;
+    uint32_t rate = mVorbisDsp.vi->rate;
     AlignedAudioBuffer buffer(frames*channels);
     if (!buffer) {
       return -1;
     }
     for (uint32_t j = 0; j < channels; ++j) {
       VorbisPCMValue* channel = pcm[j];
       for (uint32_t i = 0; i < uint32_t(frames); ++i) {
         buffer[i*channels + j] = MOZ_CONVERT_VORBIS_SAMPLE(channel[i]);
       }
     }
 
-    CheckedInt64 duration = FramesToUsecs(frames, mVorbisDsp.vi->rate);
+    CheckedInt64 duration = FramesToUsecs(frames, rate);
     if (!duration.isValid()) {
       NS_WARNING("Int overflow converting WebM audio duration");
       return -1;
     }
-    CheckedInt64 total_duration = FramesToUsecs(mFrames,
-                                                mVorbisDsp.vi->rate);
+    CheckedInt64 total_duration = FramesToUsecs(mFrames, rate);
     if (!total_duration.isValid()) {
       NS_WARNING("Int overflow converting WebM audio total_duration");
       return -1;
     }
 
     CheckedInt64 time = total_duration + aTstampUsecs;
     if (!time.isValid()) {
       NS_WARNING("Int overflow adding total_duration and aTstampUsecs");
       return -1;
     };
 
+    if (!mAudioConverter) {
+      AudioConfig in(AudioConfig::ChannelLayout(channels, VorbisLayout(channels)),
+                     rate);
+      AudioConfig out(channels, rate);
+      mAudioConverter = MakeUnique<AudioConverter>(in, out);
+    }
+    MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
+    AudioSampleBuffer data(Move(buffer));
+    mAudioConverter->Process(data);
+
     aTotalFrames += frames;
     mCallback->Output(new AudioData(aOffset,
                                     time.value(),
                                     duration.value(),
                                     frames,
-                                    Move(buffer),
-                                    mVorbisDsp.vi->channels,
-                                    mVorbisDsp.vi->rate));
+                                    data.Forget(),
+                                    channels,
+                                    rate));
     mFrames += frames;
     if (vorbis_synthesis_read(&mVorbisDsp, frames) != 0) {
       return -1;
     }
 
     frames = vorbis_synthesis_pcmout(&mVorbisDsp, &pcm);
   }
 
@@ -268,11 +278,63 @@ VorbisDataDecoder::Flush()
 /* static */
 bool
 VorbisDataDecoder::IsVorbis(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("audio/webm; codecs=vorbis") ||
          aMimeType.EqualsLiteral("audio/ogg; codecs=vorbis");
 }
 
+/* static */ const AudioConfig::Channel*
+VorbisDataDecoder::VorbisLayout(uint32_t aChannels)
+{
+  // From https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
+  // Section 4.3.9.
+  typedef AudioConfig::Channel Channel;
+
+  switch (aChannels) {
+    case 1: // the stream is monophonic
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_MONO };
+      return config;
+    }
+    case 2: // the stream is stereo. channel order: left, right
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_RIGHT };
+      return config;
+    }
+    case 3: // the stream is a 1d-surround encoding. channel order: left, center, right
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT };
+      return config;
+    }
+    case 4: // the stream is quadraphonic surround. channel order: front left, front right, rear left, rear right
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS };
+      return config;
+    }
+    case 5: // the stream is five-channel surround. channel order: front left, center, front right, rear left, rear right
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS };
+      return config;
+    }
+    case 6: // the stream is 5.1 surround. channel order: front left, center, front right, rear left, rear right, LFE
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS, AudioConfig::CHANNEL_LFE };
+      return config;
+    }
+    case 7: // surround. channel order: front left, center, front right, side left, side right, rear center, LFE
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS, AudioConfig::CHANNEL_RCENTER, AudioConfig::CHANNEL_LFE };
+      return config;
+    }
+    case 8: // the stream is 7.1 surround. channel order: front left, center, front right, side left, side right, rear left, rear right, LFE
+    {
+      static const Channel config[] = { AudioConfig::CHANNEL_LEFT, AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_RIGHT, AudioConfig::CHANNEL_LS, AudioConfig::CHANNEL_RS, AudioConfig::CHANNEL_RLS, AudioConfig::CHANNEL_RRS, AudioConfig::CHANNEL_LFE };
+      return config;
+    }
+    default:
+      return nullptr;
+  }
+}
 
 } // namespace mozilla
 #undef LOG
--- a/dom/media/platforms/agnostic/VorbisDecoder.h
+++ b/dom/media/platforms/agnostic/VorbisDecoder.h
@@ -3,16 +3,17 @@
 /* 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(VorbisDecoder_h_)
 #define VorbisDecoder_h_
 
 #include "PlatformDecoderModule.h"
 #include "mozilla/Maybe.h"
+#include "AudioConverter.h"
 
 #ifdef MOZ_TREMOR
 #include "tremor/ivorbiscodec.h"
 #else
 #include "vorbis/codec.h"
 #endif
 
 namespace mozilla {
@@ -32,16 +33,17 @@ public:
   nsresult Shutdown() override;
   const char* GetDescriptionName() const override
   {
     return "vorbis audio decoder";
   }
 
   // Return true if mimetype is Vorbis
   static bool IsVorbis(const nsACString& aMimeType);
+  static const AudioConfig::Channel* VorbisLayout(uint32_t aChannels);
 
 private:
   nsresult DecodeHeader(const unsigned char* aData, size_t aLength);
 
   void Decode (MediaRawData* aSample);
   int DoDecode (MediaRawData* aSample);
   void DoDrain ();
 
@@ -53,12 +55,13 @@ private:
   vorbis_info mVorbisInfo;
   vorbis_comment mVorbisComment;
   vorbis_dsp_state mVorbisDsp;
   vorbis_block mVorbisBlock;
 
   int64_t mPacketCount;
   int64_t mFrames;
   Maybe<int64_t> mLastFrameTime;
+  UniquePtr<AudioConverter> mAudioConverter;
 };
 
 } // namespace mozilla
 #endif