blob: dbbe9e81a5e3a3f2d53af6b37f6b811d2894fad1 [file] [log] [blame] [edit]
/*
* Copyright 2024, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioCapabilities"
#include <android-base/strings.h>
#include <android-base/properties.h>
#include <media/AudioCapabilities.h>
#include <media/CodecCapabilities.h>
#include <media/stagefright/MediaCodecConstants.h>
namespace android {
const Range<int32_t>& AudioCapabilities::getBitrateRange() const {
return mBitrateRange;
}
const std::vector<int32_t>& AudioCapabilities::getSupportedSampleRates() const {
return mSampleRates;
}
const std::vector<Range<int32_t>>&
AudioCapabilities::getSupportedSampleRateRanges() const {
return mSampleRateRanges;
}
int32_t AudioCapabilities::getMaxInputChannelCount() const {
int32_t overallMax = 0;
for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) {
int32_t lmax = mInputChannelRanges[i].upper();
if (lmax > overallMax) {
overallMax = lmax;
}
}
return overallMax;
}
int32_t AudioCapabilities::getMinInputChannelCount() const {
int32_t overallMin = MAX_INPUT_CHANNEL_COUNT;
for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) {
int32_t lmin = mInputChannelRanges[i].lower();
if (lmin < overallMin) {
overallMin = lmin;
}
}
return overallMin;
}
const std::vector<Range<int32_t>>&
AudioCapabilities::getInputChannelCountRanges() const {
return mInputChannelRanges;
}
// static
std::shared_ptr<AudioCapabilities> AudioCapabilities::Create(std::string mediaType,
std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
std::shared_ptr<AudioCapabilities> caps(new AudioCapabilities());
caps->init(mediaType, profLevs, format);
return caps;
}
void AudioCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
const sp<AMessage> &format) {
mMediaType = mediaType;
mProfileLevels = profLevs;
mError = 0;
initWithPlatformLimits();
applyLevelLimits();
parseFromInfo(format);
}
void AudioCapabilities::initWithPlatformLimits() {
mBitrateRange = Range<int32_t>(0, INT32_MAX);
mInputChannelRanges.push_back(Range<int32_t>(1, MAX_INPUT_CHANNEL_COUNT));
const int32_t minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350);
const int32_t maxSampleRate = base::GetIntProperty("ro.mediacodec.max_sample_rate", 192000);
mSampleRateRanges.push_back(Range<int32_t>(minSampleRate, maxSampleRate));
}
bool AudioCapabilities::supports(std::optional<int32_t> sampleRate,
std::optional<int32_t> inputChannels) {
// channels and sample rates are checked orthogonally
if (inputChannels
&& !std::any_of(mInputChannelRanges.begin(), mInputChannelRanges.end(),
[inputChannels](const Range<int32_t> &a) {
return a.contains(inputChannels.value()); })) {
return false;
}
if (sampleRate
&& !std::any_of(mSampleRateRanges.begin(), mSampleRateRanges.end(),
[sampleRate](const Range<int32_t> &a) { return a.contains(sampleRate.value()); })) {
return false;
}
return true;
}
bool AudioCapabilities::isSampleRateSupported(int32_t sampleRate) {
return supports(std::make_optional<int32_t>(sampleRate), std::nullopt);
}
void AudioCapabilities::limitSampleRates(std::vector<int32_t> rates) {
std::vector<Range<int32_t>> sampleRateRanges;
std::sort(rates.begin(), rates.end());
for (int32_t rate : rates) {
if (supports(std::make_optional<int32_t>(rate), std::nullopt /* channels */)) {
sampleRateRanges.push_back(Range<int32_t>(rate, rate));
}
}
mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, sampleRateRanges);
createDiscreteSampleRates();
}
void AudioCapabilities::createDiscreteSampleRates() {
mSampleRates.clear();
for (int i = 0; i < mSampleRateRanges.size(); i++) {
mSampleRates.push_back(mSampleRateRanges[i].lower());
}
}
void AudioCapabilities::limitSampleRates(std::vector<Range<int32_t>> rateRanges) {
sortDistinctRanges(&rateRanges);
mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges);
// check if all values are discrete
for (Range<int32_t> range: mSampleRateRanges) {
if (range.lower() != range.upper()) {
mSampleRates.clear();
return;
}
}
createDiscreteSampleRates();
}
void AudioCapabilities::applyLevelLimits() {
std::vector<int32_t> sampleRates;
std::optional<Range<int32_t>> sampleRateRange;
std::optional<Range<int32_t>> bitRates;
int32_t maxChannels = MAX_INPUT_CHANNEL_COUNT;
// const char *mediaType = mMediaType.c_str();
if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MPEG)) {
sampleRates = {
8000, 11025, 12000,
16000, 22050, 24000,
32000, 44100, 48000 };
bitRates = Range<int32_t>(8000, 320000);
maxChannels = 2;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)) {
sampleRates = { 8000 };
bitRates = Range<int32_t>(4750, 12200);
maxChannels = 1;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)) {
sampleRates = { 16000 };
bitRates = Range<int32_t>(6600, 23850);
maxChannels = 1;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
sampleRates = {
7350, 8000,
11025, 12000, 16000,
22050, 24000, 32000,
44100, 48000, 64000,
88200, 96000 };
bitRates = Range<int32_t>(8000, 510000);
maxChannels = 48;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_VORBIS)) {
bitRates = Range<int32_t>(32000, 500000);
sampleRateRange = Range<int32_t>(8000, 192000);
maxChannels = 255;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_OPUS)) {
bitRates = Range<int32_t>(6000, 510000);
sampleRates = { 8000, 12000, 16000, 24000, 48000 };
maxChannels = 255;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_RAW)) {
sampleRateRange = Range<int32_t>(1, 192000);
bitRates = Range<int32_t>(1, 10000000);
maxChannels = MAX_NUM_CHANNELS;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
sampleRateRange = Range<int32_t>(1, 655350);
// lossless codec, so bitrate is ignored
maxChannels = 255;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
|| base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)) {
sampleRates = { 8000 };
bitRates = Range<int32_t>(64000, 64000);
// platform allows multiple channels for this format
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
sampleRates = { 8000 };
bitRates = Range<int32_t>(13000, 13000);
maxChannels = 1;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC3)) {
maxChannels = 6;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_EAC3)) {
maxChannels = 16;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_EAC3_JOC)) {
sampleRates = { 48000 };
bitRates = Range<int32_t>(32000, 6144000);
maxChannels = 16;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC4)) {
sampleRates = { 44100, 48000, 96000, 192000 };
bitRates = Range<int32_t>(16000, 2688000);
maxChannels = 24;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)) {
sampleRates = { 44100, 48000 };
bitRates = Range<int32_t>(96000, 1524000);
maxChannels = 6;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_HD)) {
for (ProfileLevel profileLevel: mProfileLevels) {
switch (profileLevel.mProfile) {
case DTS_HDProfileLBR:
sampleRates = { 22050, 24000, 44100, 48000 };
bitRates = Range<int32_t>(32000, 768000);
break;
case DTS_HDProfileHRA:
case DTS_HDProfileMA:
sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
bitRates = Range<int32_t>(96000, 24500000);
break;
default:
ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile,
mMediaType.c_str());
mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
bitRates = Range<int32_t>(96000, 24500000);
}
}
maxChannels = 8;
} else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS_UHD)) {
for (ProfileLevel profileLevel: mProfileLevels) {
switch (profileLevel.mProfile) {
case DTS_UHDProfileP2:
sampleRates = { 48000 };
bitRates = Range<int32_t>(96000, 768000);
maxChannels = 10;
break;
case DTS_UHDProfileP1:
sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
bitRates = Range<int32_t>(96000, 24500000);
maxChannels = 32;
break;
default:
ALOGW("Unrecognized profile %d for %s", profileLevel.mProfile,
mMediaType.c_str());
mError |= ERROR_CAPABILITIES_UNRECOGNIZED;
sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 };
bitRates = Range<int32_t>(96000, 24500000);
maxChannels = 32;
}
}
} else {
ALOGW("Unsupported mediaType %s", mMediaType.c_str());
mError |= ERROR_CAPABILITIES_UNSUPPORTED;
}
// restrict ranges
if (!sampleRates.empty()) {
limitSampleRates(sampleRates);
} else if (sampleRateRange) {
std::vector<Range<int32_t>> rateRanges = { sampleRateRange.value() };
limitSampleRates(rateRanges);
}
Range<int32_t> channelRange = Range<int32_t>(1, maxChannels);
std::vector<Range<int32_t>> inputChannels = { channelRange };
applyLimits(inputChannels, bitRates);
}
void AudioCapabilities::applyLimits(
const std::vector<Range<int32_t>> &inputChannels,
const std::optional<Range<int32_t>> &bitRates) {
// clamp & make a local copy
std::vector<Range<int32_t>> inputChannelsCopy(inputChannels.size());
for (int i = 0; i < inputChannels.size(); i++) {
int32_t lower = inputChannels[i].clamp(1);
int32_t upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT);
inputChannelsCopy[i] = Range<int32_t>(lower, upper);
}
// sort, intersect with existing, & save channel list
sortDistinctRanges(&inputChannelsCopy);
mInputChannelRanges = intersectSortedDistinctRanges(inputChannelsCopy, mInputChannelRanges);
if (bitRates) {
mBitrateRange = mBitrateRange.intersect(bitRates.value());
}
}
void AudioCapabilities::parseFromInfo(const sp<AMessage> &format) {
int32_t maxInputChannels = MAX_INPUT_CHANNEL_COUNT;
std::vector<Range<int32_t>> channels = { Range<int32_t>(1, maxInputChannels) };
std::optional<Range<int32_t>> bitRates = POSITIVE_INT32;
AString rateAString;
if (format->findString("sample-rate-ranges", &rateAString)) {
std::vector<std::string> rateStrings = base::Split(std::string(rateAString.c_str()), ",");
std::vector<Range<int32_t>> rateRanges;
for (std::string rateString : rateStrings) {
std::optional<Range<int32_t>> rateRange = Range<int32_t>::Parse(rateString);
if (!rateRange) {
continue;
}
rateRanges.push_back(rateRange.value());
}
limitSampleRates(rateRanges);
}
// we will prefer channel-ranges over max-channel-count
AString valueStr;
if (format->findString("channel-ranges", &valueStr)) {
std::vector<std::string> channelStrings = base::Split(std::string(valueStr.c_str()), ",");
std::vector<Range<int32_t>> channelRanges;
for (std::string channelString : channelStrings) {
std::optional<Range<int32_t>> channelRange = Range<int32_t>::Parse(channelString);
if (!channelRange) {
continue;
}
channelRanges.push_back(channelRange.value());
}
channels = channelRanges;
} else if (format->findString("channel-range", &valueStr)) {
std::optional<Range<int32_t>> oneRange
= Range<int32_t>::Parse(std::string(valueStr.c_str()));
if (oneRange) {
channels = { oneRange.value() };
}
} else if (format->findString("max-channel-count", &valueStr)) {
maxInputChannels = std::atoi(valueStr.c_str());
if (maxInputChannels == 0) {
channels = { Range<int32_t>(0, 0) };
} else {
channels = { Range<int32_t>(1, maxInputChannels) };
}
} else if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) {
maxInputChannels = 0;
channels = { Range<int32_t>(0, 0) };
}
if (format->findString("bitrate-range", &valueStr)) {
std::optional<Range<int32_t>> parsedBitrate = Range<int32_t>::Parse(valueStr.c_str());
if (parsedBitrate) {
bitRates = bitRates.value().intersect(parsedBitrate.value());
}
}
applyLimits(channels, bitRates);
}
void AudioCapabilities::getDefaultFormat(sp<AMessage> &format) {
// report settings that have only a single choice
if (mBitrateRange.lower() == mBitrateRange.upper()) {
format->setInt32(KEY_BIT_RATE, mBitrateRange.lower());
}
if (getMaxInputChannelCount() == 1) {
// mono-only format
format->setInt32(KEY_CHANNEL_COUNT, 1);
}
if (!mSampleRates.empty() && mSampleRates.size() == 1) {
format->setInt32(KEY_SAMPLE_RATE, mSampleRates[0]);
}
}
bool AudioCapabilities::supportsFormat(const sp<AMessage> &format) {
int32_t sampleRateValue;
std::optional<int32_t> sampleRate = format->findInt32(KEY_SAMPLE_RATE, &sampleRateValue)
? std::make_optional<int32_t>(sampleRateValue) : std::nullopt;
int32_t channelsValue;
std::optional<int32_t> channels = format->findInt32(KEY_CHANNEL_COUNT, &channelsValue)
? std::make_optional<int32_t>(channelsValue) : std::nullopt;
if (!supports(sampleRate, channels)) {
return false;
}
if (!CodecCapabilities::SupportsBitrate(mBitrateRange, format)) {
return false;
}
// nothing to do for:
// KEY_CHANNEL_MASK: codecs don't get this
// KEY_IS_ADTS: required feature for all AAC decoders
return true;
}
} // namespace android