Bug 1431221 - P1. Add method to retrieve SMPTE equivalent layout from any channel layout. r=padenot draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Mon, 22 Jan 2018 15:10:09 +0100
changeset 771683 7991d8de60c1b9c73ffac12a4294a94727aa06aa
parent 771682 29aad00bd31e0077c8ff31954294745e2e5da3ab
child 771684 7641dd7313d1b547c55b1a5800c5d8a382b1f4b8
push id103752
push userbmo:jyavenard@mozilla.com
push dateFri, 23 Mar 2018 17:52:32 +0000
reviewerspadenot
bugs1431221
milestone61.0a1
Bug 1431221 - P1. Add method to retrieve SMPTE equivalent layout from any channel layout. r=padenot MozReview-Commit-ID: J8yT5OWIbAH
dom/media/MediaInfo.cpp
dom/media/MediaInfo.h
--- a/dom/media/MediaInfo.cpp
+++ b/dom/media/MediaInfo.cpp
@@ -48,28 +48,106 @@ typedef AudioConfig::ChannelLayout Chann
  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
 */
 
+ChannelLayout ChannelLayout::LMONO{ AudioConfig::CHANNEL_MONO };
+ChannelLayout ChannelLayout::LMONO_LFE{ AudioConfig::CHANNEL_MONO,
+                                        AudioConfig::CHANNEL_LFE };
+ChannelLayout ChannelLayout::LSTEREO{ AudioConfig::CHANNEL_LEFT,
+                                      AudioConfig::CHANNEL_RIGHT };
+ChannelLayout ChannelLayout::LSTEREO_LFE{ AudioConfig::CHANNEL_LEFT,
+                                          AudioConfig::CHANNEL_RIGHT,
+                                          AudioConfig::CHANNEL_LFE };
+ChannelLayout ChannelLayout::L3F{ AudioConfig::CHANNEL_LEFT,
+                                  AudioConfig::CHANNEL_RIGHT,
+                                  AudioConfig::CHANNEL_CENTER };
+ChannelLayout ChannelLayout::L3F_LFE{ AudioConfig::CHANNEL_LEFT,
+                                      AudioConfig::CHANNEL_RIGHT,
+                                      AudioConfig::CHANNEL_CENTER,
+                                      AudioConfig::CHANNEL_LFE };
+ChannelLayout ChannelLayout::L2F1{ AudioConfig::CHANNEL_LEFT,
+                                   AudioConfig::CHANNEL_RIGHT,
+                                   AudioConfig::CHANNEL_RCENTER };
+ChannelLayout ChannelLayout::L2F1_LFE{ AudioConfig::CHANNEL_LEFT,
+                                       AudioConfig::CHANNEL_RIGHT,
+                                       AudioConfig::CHANNEL_LFE,
+                                       AudioConfig::CHANNEL_RCENTER };
+ChannelLayout ChannelLayout::L3F1{ AudioConfig::CHANNEL_LEFT,
+                                   AudioConfig::CHANNEL_RIGHT,
+                                   AudioConfig::CHANNEL_CENTER,
+                                   AudioConfig::CHANNEL_RCENTER };
+ChannelLayout ChannelLayout::L3F1_LFE{ AudioConfig::CHANNEL_LEFT,
+                                       AudioConfig::CHANNEL_RIGHT,
+                                       AudioConfig::CHANNEL_CENTER,
+                                       AudioConfig::CHANNEL_LFE,
+                                       AudioConfig::CHANNEL_RCENTER };
+ChannelLayout ChannelLayout::L2F2{ AudioConfig::CHANNEL_LEFT,
+                                   AudioConfig::CHANNEL_RIGHT,
+                                   AudioConfig::CHANNEL_LS,
+                                   AudioConfig::CHANNEL_RS };
+ChannelLayout ChannelLayout::L2F2_LFE{ AudioConfig::CHANNEL_LEFT,
+                                       AudioConfig::CHANNEL_RIGHT,
+                                       AudioConfig::CHANNEL_LFE,
+                                       AudioConfig::CHANNEL_LS,
+                                       AudioConfig::CHANNEL_RS };
+ChannelLayout ChannelLayout::L3F2{ AudioConfig::CHANNEL_LEFT,
+                                   AudioConfig::CHANNEL_RIGHT,
+                                   AudioConfig::CHANNEL_CENTER,
+                                   AudioConfig::CHANNEL_LS,
+                                   AudioConfig::CHANNEL_RS };
+ChannelLayout ChannelLayout::L3F2_LFE{
+  AudioConfig::CHANNEL_LEFT,   AudioConfig::CHANNEL_RIGHT,
+  AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_LFE,
+  AudioConfig::CHANNEL_LS,     AudioConfig::CHANNEL_RS
+};
+ChannelLayout ChannelLayout::L3F3R_LFE{
+  AudioConfig::CHANNEL_LEFT,    AudioConfig::CHANNEL_RIGHT,
+  AudioConfig::CHANNEL_CENTER,  AudioConfig::CHANNEL_LFE,
+  AudioConfig::CHANNEL_RCENTER, AudioConfig::CHANNEL_LS,
+  AudioConfig::CHANNEL_RS
+};
+ChannelLayout ChannelLayout::L3F4_LFE{
+  AudioConfig::CHANNEL_LEFT,   AudioConfig::CHANNEL_RIGHT,
+  AudioConfig::CHANNEL_CENTER, AudioConfig::CHANNEL_LFE,
+  AudioConfig::CHANNEL_RLS,    AudioConfig::CHANNEL_RRS,
+  AudioConfig::CHANNEL_LS,     AudioConfig::CHANNEL_RS
+};
+
 void
 AudioConfig::ChannelLayout::UpdateChannelMap()
 {
+  mValid = mChannels.Length() <= MAX_AUDIO_CHANNELS;
   mChannelMap = 0;
-  mValid = mChannels.Length() <= MAX_AUDIO_CHANNELS;
+  if (mValid) {
+    mChannelMap = Map();
+    mValid = mChannelMap > 0;
+  }
+}
+
+uint32_t
+AudioConfig::ChannelLayout::Map() const
+{
+  if (mChannelMap) {
+    return mChannelMap;
+  }
+  uint32_t map = 0;
   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;
+      // Invalid configuration.
+      return 0;
     }
