Bug 1248861: P4. Add AudioConfig and introduce channel layout definition. r=cpearce
authorJean-Yves Avenard <jyavenard@mozilla.com>
Wed, 06 Apr 2016 10:20:42 +1000
changeset 330576 45e19952805dbbded2845cbaa21f1abaf83d0f69
parent 330575 6aa7d5d7d5c325070402d9df3b86538ab6ae3ed1
child 330577 ccfb0594978c959a4166b17314b8dc94b85be844
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)
reviewerscpearce
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: P4. Add AudioConfig and introduce channel layout definition. r=cpearce Long term goal would be to merge AudioConfig with the existing AudioInfo class which doesn't provide sufficient data to properly determine how to play multichannel audio. MozReview-Commit-ID: 3UDpZWPBUvS
dom/media/MediaInfo.cpp
dom/media/MediaInfo.h
dom/media/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaInfo.cpp
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "MediaInfo.h"
+
+namespace mozilla {
+
+typedef AudioConfig::ChannelLayout ChannelLayout;
+
+/**
+ * AudioConfig::ChannelLayout
+ */
+
+/*
+ SMPTE channel layout (also known as wave order)
+ DUAL-MONO      L   R
+ DUAL-MONO-LFE  L   R   LFE
+ MONO           M
+ MONO-LFE       M   LFE
+ STEREO         L   R
+ STEREO-LFE     L   R   LFE
+ 3F             L   R   C
+ 3F-LFE         L   R   C    LFE
+ 2F1            L   R   S
+ 2F1-LFE        L   R   LFE  S
+ 3F1            L   R   C    S
+ 3F1-LFE        L   R   C    LFE S
+ 2F2            L   R   LS   RS
+ 2F2-LFE        L   R   LFE  LS   RS
+ 3F2            L   R   C    LS   RS
+ 3F2-LFE        L   R   C    LFE  LS   RS
+ 3F3R-LFE       L   R   C    LFE  BC   LS   RS
+ 3F4-LFE        L   R   C    LFE  Rls  Rrs  LS   RS
+*/
+
+void
+AudioConfig::ChannelLayout::UpdateChannelMap()
+{
+  mChannelMap = 0;
+  mValid = mChannels.Length() <= MAX_AUDIO_CHANNELS;
+  for (size_t i = 0; i < mChannels.Length() && i <= MAX_AUDIO_CHANNELS; i++) {
+    uint32_t mask = 1 << mChannels[i];
+    if (mChannels[i] == CHANNEL_INVALID || (mChannelMap & mask)) {
+      mValid = false;
+    }
+    mChannelMap |= mask;
+  }
+}
+
+/* static */ const AudioConfig::Channel*
+AudioConfig::ChannelLayout::SMPTEDefault(uint32_t aChannels) const
+{
+  switch (aChannels) {
+    case 1: // MONO
+    {
+      static const Channel config[] = { CHANNEL_MONO };
+      return config;
+    }
+    case 2: // STEREO
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT };
+      return config;
+    }
+    case 3: // 3F
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER };
+      return config;
+    }
+    case 4: // 2F2
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_LS, CHANNEL_RS };
+      return config;
+    }
+    case 5: // 3F2
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LS, CHANNEL_RS };
+      return config;
+    }
+    case 6: // 3F2-LFE
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_LS, CHANNEL_RS };
+      return config;
+    }
+    case 7: // 3F3R-LFE
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RCENTER, CHANNEL_LS, CHANNEL_RS };
+      return config;
+    }
+    case 8: // 3F4-LFE
+    {
+      static const Channel config[] = { CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RLS, CHANNEL_RRS, CHANNEL_LS, CHANNEL_RS };
+      return config;
+    }
+    default:
+      return nullptr;
+  }
+}
+
+/**
+ * AudioConfig::ChannelConfig
+ */
+
+/* static */ const char*
+AudioConfig::FormatToString(AudioConfig::SampleFormat aFormat)
+{
+  switch (aFormat) {
+    case FORMAT_U8:     return "unsigned 8 bit";
+    case FORMAT_S16:    return "signed 16 bit";
+    case FORMAT_S24:    return "signed 24 bit MSB";
+    case FORMAT_S24LSB: return "signed 24 bit LSB";
+    case FORMAT_S32:    return "signed 32 bit";
+    case FORMAT_FLT:    return "32 bit floating point";
+    case FORMAT_NONE:   return "none";
+    default:            return "unknown";
+  }
+}
+/* static */ uint32_t
+AudioConfig::SampleSize(AudioConfig::SampleFormat aFormat)
+{
+  switch (aFormat) {
+    case FORMAT_U8:     return 1;
+    case FORMAT_S16:    return 2;
+    case FORMAT_S24:    MOZ_FALLTHROUGH;
+    case FORMAT_S24LSB: MOZ_FALLTHROUGH;
+    case FORMAT_S32:    MOZ_FALLTHROUGH;
+    case FORMAT_FLT:    return 4;
+    case FORMAT_NONE:
+    default:            return 0;
+  }
+}
+
+/* static */ uint32_t
+AudioConfig::FormatToBits(AudioConfig::SampleFormat aFormat)
+{
+  switch (aFormat) {
+    case FORMAT_U8:     return 8;
+    case FORMAT_S16:    return 16;
+    case FORMAT_S24LSB: MOZ_FALLTHROUGH;
+    case FORMAT_S24:    return 24;
+    case FORMAT_S32:    MOZ_FALLTHROUGH;
+    case FORMAT_FLT:    return 32;
+    case FORMAT_NONE:   MOZ_FALLTHROUGH;
+    default:            return 0;
+  }
+}
+
+AudioConfig::AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
+                         AudioConfig::SampleFormat aFormat, bool aInterleaved)
+  : mChannelLayout(aChannelLayout)
+  , mChannels(aChannelLayout.Count())
+  , mRate(aRate)
+  , mFormat(aFormat)
+  , mInterleaved(aInterleaved)
+{}
+
+AudioConfig::AudioConfig(uint32_t aChannels, uint32_t aRate,
+                         AudioConfig::SampleFormat aFormat, bool aInterleaved)
+  : mChannelLayout(aChannels)
+  , mChannels(aChannels)
+  , mRate(aRate)
+  , mFormat(aFormat)
+  , mInterleaved(aInterleaved)
+{}
+
+} // namespace mozilla
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -469,11 +469,148 @@ private:
   UniquePtr<TrackInfo> mInfo;
   // A unique ID, guaranteed to change when changing streams.
   uint32_t mStreamSourceID;
 
 public:
   const nsCString& mMimeType;
 };
 
