Loading media/libmedia/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -258,6 +258,7 @@ cc_library_shared { name: "libmedia_codeclist_capabilities", srcs: [ "AudioCapabilities.cpp", "CodecCapabilities.cpp", "CodecCapabilitiesUtils.cpp", ], Loading media/libmedia/AudioCapabilities.cpp 0 → 100644 +393 −0 Original line number Diff line number Diff line /* * 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<int>& AudioCapabilities::getBitrateRange() const { return mBitrateRange; } const std::vector<int>& AudioCapabilities::getSupportedSampleRates() const { return mSampleRates; } const std::vector<Range<int>>& AudioCapabilities::getSupportedSampleRateRanges() const { return mSampleRateRanges; } int AudioCapabilities::getMaxInputChannelCount() const { int overallMax = 0; for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) { int lmax = mInputChannelRanges[i].upper(); if (lmax > overallMax) { overallMax = lmax; } } return overallMax; } int AudioCapabilities::getMinInputChannelCount() const { int overallMin = MAX_INPUT_CHANNEL_COUNT; for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) { int lmin = mInputChannelRanges[i].lower(); if (lmin < overallMin) { overallMin = lmin; } } return overallMin; } const std::vector<Range<int>>& 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; initWithPlatformLimits(); applyLevelLimits(); parseFromInfo(format); } void AudioCapabilities::initWithPlatformLimits() { mBitrateRange = Range<int>(0, INT_MAX); mInputChannelRanges.push_back(Range<int>(1, MAX_INPUT_CHANNEL_COUNT)); const int minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350); const int maxSampleRate = base::GetIntProperty("ro.mediacodec.max_sample_rate", 192000); mSampleRateRanges.push_back(Range<int>(minSampleRate, maxSampleRate)); } bool AudioCapabilities::supports(int sampleRate, int inputChannels) { // channels and sample rates are checked orthogonally if (inputChannels != 0 && !std::any_of(mInputChannelRanges.begin(), mInputChannelRanges.end(), [inputChannels](const Range<int> &a) { return a.contains(inputChannels); })) { return false; } if (sampleRate != 0 && !std::any_of(mSampleRateRanges.begin(), mSampleRateRanges.end(), [sampleRate](const Range<int> &a) { return a.contains(sampleRate); })) { return false; } return true; } bool AudioCapabilities::isSampleRateSupported(int sampleRate) { return supports(sampleRate, 0); } void AudioCapabilities::limitSampleRates(std::vector<int> rates) { std::vector<Range<int>> sampleRateRanges; std::sort(rates.begin(), rates.end()); for (int rate : rates) { if (supports(rate, 0 /* channels */)) { sampleRateRanges.push_back(Range<int>(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<int>> rateRanges) { sortDistinctRanges(&rateRanges); mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); // check if all values are discrete for (Range<int> range: mSampleRateRanges) { if (range.lower() != range.upper()) { mSampleRates.clear(); return; } } createDiscreteSampleRates(); } void AudioCapabilities::applyLevelLimits() { std::vector<int> sampleRates; std::optional<Range<int>> sampleRateRange; std::optional<Range<int>> bitRates; int 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<int>(8000, 320000); maxChannels = 2; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)) { sampleRates = { 8000 }; bitRates = Range<int>(4750, 12200); maxChannels = 1; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)) { sampleRates = { 16000 }; bitRates = Range<int>(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<int>(8000, 510000); maxChannels = 48; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_VORBIS)) { bitRates = Range<int>(32000, 500000); sampleRateRange = Range<int>(8000, 192000); maxChannels = 255; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_OPUS)) { bitRates = Range<int>(6000, 510000); sampleRates = { 8000, 12000, 16000, 24000, 48000 }; maxChannels = 255; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_RAW)) { sampleRateRange = Range<int>(1, 192000); bitRates = Range<int>(1, 10000000); maxChannels = MAX_NUM_CHANNELS; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) { sampleRateRange = Range<int>(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<int>(64000, 64000); // platform allows multiple channels for this format } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) { sampleRates = { 8000 }; bitRates = Range<int>(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<int>(32000, 6144000); maxChannels = 16; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC4)) { sampleRates = { 44100, 48000, 96000, 192000 }; bitRates = Range<int>(16000, 2688000); maxChannels = 24; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)) { sampleRates = { 44100, 48000 }; bitRates = Range<int>(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<int>(32000, 768000); break; case DTS_HDProfileHRA: case DTS_HDProfileMA: sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 }; bitRates = Range<int>(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<int>(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<int>(96000, 768000); maxChannels = 10; break; case DTS_UHDProfileP1: sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 }; bitRates = Range<int>(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<int>(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<int>> rateRanges = { sampleRateRange.value() }; limitSampleRates(rateRanges); } Range<int> channelRange = Range<int>(1, maxChannels); std::vector<Range<int>> inputChannels = { channelRange }; applyLimits(inputChannels, bitRates); } void AudioCapabilities::applyLimits( const std::vector<Range<int>> &inputChannels, const std::optional<Range<int>> &bitRates) { // clamp & make a local copy std::vector<Range<int>> inputChannelsCopy(inputChannels.size()); for (int i = 0; i < inputChannels.size(); i++) { int lower = inputChannels[i].clamp(1); int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT); inputChannelsCopy[i] = Range<int>(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) { int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; std::vector<Range<int>> channels = { Range<int>(1, maxInputChannels) }; std::optional<Range<int>> bitRates = POSITIVE_INTEGERS; AString rateAString; if (format->findString("sample-rate-ranges", &rateAString)) { std::vector<std::string> rateStrings = base::Split(std::string(rateAString.c_str()), ","); std::vector<Range<int>> rateRanges; for (std::string rateString : rateStrings) { std::optional<Range<int>> rateRange = ParseIntRange(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<int>> channelRanges; for (std::string channelString : channelStrings) { std::optional<Range<int>> channelRange = ParseIntRange(channelString); if (!channelRange) { continue; } channelRanges.push_back(channelRange.value()); } channels = channelRanges; } else if (format->findString("channel-range", &valueStr)) { std::optional<Range<int>> oneRange = ParseIntRange(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<int>(0, 0) }; } else { channels = { Range<int>(1, maxInputChannels) }; } } else if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) { maxInputChannels = 0; channels = { Range<int>(0, 0) }; } if (format->findString("bitrate-range", &valueStr)) { std::optional<Range<int>> parsedBitrate = ParseIntRange(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 sampleRate; format->findInt32(KEY_SAMPLE_RATE, &sampleRate); int32_t channels; format->findInt32(KEY_CHANNEL_COUNT, &channels); 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 No newline at end of file media/libmedia/CodecCapabilities.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -25,4 +25,33 @@ namespace android { bool CodecCapabilities::SupportsBitrate(Range<int> bitrateRange, const sp<AMessage> &format) { // consider max bitrate over average bitrate for support int32_t maxBitrate = 0; format->findInt32(KEY_MAX_BIT_RATE, &maxBitrate); int32_t bitrate = 0; format->findInt32(KEY_BIT_RATE, &bitrate); if (bitrate == 0) { bitrate = maxBitrate; } else if (maxBitrate != 0) { bitrate = std::max(bitrate, maxBitrate); } if (bitrate > 0) { return bitrateRange.contains(bitrate); } return true; } const std::string& CodecCapabilities::getMediaType() { return mMediaType; } const std::vector<ProfileLevel>& CodecCapabilities::getProfileLevels() { return mProfileLevels; } } // namespace android No newline at end of file media/libmedia/CodecCapabilitiesUtils.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <algorithm> #include <cmath> #include <regex> #include <string> #include <vector> Loading @@ -29,4 +30,24 @@ namespace android { std::optional<Range<int>> ParseIntRange(const std::string &str) { if (str.empty()) { ALOGW("could not parse empty integer range"); return std::nullopt; } int lower, upper; std::regex regex("([0-9]+)-([0-9]+)"); std::smatch match; if (std::regex_match(str, match, regex)) { lower = std::atoi(match[1].str().c_str()); upper = std::atoi(match[2].str().c_str()); } else if (std::atoi(str.c_str()) != 0) { lower = upper = std::atoi(str.c_str()); } else { ALOGW("could not parse integer range: %s", str.c_str()); return std::nullopt; } return std::make_optional<Range<int>>(lower, upper); } } // namespace android No newline at end of file media/libmedia/include/media/AudioCapabilities.h 0 → 100644 +138 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef AUDIO_CAPABILITIES_H_ #define AUDIO_CAPABILITIES_H_ #include <media/CodecCapabilitiesUtils.h> #include <media/stagefright/foundation/AMessage.h> #include <system/audio.h> #include <utils/StrongPointer.h> namespace android { struct AudioCapabilities { /** * Create AudioCapabilities. */ static std::shared_ptr<AudioCapabilities> Create(std::string mediaType, std::vector<ProfileLevel> profLevs, const sp<AMessage> &format); /** * Returns the range of supported bitrates in bits/second. */ const Range<int>& getBitrateRange() const; /** * Returns the array of supported sample rates if the codec * supports only discrete values. Otherwise, it returns an empty array. * The array is sorted in ascending order. */ const std::vector<int>& getSupportedSampleRates() const; /** * Returns the array of supported sample rate ranges. The * array is sorted in ascending order, and the ranges are * distinct. */ const std::vector<Range<int>>& getSupportedSampleRateRanges() const; /** * Returns the maximum number of input channels supported. * The returned value should be between 1 and 255. * * Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support * for any number of input channels between 1 and this maximum value. * * As of {@link android.os.Build.VERSION_CODES#S}, * the implied lower limit of 1 channel is no longer valid. * As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is * superseded by {@link #getInputChannelCountRanges}, * which returns an array of ranges of channels. * The {@link #getMaxInputChannelCount} method will return the highest value * in the ranges returned by {@link #getInputChannelCountRanges} */ int getMaxInputChannelCount() const; /** * Returns the minimum number of input channels supported. * This is often 1, but does vary for certain mime types. * * This returns the lowest channel count in the ranges returned by * {@link #getInputChannelCountRanges}. */ int getMinInputChannelCount() const; /** * Returns an array of ranges representing the number of input channels supported. * The codec supports any number of input channels within this range. * * This supersedes the {@link #getMaxInputChannelCount} method. * * For many codecs, this will be a single range [1..N], for some N. * * The returned array cannot be empty. */ const std::vector<Range<int>>& getInputChannelCountRanges() const; /** * Query whether the sample rate is supported by the codec. */ bool isSampleRateSupported(int sampleRate); /* For internal use only. Not exposed as a public API */ void getDefaultFormat(sp<AMessage> &format); /* For internal use only. Not exposed as a public API */ bool supportsFormat(const sp<AMessage> &format); private: static constexpr int MAX_INPUT_CHANNEL_COUNT = 30; static constexpr uint32_t MAX_NUM_CHANNELS = FCC_LIMIT; int mError; std::string mMediaType; std::vector<ProfileLevel> mProfileLevels; Range<int> mBitrateRange; std::vector<int> mSampleRates; std::vector<Range<int>> mSampleRateRanges; std::vector<Range<int>> mInputChannelRanges; /* no public constructor */ AudioCapabilities() {} void init(std::string mediaType, std::vector<ProfileLevel> profLevs, const sp<AMessage> &format); void initWithPlatformLimits(); bool supports(int sampleRate, int inputChannels); void limitSampleRates(std::vector<int> rates); void createDiscreteSampleRates(); void limitSampleRates(std::vector<Range<int>> rateRanges); void applyLevelLimits(); void applyLimits(const std::vector<Range<int>> &inputChannels, const std::optional<Range<int>> &bitRates); void parseFromInfo(const sp<AMessage> &format); friend struct CodecCapabilities; }; } // namespace android #endif // AUDIO_CAPABILITIES_H_ No newline at end of file Loading
media/libmedia/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -258,6 +258,7 @@ cc_library_shared { name: "libmedia_codeclist_capabilities", srcs: [ "AudioCapabilities.cpp", "CodecCapabilities.cpp", "CodecCapabilitiesUtils.cpp", ], Loading
media/libmedia/AudioCapabilities.cpp 0 → 100644 +393 −0 Original line number Diff line number Diff line /* * 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<int>& AudioCapabilities::getBitrateRange() const { return mBitrateRange; } const std::vector<int>& AudioCapabilities::getSupportedSampleRates() const { return mSampleRates; } const std::vector<Range<int>>& AudioCapabilities::getSupportedSampleRateRanges() const { return mSampleRateRanges; } int AudioCapabilities::getMaxInputChannelCount() const { int overallMax = 0; for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) { int lmax = mInputChannelRanges[i].upper(); if (lmax > overallMax) { overallMax = lmax; } } return overallMax; } int AudioCapabilities::getMinInputChannelCount() const { int overallMin = MAX_INPUT_CHANNEL_COUNT; for (int i = mInputChannelRanges.size() - 1; i >= 0; i--) { int lmin = mInputChannelRanges[i].lower(); if (lmin < overallMin) { overallMin = lmin; } } return overallMin; } const std::vector<Range<int>>& 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; initWithPlatformLimits(); applyLevelLimits(); parseFromInfo(format); } void AudioCapabilities::initWithPlatformLimits() { mBitrateRange = Range<int>(0, INT_MAX); mInputChannelRanges.push_back(Range<int>(1, MAX_INPUT_CHANNEL_COUNT)); const int minSampleRate = base::GetIntProperty("ro.mediacodec.min_sample_rate", 7350); const int maxSampleRate = base::GetIntProperty("ro.mediacodec.max_sample_rate", 192000); mSampleRateRanges.push_back(Range<int>(minSampleRate, maxSampleRate)); } bool AudioCapabilities::supports(int sampleRate, int inputChannels) { // channels and sample rates are checked orthogonally if (inputChannels != 0 && !std::any_of(mInputChannelRanges.begin(), mInputChannelRanges.end(), [inputChannels](const Range<int> &a) { return a.contains(inputChannels); })) { return false; } if (sampleRate != 0 && !std::any_of(mSampleRateRanges.begin(), mSampleRateRanges.end(), [sampleRate](const Range<int> &a) { return a.contains(sampleRate); })) { return false; } return true; } bool AudioCapabilities::isSampleRateSupported(int sampleRate) { return supports(sampleRate, 0); } void AudioCapabilities::limitSampleRates(std::vector<int> rates) { std::vector<Range<int>> sampleRateRanges; std::sort(rates.begin(), rates.end()); for (int rate : rates) { if (supports(rate, 0 /* channels */)) { sampleRateRanges.push_back(Range<int>(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<int>> rateRanges) { sortDistinctRanges(&rateRanges); mSampleRateRanges = intersectSortedDistinctRanges(mSampleRateRanges, rateRanges); // check if all values are discrete for (Range<int> range: mSampleRateRanges) { if (range.lower() != range.upper()) { mSampleRates.clear(); return; } } createDiscreteSampleRates(); } void AudioCapabilities::applyLevelLimits() { std::vector<int> sampleRates; std::optional<Range<int>> sampleRateRange; std::optional<Range<int>> bitRates; int 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<int>(8000, 320000); maxChannels = 2; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)) { sampleRates = { 8000 }; bitRates = Range<int>(4750, 12200); maxChannels = 1; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)) { sampleRates = { 16000 }; bitRates = Range<int>(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<int>(8000, 510000); maxChannels = 48; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_VORBIS)) { bitRates = Range<int>(32000, 500000); sampleRateRange = Range<int>(8000, 192000); maxChannels = 255; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_OPUS)) { bitRates = Range<int>(6000, 510000); sampleRates = { 8000, 12000, 16000, 24000, 48000 }; maxChannels = 255; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_RAW)) { sampleRateRange = Range<int>(1, 192000); bitRates = Range<int>(1, 10000000); maxChannels = MAX_NUM_CHANNELS; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) { sampleRateRange = Range<int>(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<int>(64000, 64000); // platform allows multiple channels for this format } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) { sampleRates = { 8000 }; bitRates = Range<int>(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<int>(32000, 6144000); maxChannels = 16; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AC4)) { sampleRates = { 44100, 48000, 96000, 192000 }; bitRates = Range<int>(16000, 2688000); maxChannels = 24; } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_DTS)) { sampleRates = { 44100, 48000 }; bitRates = Range<int>(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<int>(32000, 768000); break; case DTS_HDProfileHRA: case DTS_HDProfileMA: sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 }; bitRates = Range<int>(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<int>(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<int>(96000, 768000); maxChannels = 10; break; case DTS_UHDProfileP1: sampleRates = { 44100, 48000, 88200, 96000, 176400, 192000 }; bitRates = Range<int>(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<int>(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<int>> rateRanges = { sampleRateRange.value() }; limitSampleRates(rateRanges); } Range<int> channelRange = Range<int>(1, maxChannels); std::vector<Range<int>> inputChannels = { channelRange }; applyLimits(inputChannels, bitRates); } void AudioCapabilities::applyLimits( const std::vector<Range<int>> &inputChannels, const std::optional<Range<int>> &bitRates) { // clamp & make a local copy std::vector<Range<int>> inputChannelsCopy(inputChannels.size()); for (int i = 0; i < inputChannels.size(); i++) { int lower = inputChannels[i].clamp(1); int upper = inputChannels[i].clamp(MAX_INPUT_CHANNEL_COUNT); inputChannelsCopy[i] = Range<int>(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) { int maxInputChannels = MAX_INPUT_CHANNEL_COUNT; std::vector<Range<int>> channels = { Range<int>(1, maxInputChannels) }; std::optional<Range<int>> bitRates = POSITIVE_INTEGERS; AString rateAString; if (format->findString("sample-rate-ranges", &rateAString)) { std::vector<std::string> rateStrings = base::Split(std::string(rateAString.c_str()), ","); std::vector<Range<int>> rateRanges; for (std::string rateString : rateStrings) { std::optional<Range<int>> rateRange = ParseIntRange(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<int>> channelRanges; for (std::string channelString : channelStrings) { std::optional<Range<int>> channelRange = ParseIntRange(channelString); if (!channelRange) { continue; } channelRanges.push_back(channelRange.value()); } channels = channelRanges; } else if (format->findString("channel-range", &valueStr)) { std::optional<Range<int>> oneRange = ParseIntRange(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<int>(0, 0) }; } else { channels = { Range<int>(1, maxInputChannels) }; } } else if ((mError & ERROR_CAPABILITIES_UNSUPPORTED) != 0) { maxInputChannels = 0; channels = { Range<int>(0, 0) }; } if (format->findString("bitrate-range", &valueStr)) { std::optional<Range<int>> parsedBitrate = ParseIntRange(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 sampleRate; format->findInt32(KEY_SAMPLE_RATE, &sampleRate); int32_t channels; format->findInt32(KEY_CHANNEL_COUNT, &channels); 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 No newline at end of file
media/libmedia/CodecCapabilities.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -25,4 +25,33 @@ namespace android { bool CodecCapabilities::SupportsBitrate(Range<int> bitrateRange, const sp<AMessage> &format) { // consider max bitrate over average bitrate for support int32_t maxBitrate = 0; format->findInt32(KEY_MAX_BIT_RATE, &maxBitrate); int32_t bitrate = 0; format->findInt32(KEY_BIT_RATE, &bitrate); if (bitrate == 0) { bitrate = maxBitrate; } else if (maxBitrate != 0) { bitrate = std::max(bitrate, maxBitrate); } if (bitrate > 0) { return bitrateRange.contains(bitrate); } return true; } const std::string& CodecCapabilities::getMediaType() { return mMediaType; } const std::vector<ProfileLevel>& CodecCapabilities::getProfileLevels() { return mProfileLevels; } } // namespace android No newline at end of file
media/libmedia/CodecCapabilitiesUtils.cpp +21 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include <algorithm> #include <cmath> #include <regex> #include <string> #include <vector> Loading @@ -29,4 +30,24 @@ namespace android { std::optional<Range<int>> ParseIntRange(const std::string &str) { if (str.empty()) { ALOGW("could not parse empty integer range"); return std::nullopt; } int lower, upper; std::regex regex("([0-9]+)-([0-9]+)"); std::smatch match; if (std::regex_match(str, match, regex)) { lower = std::atoi(match[1].str().c_str()); upper = std::atoi(match[2].str().c_str()); } else if (std::atoi(str.c_str()) != 0) { lower = upper = std::atoi(str.c_str()); } else { ALOGW("could not parse integer range: %s", str.c_str()); return std::nullopt; } return std::make_optional<Range<int>>(lower, upper); } } // namespace android No newline at end of file
media/libmedia/include/media/AudioCapabilities.h 0 → 100644 +138 −0 Original line number Diff line number Diff line /* * 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. */ #ifndef AUDIO_CAPABILITIES_H_ #define AUDIO_CAPABILITIES_H_ #include <media/CodecCapabilitiesUtils.h> #include <media/stagefright/foundation/AMessage.h> #include <system/audio.h> #include <utils/StrongPointer.h> namespace android { struct AudioCapabilities { /** * Create AudioCapabilities. */ static std::shared_ptr<AudioCapabilities> Create(std::string mediaType, std::vector<ProfileLevel> profLevs, const sp<AMessage> &format); /** * Returns the range of supported bitrates in bits/second. */ const Range<int>& getBitrateRange() const; /** * Returns the array of supported sample rates if the codec * supports only discrete values. Otherwise, it returns an empty array. * The array is sorted in ascending order. */ const std::vector<int>& getSupportedSampleRates() const; /** * Returns the array of supported sample rate ranges. The * array is sorted in ascending order, and the ranges are * distinct. */ const std::vector<Range<int>>& getSupportedSampleRateRanges() const; /** * Returns the maximum number of input channels supported. * The returned value should be between 1 and 255. * * Through {@link android.os.Build.VERSION_CODES#R}, this method indicated support * for any number of input channels between 1 and this maximum value. * * As of {@link android.os.Build.VERSION_CODES#S}, * the implied lower limit of 1 channel is no longer valid. * As of {@link android.os.Build.VERSION_CODES#S}, {@link #getMaxInputChannelCount} is * superseded by {@link #getInputChannelCountRanges}, * which returns an array of ranges of channels. * The {@link #getMaxInputChannelCount} method will return the highest value * in the ranges returned by {@link #getInputChannelCountRanges} */ int getMaxInputChannelCount() const; /** * Returns the minimum number of input channels supported. * This is often 1, but does vary for certain mime types. * * This returns the lowest channel count in the ranges returned by * {@link #getInputChannelCountRanges}. */ int getMinInputChannelCount() const; /** * Returns an array of ranges representing the number of input channels supported. * The codec supports any number of input channels within this range. * * This supersedes the {@link #getMaxInputChannelCount} method. * * For many codecs, this will be a single range [1..N], for some N. * * The returned array cannot be empty. */ const std::vector<Range<int>>& getInputChannelCountRanges() const; /** * Query whether the sample rate is supported by the codec. */ bool isSampleRateSupported(int sampleRate); /* For internal use only. Not exposed as a public API */ void getDefaultFormat(sp<AMessage> &format); /* For internal use only. Not exposed as a public API */ bool supportsFormat(const sp<AMessage> &format); private: static constexpr int MAX_INPUT_CHANNEL_COUNT = 30; static constexpr uint32_t MAX_NUM_CHANNELS = FCC_LIMIT; int mError; std::string mMediaType; std::vector<ProfileLevel> mProfileLevels; Range<int> mBitrateRange; std::vector<int> mSampleRates; std::vector<Range<int>> mSampleRateRanges; std::vector<Range<int>> mInputChannelRanges; /* no public constructor */ AudioCapabilities() {} void init(std::string mediaType, std::vector<ProfileLevel> profLevs, const sp<AMessage> &format); void initWithPlatformLimits(); bool supports(int sampleRate, int inputChannels); void limitSampleRates(std::vector<int> rates); void createDiscreteSampleRates(); void limitSampleRates(std::vector<Range<int>> rateRanges); void applyLevelLimits(); void applyLimits(const std::vector<Range<int>> &inputChannels, const std::optional<Range<int>> &bitRates); void parseFromInfo(const sp<AMessage> &format); friend struct CodecCapabilities; }; } // namespace android #endif // AUDIO_CAPABILITIES_H_ No newline at end of file