Bug 1248861: P10. Ensure opus decoder channel layout is always in SMPTE order. r=rillian
☠☠ backed out by d2fc02d6d642 ☠ ☠
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 05 Apr 2016 23:35:31 +1000
changeset 316224 b6a2c92ff375367e718e3de208e33baf5a87f9a3
parent 316223 24b970861675c0cfa10876b770942def8634b73d
child 316225 9eb3bffac91e5e260178551d14a92328a8e4926c
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrillian
bugs1248861
milestone48.0a1
Bug 1248861: P10. Ensure opus decoder channel layout is always in SMPTE order. r=rillian MozReview-Commit-ID: BDZ25pXJQWa
dom/media/platforms/agnostic/OpusDecoder.cpp
dom/media/platforms/agnostic/OpusDecoder.h
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -2,17 +2,19 @@
 /* vim:set ts=2 sw=2 sts=2 et cindent: */
 /* 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/. */
 
 #include "OpusDecoder.h"
 #include "TimeUnits.h"
 #include "VorbisUtils.h"
+#include "VorbisDecoder.h" // For VorbisLayout
 #include "mozilla/Endian.h"
+#include "mozilla/PodOperations.h"
 
 #include <stdint.h>
 #include <inttypes.h>  // For PRId64
 
 extern mozilla::LogModule* GetPDMLog();
 #define OPUS_DEBUG(arg, ...) MOZ_LOG(GetPDMLog(), mozilla::LogLevel::Debug, \
     ("OpusDataDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
 
@@ -61,17 +63,17 @@ OpusDataDecoder::Init()
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
   }
 
   int r;
   mOpusDecoder = opus_multistream_decoder_create(mOpusParser->mRate,
                                                  mOpusParser->mChannels,
                                                  mOpusParser->mStreams,
                                                  mOpusParser->mCoupledStreams,
-                                                 mOpusParser->mMappingTable,
+                                                 mMappingTable,
                                                  &r);
   mSkip = mOpusParser->mPreSkip;
   mPaddingDiscarded = false;
 
   if (codecDelay != FramesToUsecs(mOpusParser->mPreSkip,
                                   mOpusParser->mRate).value()) {
     NS_WARNING("Invalid Opus header: CodecDelay and pre-skip do not match!");
     return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
@@ -95,23 +97,40 @@ OpusDataDecoder::DecodeHeader(const unsi
   MOZ_ASSERT(!mOpusDecoder);
   MOZ_ASSERT(!mDecodedHeader);
   mDecodedHeader = true;
 
   mOpusParser = new OpusParser;
   if (!mOpusParser->DecodeHeader(const_cast<unsigned char*>(aData), aLength)) {
     return NS_ERROR_FAILURE;
   }
+  int channels = mOpusParser->mChannels;
   // No channel mapping for more than 8 channels.
-  if (mOpusParser->mChannels > 8) {
+  if (channels > 8) {
     OPUS_DEBUG("No channel mapping for more than 8 channels. Source is %d channels",
-               mOpusParser->mChannels);
+               channels);
     return NS_ERROR_FAILURE;
   }
 
+  AudioConfig::ChannelLayout vorbisLayout(
+    channels, VorbisDataDecoder::VorbisLayout(channels));
+  AudioConfig::ChannelLayout smpteLayout(channels);
+  static_assert(sizeof(mOpusParser->mMappingTable) / sizeof(mOpusParser->mMappingTable[0]) >= MAX_AUDIO_CHANNELS,
+                       "Invalid size set");
+  uint8_t map[sizeof(mOpusParser->mMappingTable) / sizeof(mOpusParser->mMappingTable[0])];
+  if (vorbisLayout.MappingTable(smpteLayout, map)) {
+    for (int i = 0; i < channels; i++) {
+      mMappingTable[i] = mOpusParser->mMappingTable[map[i]];
+    }
+  } else {
+    // Should never get here as vorbis layout is always convertible to SMPTE
+    // default layout.
+    PodCopy(mMappingTable, mOpusParser->mMappingTable, MAX_AUDIO_CHANNELS);
+  }
+
   return NS_OK;
 }
 
 nsresult
 OpusDataDecoder::Input(MediaRawData* aSample)
 {
   nsCOMPtr<nsIRunnable> runnable(
     NS_NewRunnableMethodWithArg<RefPtr<MediaRawData>>(
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -54,12 +54,13 @@ private:
   bool mDecodedHeader;
 
   // Opus padding should only be discarded on the final packet.  Once this
   // is set to true, if the reader attempts to decode any further packets it
   // will raise an error so we can indicate that the file is invalid.
   bool mPaddingDiscarded;
   int64_t mFrames;
   Maybe<int64_t> mLastFrameTime;
+  uint8_t mMappingTable[MAX_AUDIO_CHANNELS]; // Channel mapping table.
 };
 
 } // namespace mozilla
 #endif