gecko-dev/dom/media/AudioConfig.cpp

344 строки
10 KiB
C++

/* -*- 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 "AudioConfig.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() {
mValid = mChannels.Length() <= MAX_CHANNELS;
mChannelMap = UNKNOWN_MAP;
if (mValid) {
mChannelMap = Map();
mValid = mChannelMap > 0;
}
}
auto AudioConfig::ChannelLayout::Map() const -> ChannelMap {
if (mChannelMap != UNKNOWN_MAP) {
return mChannelMap;
}
if (mChannels.Length() > MAX_CHANNELS) {
return UNKNOWN_MAP;
}
ChannelMap map = UNKNOWN_MAP;
for (size_t i = 0; i < mChannels.Length(); i++) {
if (uint32_t(mChannels[i]) > sizeof(ChannelMap) * 8) {
return UNKNOWN_MAP;
}
ChannelMap mask = 1 << mChannels[i];
if (mChannels[i] == CHANNEL_INVALID || (mChannelMap & mask)) {
// Invalid configuration.
return UNKNOWN_MAP;
}
map |= mask;
}
return map;
}
const AudioConfig::Channel*
AudioConfig::ChannelLayout::DefaultLayoutForChannels(uint32_t aChannels) const {
switch (aChannels) {
case 1: // MONO
{
static const Channel config[] = {CHANNEL_FRONT_CENTER};
return config;
}
case 2: // STEREO
{
static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT};
return config;
}
case 3: // 3F
{
static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER};
return config;
}
case 4: // QUAD
{
static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
return config;
}
case 5: // 3F2
{
static const Channel config[] = {CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_SIDE_LEFT,
CHANNEL_SIDE_RIGHT};
return config;
}
case 6: // 3F2-LFE
{
static const Channel config[] = {
CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
CHANNEL_LFE, CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
return config;
}
case 7: // 3F3R-LFE
{
static const Channel config[] = {
CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
CHANNEL_LFE, CHANNEL_BACK_CENTER, CHANNEL_SIDE_LEFT,
CHANNEL_SIDE_RIGHT};
return config;
}
case 8: // 3F4-LFE
{
static const Channel config[] = {
CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_FRONT_CENTER,
CHANNEL_LFE, CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT,
CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
return config;
}
default:
return nullptr;
}
}
/* static */ AudioConfig::ChannelLayout
AudioConfig::ChannelLayout::SMPTEDefault(const ChannelLayout& aChannelLayout) {
if (!aChannelLayout.IsValid()) {
return aChannelLayout;
}
return SMPTEDefault(aChannelLayout.Map());
}
/* static */
ChannelLayout AudioConfig::ChannelLayout::SMPTEDefault(ChannelMap aMap) {
// First handle the most common cases.
switch (aMap) {
case LMONO_MAP:
return ChannelLayout{CHANNEL_FRONT_CENTER};
case LSTEREO_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT};
case L3F_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER};
case L3F_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_LFE};
case L2F1_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_BACK_CENTER};
case L2F1_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_LFE,
CHANNEL_BACK_CENTER};
case L3F1_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_BACK_CENTER};
case L3F1_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_LFE,
CHANNEL_BACK_CENTER};
case L2F2_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
case L2F2_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_LFE,
CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
case LQUAD_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
case LQUAD_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT, CHANNEL_LFE,
CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
case L3F2_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_SIDE_LEFT,
CHANNEL_SIDE_RIGHT};
case L3F2_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_LFE,
CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
case L3F2_BACK_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_BACK_LEFT,
CHANNEL_BACK_RIGHT};
case L3F2_BACK_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_LFE,
CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT};
case L3F3R_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_LFE,
CHANNEL_BACK_CENTER, CHANNEL_SIDE_LEFT,
CHANNEL_SIDE_RIGHT};
case L3F4_LFE_MAP:
return ChannelLayout{CHANNEL_FRONT_LEFT, CHANNEL_FRONT_RIGHT,
CHANNEL_FRONT_CENTER, CHANNEL_LFE,
CHANNEL_BACK_LEFT, CHANNEL_BACK_RIGHT,
CHANNEL_SIDE_LEFT, CHANNEL_SIDE_RIGHT};
default:
break;
}
static_assert(MAX_CHANNELS <= sizeof(ChannelMap) * 8,
"Must be able to fit channels on bit mask");
AutoTArray<Channel, MAX_CHANNELS> layout;
uint32_t channels = 0;
uint32_t i = 0;
while (aMap) {
if (aMap & 1) {
channels++;
if (channels > MAX_CHANNELS) {
return ChannelLayout();
}
layout.AppendElement(static_cast<Channel>(i));
}
aMap >>= 1;
i++;
}
return ChannelLayout(channels, layout.Elements());
}
bool AudioConfig::ChannelLayout::MappingTable(const ChannelLayout& aOther,
nsTArray<uint8_t>* aMap) const {
if (!IsValid() || !aOther.IsValid() || Map() != aOther.Map()) {
if (aMap) {
aMap->SetLength(0);
}
return false;
}
if (!aMap) {
return true;
}
aMap->SetLength(Count());
for (uint32_t i = 0; i < Count(); i++) {
for (uint32_t j = 0; j < Count(); j++) {
if (aOther[j] == mChannels[i]) {
(*aMap)[j] = i;
break;
}
}
}
return true;
}
/**
* 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(const ChannelLayout& aChannelLayout,
uint32_t aChannels, uint32_t aRate,
AudioConfig::SampleFormat aFormat, bool aInterleaved)
: mChannelLayout(aChannelLayout),
mChannels(aChannels),
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