Bug 1431221 - P10. Properly retrieve and set channel layout for opus and vorbis. r=cpearce draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Sun, 11 Feb 2018 18:58:03 +0100
changeset 771692 e5498bba39e88aba383a211ff1a56e6f4a23d55e
parent 771691 537a710487b2c29adee5c1d3cd614986f01f9b33
child 771693 4fbcdc69f42a66bd9f988cfb7837f61c1bc73c7f
push id103752
push userbmo:jyavenard@mozilla.com
push dateFri, 23 Mar 2018 17:52:32 +0000
reviewerscpearce
bugs1431221
milestone61.0a1
Bug 1431221 - P10. Properly retrieve and set channel layout for opus and vorbis. r=cpearce MozReview-Commit-ID: A4jEQzHRKDT
dom/media/platforms/agnostic/OpusDecoder.cpp
dom/media/platforms/agnostic/OpusDecoder.h
dom/media/platforms/agnostic/VorbisDecoder.cpp
--- a/dom/media/platforms/agnostic/OpusDecoder.cpp
+++ b/dom/media/platforms/agnostic/OpusDecoder.cpp
@@ -30,16 +30,17 @@ namespace mozilla {
 OpusDataDecoder::OpusDataDecoder(const CreateDecoderParams& aParams)
   : mInfo(aParams.AudioConfig())
   , mTaskQueue(aParams.mTaskQueue)
   , mOpusDecoder(nullptr)
   , mSkip(0)
   , mDecodedHeader(false)
   , mPaddingDiscarded(false)
   , mFrames(0)
+  , mChannelMap(AudioConfig::ChannelLayout::UNKNOWN_MAP)
 {
 }
 
 OpusDataDecoder::~OpusDataDecoder()
 {
   if (mOpusDecoder) {
     opus_multistream_decoder_destroy(mOpusDecoder);
     mOpusDecoder = nullptr;
@@ -125,28 +126,33 @@ OpusDataDecoder::DecodeHeader(const unsi
   mDecodedHeader = true;
 
   mOpusParser = new OpusParser;
   if (!mOpusParser->DecodeHeader(const_cast<unsigned char*>(aData), aLength)) {
     return NS_ERROR_FAILURE;
   }
   int channels = mOpusParser->mChannels;
 
-  AudioConfig::ChannelLayout layout(channels);
-  if (!layout.IsValid()) {
+  AudioConfig::ChannelLayout vorbisLayout(
+    channels, VorbisDataDecoder::VorbisLayout(channels));
+  if (!vorbisLayout.IsValid()) {
     OPUS_DEBUG("Invalid channel mapping. Source is %d channels", channels);
     return NS_ERROR_FAILURE;
   }
+  mChannelMap = vorbisLayout.Map();
 
-  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])];
+  AudioConfig::ChannelLayout smpteLayout(
+    AudioConfig::ChannelLayout::SMPTEDefault(vorbisLayout));
+
+  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);
@@ -313,19 +319,24 @@ OpusDataDecoder::ProcessDecode(MediaRawD
                   RESULT_DETAIL("Overflow shifting tstamp by codec delay")),
       __func__);
   };
 
 
   mFrames += frames;
 
   return DecodePromise::CreateAndResolve(
-    DecodedData{ new AudioData(aSample->mOffset, time, duration,
-                               frames, Move(buffer), mOpusParser->mChannels,
-                               mOpusParser->mRate) },
+    DecodedData{ new AudioData(aSample->mOffset,
+                               time,
+                               duration,
+                               frames,
+                               Move(buffer),
+                               mOpusParser->mChannels,
+                               mOpusParser->mRate,
+                               mChannelMap) },
     __func__);
 }
 
 RefPtr<MediaDataDecoder::DecodePromise>
 OpusDataDecoder::Drain()
 {
   RefPtr<OpusDataDecoder> self = this;
   // InvokeAsync dispatches a task that will be run after any pending decode
--- a/dom/media/platforms/agnostic/OpusDecoder.h
+++ b/dom/media/platforms/agnostic/OpusDecoder.h
@@ -64,12 +64,13 @@ private:
 
   // 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.
+  AudioConfig::ChannelLayout::ChannelMap mChannelMap;
 };
 
 } // namespace mozilla
 #endif
--- a/dom/media/platforms/agnostic/VorbisDecoder.cpp
+++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp
@@ -228,33 +228,41 @@ VorbisDataDecoder::ProcessDecode(MediaRa
       return DecodePromise::CreateAndReject(
         MediaResult(
           NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
           RESULT_DETAIL("Overflow adding total_duration and aSample->mTime")),
         __func__);
     };
 
     if (!mAudioConverter) {
-      AudioConfig in(
-        AudioConfig::ChannelLayout(channels, VorbisLayout(channels)), rate);
-      AudioConfig out(channels, rate);
+      const AudioConfig::ChannelLayout layout =
+        AudioConfig::ChannelLayout(channels, VorbisLayout(channels));
+      AudioConfig in(layout, rate);
+      AudioConfig out(AudioConfig::ChannelLayout::SMPTEDefault(layout), rate);
       if (!in.IsValid() || !out.IsValid()) {
         return DecodePromise::CreateAndReject(
           MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
                       RESULT_DETAIL("Invalid channel layout:%u", channels)),
           __func__);
       }
       mAudioConverter = MakeUnique<AudioConverter>(in, out);
     }
     MOZ_ASSERT(mAudioConverter->CanWorkInPlace());
     AudioSampleBuffer data(Move(buffer));
     data = mAudioConverter->Process(Move(data));
 
-    results.AppendElement(new AudioData(aOffset, time, duration,
-                                        frames, data.Forget(), channels, rate));
+    results.AppendElement(
+      new AudioData(aOffset,
+                    time,
+                    duration,
+                    frames,
+                    data.Forget(),
+                    channels,
+                    rate,
+                    mAudioConverter->OutputConfig().Layout().Map()));
     mFrames += frames;
     err = vorbis_synthesis_read(&mVorbisDsp, frames);
     if (err) {
       return DecodePromise::CreateAndReject(
         MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
                     RESULT_DETAIL("vorbis_synthesis_read:%d", err)),
         __func__);
     }