Bug 1248861: P7. Ensure vorbis decoder channel layout is always in SMPTE order. r=rillian
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 05 Apr 2016 23:14:34 +1000
changeset 330579 ee6f81089bbef1a410ed071385db3afb1b433a80
parent 330578 011a0670d86584766920d5e04f91dc3ba7a8677a
child 330580 bf78ded55e21463df4a8e5878afa396ccbd41100
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