+// Maximum channel number we can currently handle (7.1)
+#define MAX_AUDIO_CHANNELS 8
+
+class AudioConfig {
+public:
+  enum Channel {
+    CHANNEL_INVALID = -1,
+    CHANNEL_MONO = 0,
+    CHANNEL_LEFT,
+    CHANNEL_RIGHT,
+    CHANNEL_CENTER,
+    CHANNEL_LS,
+    CHANNEL_RS,
+    CHANNEL_RLS,
+    CHANNEL_RCENTER,
+    CHANNEL_RRS,
+    CHANNEL_LFE,
+  };
+
+  class ChannelLayout {
+  public:
+    ChannelLayout()
+      : mChannelMap(0)
+      , mValid(false)
+    {}
+    explicit ChannelLayout(uint32_t aChannels)
+      : ChannelLayout(aChannels, SMPTEDefault(aChannels))
+    {}
+    ChannelLayout(uint32_t aChannels, const Channel* aConfig)
+    {
+      mChannels.AppendElements(aConfig, aChannels);
+      UpdateChannelMap();
+    }
+    bool operator==(const ChannelLayout& aOther) const
+    {
+      return mChannels == aOther.mChannels;
+    }
+    bool operator!=(const ChannelLayout& aOther) const
+    {
+      return mChannels != aOther.mChannels;
+    }
+    const Channel& operator[](uint32_t aIndex) const
+    {
+      return mChannels[aIndex];
+    }
+    uint32_t Count() const
+    {
+      return mChannels.Length();
+    }
+    uint32_t Map() const
+    {
+      return mChannelMap;
+    }
+    bool IsValid() const {
+      return mValid;
+    }
+    bool HasChannel(Channel aChannel) const
+    {
+      return mChannelMap & (1 << aChannel);
+    }
+  private:
+    void UpdateChannelMap();
+    const Channel* SMPTEDefault(uint32_t aChannels) const;
+    AutoTArray<Channel, MAX_AUDIO_CHANNELS> mChannels;
+    uint32_t mChannelMap;
+    bool mValid;
+  };
+
+  enum SampleFormat {
+    FORMAT_NONE = 0,
+    FORMAT_U8,
+    FORMAT_S16,
+    FORMAT_S24LSB,
+    FORMAT_S24,
+    FORMAT_S32,
+    FORMAT_FLT,
+#if defined(MOZ_SAMPLE_TYPE_FLOAT32)
+    FORMAT_DEFAULT = FORMAT_FLT
+#elif defined(MOZ_SAMPLE_TYPE_S16)
+    FORMAT_DEFAULT = FORMAT_S16
+#else
+#error "Not supported audio type"
+#endif
+  };
+
+  AudioConfig(const ChannelLayout& aChannelLayout, uint32_t aRate,
+              AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
+              bool aInterleaved = true);
+  // Will create a channel configuration from default SMPTE ordering.
+  AudioConfig(uint32_t aChannels, uint32_t aRate,
+              AudioConfig::SampleFormat aFormat = FORMAT_DEFAULT,
+              bool aInterleaved = true);
+
+  const ChannelLayout& Layout() const
+  {
+    return mChannelLayout;
+  }
+  uint32_t Channels() const
+  {
+    if (!mChannelLayout.IsValid()) {
+      return mChannels;
+    }
+    return mChannelLayout.Count();
+  }
+  uint32_t Rate() const
+  {
+    return mRate;
+  }
+  SampleFormat Format() const
+  {
+    return mFormat;
+  }
+  bool Interleaved() const
+  {
+    return mInterleaved;
+  }
+
+  static const char* FormatToString(SampleFormat aFormat);
+  static uint32_t SampleSize(SampleFormat aFormat);
+  static uint32_t FormatToBits(SampleFormat aFormat);
+
+private:
+  // Channels configuration.
+  ChannelLayout mChannelLayout;
+
+  // Channel count.
+  uint32_t mChannels;
+
+  // Sample rate.
+  uint32_t mRate;
+
+  // Sample format.
+  SampleFormat mFormat;
+
+  bool mInterleaved;
+};
+
 } // namespace mozilla
 
 #endif // MediaInfo_h
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -215,16 +215,17 @@ UNIFIED_SOURCES += [
     'MediaData.cpp',
     'MediaDecoder.cpp',
     'MediaDecoderReader.cpp',
     'MediaDecoderReaderWrapper.cpp',
     'MediaDecoderStateMachine.cpp',
     'MediaDeviceInfo.cpp',
     'MediaDevices.cpp',
     'MediaFormatReader.cpp',
+    'MediaInfo.cpp',
     'MediaManager.cpp',
     'MediaRecorder.cpp',
     'MediaResource.cpp',
     'MediaShutdownManager.cpp',
     'MediaStreamError.cpp',
     'MediaStreamGraph.cpp',
     'MediaStreamTrack.cpp',
     'MediaTimer.cpp',