Bug 1431221 - P1. Add method to retrieve SMPTE equivalent layout from any channel layout. r=padenot
MozReview-Commit-ID: J8yT5OWIbAH
--- 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;
};