-    mChannelMap |= mask;
+    map |= mask;
   }
+  return map;
 }
 
 /* static */ const AudioConfig::Channel*
 AudioConfig::ChannelLayout::SMPTEDefault(uint32_t aChannels) const
 {
   switch (aChannels) {
     case 1: // MONO
     {
@@ -111,16 +189,64 @@ AudioConfig::ChannelLayout::SMPTEDefault
       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;
   }
 }
 
+/* static */ const AudioConfig::ChannelLayout&
+AudioConfig::ChannelLayout::SMPTEDefault(
+  const ChannelLayout& aChannelLayout)
+{
+  MOZ_ASSERT(LMONO_MAP == LMONO.Map());
+  MOZ_ASSERT(LMONO_LFE_MAP == LMONO_LFE.Map());
+  MOZ_ASSERT(LSTEREO_MAP == LSTEREO.Map());
+  MOZ_ASSERT(LSTEREO_LFE_MAP == LSTEREO_LFE.Map());
+  MOZ_ASSERT(L3F_MAP == L3F.Map());
+  MOZ_ASSERT(L3F_LFE_MAP == L3F_LFE.Map());
+  MOZ_ASSERT(L2F1_MAP == L2F1.Map());
+  MOZ_ASSERT(L2F1_LFE_MAP == L2F1_LFE.Map());
+  MOZ_ASSERT(L3F1_MAP == L3F1.Map());
+  MOZ_ASSERT(L3F1_LFE_MAP == L3F1_LFE.Map());
+  MOZ_ASSERT(L2F2_MAP == L2F2.Map());
+  MOZ_ASSERT(L2F2_LFE_MAP == L2F2_LFE.Map());
+  MOZ_ASSERT(L3F2_MAP == L3F2.Map());
+  MOZ_ASSERT(L3F2_LFE_MAP == L3F2_LFE.Map());
+  MOZ_ASSERT(L3F3R_LFE_MAP == L3F3R_LFE.Map());
+  MOZ_ASSERT(L3F4_LFE_MAP == L3F4_LFE.Map());
+
+  if (!aChannelLayout.IsValid()) {
+    return aChannelLayout;
+  }
+  const uint32_t map = aChannelLayout.Map();
+  switch (map) {
+    case LMONO_MAP: return LMONO;
+    case LMONO_LFE_MAP: return LMONO_LFE;
+    case LSTEREO_MAP: return LSTEREO;
+    case LSTEREO_LFE_MAP : return LSTEREO_LFE;
+    case L3F_MAP: return L3F;
+    case L3F_LFE_MAP: return L3F_LFE;
+    case L2F1_MAP: return L2F1;
+    case L2F1_LFE_MAP: return L2F1_LFE;
+    case L3F1_MAP: return L3F1;
+    case L3F1_LFE_MAP: return L3F1_LFE;
+    case L2F2_MAP: return L2F2;
+    case L2F2_LFE_MAP: return L2F2_LFE;
+    case L3F2_MAP: return L3F2;
+    case L3F2_LFE_MAP: return L3F2_LFE;
+    case L3F3R_LFE_MAP: return L3F3R_LFE;
+    case L3F4_LFE_MAP: return L3F4_LFE;
+    default:
+      // unknown return identical.
+      return aChannelLayout;
+  }
+}
+
 bool
 AudioConfig::ChannelLayout::MappingTable(const ChannelLayout& aOther,
                                          uint8_t* aMap) const
 {
   if (!IsValid() || !aOther.IsValid() ||
       Map() != aOther.Map()) {
     return false;
   }
--- a/dom/media/MediaInfo.h
+++ b/dom/media/MediaInfo.h
@@ -611,84 +611,153 @@ private:
 
 public:
   const nsCString& mMimeType;
 };
 
 class AudioConfig
 {
 public:
+  // Channel definition is conveniently defined to be in the same order as
+  // WAVEFORMAT && SMPTE, even though this is unused for now.
   enum Channel
   {
     CHANNEL_INVALID = -1,
     CHANNEL_MONO = 0,
     CHANNEL_LEFT,
     CHANNEL_RIGHT,
     CHANNEL_CENTER,
+    CHANNEL_LFE,
+    CHANNEL_RCENTER,
     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)
       : ChannelLayout()
     {
-      if (!aConfig) {
+      if (aChannels == 0 || !aConfig) {
         mValid = false;
         return;
       }
       mChannels.AppendElements(aConfig, aChannels);
       UpdateChannelMap();
     }
+    ChannelLayout(std::initializer_list<Channel> aChannelList)
+      : ChannelLayout(aChannelList.size(), aChannelList.begin())
+    {
+    }
     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;
-    }
+    uint32_t Map() const;
+
     // Calculate the mapping table from the current layout to aOther such that
     // one can easily go from one layout to the other by doing:
     // out[channel] = in[map[channel]].
     // Returns true if the reordering is possible or false otherwise.
     // If true, then aMap, if set, will be updated to contain the mapping table
     // allowing conversion from the current layout to aOther.
     // If aMap is nullptr, then MappingTable can be used to simply determine if
     // the current layout can be easily reordered to aOther.
     // aMap must be an array of size MAX_AUDIO_CHANNELS.
     bool MappingTable(const ChannelLayout& aOther, uint8_t* aMap = nullptr) const;
     bool IsValid() const { return mValid; }
     bool HasChannel(Channel aChannel) const
     {
       return mChannelMap & (1 << aChannel);
     }
+
+    static const ChannelLayout& SMPTEDefault(
+      const ChannelLayout& aChannelLayout);
+
+    // Common channel layout definitions.
+    static ChannelLayout LMONO;
+    static constexpr uint32_t LMONO_MAP = 1 << CHANNEL_MONO;
+    static ChannelLayout LMONO_LFE;
+    static constexpr uint32_t LMONO_LFE_MAP =
+      1 << CHANNEL_MONO | 1 << CHANNEL_LFE;
+    static ChannelLayout LSTEREO;
+    static constexpr uint32_t LSTEREO_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT;
+    static ChannelLayout LSTEREO_LFE;
+    static constexpr uint32_t LSTEREO_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_LFE;
+    static ChannelLayout L3F;
+    static constexpr uint32_t L3F_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER;
+    static ChannelLayout L3F_LFE;
+    static constexpr uint32_t L3F_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_LFE;
+    static ChannelLayout L2F1;
+    static constexpr uint32_t L2F1_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_RCENTER;
+    static ChannelLayout L2F1_LFE;
+    static constexpr uint32_t L2F1_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_LFE |
+      1 << CHANNEL_RCENTER;
+    static ChannelLayout L3F1;
+    static constexpr uint32_t L3F1_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_RCENTER;
+    static ChannelLayout L3F1_LFE;
+    static constexpr uint32_t L3F1_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_LFE | 1 << CHANNEL_RCENTER;
+    static ChannelLayout L2F2;
+    static constexpr uint32_t L2F2_MAP = 1 << CHANNEL_LEFT |
+                                         1 << CHANNEL_RIGHT | 1 << CHANNEL_LS |
+                                         1 << CHANNEL_RS;
+    static ChannelLayout L2F2_LFE;
+    static constexpr uint32_t L2F2_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_LFE |
+      1 << CHANNEL_LS | 1 << CHANNEL_RS;
+    static ChannelLayout L3F2;
+    static constexpr uint32_t L3F2_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_LS | 1 << CHANNEL_RS;
+    static ChannelLayout L3F2_LFE;
+    static constexpr uint32_t L3F2_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_LFE | 1 << CHANNEL_LS | 1 << CHANNEL_RS;
+    static ChannelLayout L3F3R_LFE;
+    static constexpr uint32_t L3F3R_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_LFE | 1 << CHANNEL_RCENTER | 1 << CHANNEL_LS |
+      1 << CHANNEL_RS;
+    static ChannelLayout L3F4_LFE;
+    static constexpr uint32_t L3F4_LFE_MAP =
+      1 << CHANNEL_LEFT | 1 << CHANNEL_RIGHT | 1 << CHANNEL_CENTER |
+      1 << CHANNEL_LFE | 1 << CHANNEL_RLS | 1 << CHANNEL_RRS | 1 << CHANNEL_LS |
+      1 << CHANNEL_RS;
+
   private:
     void UpdateChannelMap();
     const Channel* SMPTEDefault(uint32_t aChannels) const;
     AutoTArray<Channel, MAX_AUDIO_CHANNELS> mChannels;
     uint32_t mChannelMap;
     bool mValid;
   };