/* * 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 "EncoderCapabilities" #include #include #include #include namespace android { const Range& EncoderCapabilities::getQualityRange() { return mQualityRange; } const Range& EncoderCapabilities::getComplexityRange() { return mComplexityRange; } // static int EncoderCapabilities::ParseBitrateMode(std::string mode) { for (Feature feat: sBitrateModes) { if (base::EqualsIgnoreCase(feat.mName, mode)) { return feat.mValue; } } return 0; } bool EncoderCapabilities::isBitrateModeSupported(int mode) { for (Feature feat : sBitrateModes) { if (mode == feat.mValue) { return (mBitControl & (1 << mode)) != 0; } } return false; } // static std::shared_ptr EncoderCapabilities::Create(std::string mediaType, std::vector profLevs, const sp &format) { std::shared_ptr caps(new EncoderCapabilities()); caps->init(mediaType, profLevs, format); return caps; } void EncoderCapabilities::init(std::string mediaType, std::vector profLevs, const sp &format) { // no support for complexity or quality yet mMediaType = mediaType; mProfileLevels = profLevs; mComplexityRange = Range(0, 0); mQualityRange = Range(0, 0); mBitControl = (1 << BITRATE_MODE_VBR); applyLevelLimits(); parseFromInfo(format); } void EncoderCapabilities::applyLevelLimits() { if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) { mComplexityRange = Range(0, 8); mBitControl = (1 << BITRATE_MODE_CQ); } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW) || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) { mBitControl = (1 << BITRATE_MODE_CBR); } } void EncoderCapabilities::parseFromInfo(const sp &format) { AString complexityRangeAStr; if (format->findString("complexity-range", &complexityRangeAStr)) { std::optional> complexityRangeOpt = Range::Parse(std::string(complexityRangeAStr.c_str())); mComplexityRange = complexityRangeOpt.value_or(mComplexityRange); // TODO should we limit this to level limits? } AString qualityRangeAStr; if (format->findString("quality-range", &qualityRangeAStr)) { std::optional> qualityRangeOpt = Range::Parse(std::string(qualityRangeAStr.c_str())); mQualityRange = qualityRangeOpt.value_or(mQualityRange); } AString bitrateModesAStr; if (format->findString("feature-bitrate-modes", &bitrateModesAStr)) { mBitControl = 0; for (std::string mode: base::Split(std::string(bitrateModesAStr.c_str()), ",")) { mBitControl |= (1 << ParseBitrateMode(mode)); } } format->findInt32("complexity-default", &mDefaultComplexity); format->findInt32("quality-default", &mDefaultQuality); AString qualityScaleAStr; if (format->findString("quality-scale", &qualityScaleAStr)) { mQualityScale = std::string(qualityScaleAStr.c_str()); } } bool EncoderCapabilities::supports( std::optional complexity, std::optional quality, std::optional profile) { bool ok = true; if (complexity) { ok &= mComplexityRange.contains(complexity.value()); } if (quality) { ok &= mQualityRange.contains(quality.value()); } if (profile) { ok &= std::any_of(mProfileLevels.begin(), mProfileLevels.end(), [&profile](ProfileLevel pl){ return pl.mProfile == profile.value(); }); } return ok; } void EncoderCapabilities::getDefaultFormat(sp &format) { // don't list trivial quality/complexity as default for now if (mQualityRange.upper() != mQualityRange.lower() && mDefaultQuality != 0) { format->setInt32(KEY_QUALITY, mDefaultQuality); } if (mComplexityRange.upper() != mComplexityRange.lower() && mDefaultComplexity != 0) { format->setInt32(KEY_COMPLEXITY, mDefaultComplexity); } // bitrates are listed in order of preference for (Feature feat : sBitrateModes) { if ((mBitControl & (1 << feat.mValue)) != 0) { format->setInt32(KEY_BITRATE_MODE, feat.mValue); break; } } } bool EncoderCapabilities::supportsFormat(const sp &format) { int32_t mode; if (format->findInt32(KEY_BITRATE_MODE, &mode) && !isBitrateModeSupported(mode)) { return false; } int tmp; std::optional complexity = std::nullopt; if (format->findInt32(KEY_COMPLEXITY, &tmp)) { complexity = tmp; } if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) { int flacComplexity; if (format->findInt32(KEY_FLAC_COMPRESSION_LEVEL, &flacComplexity)) { if (!complexity) { complexity = flacComplexity; } else if (flacComplexity != complexity.value()) { ALOGE("Conflicting values for complexity and flac-compression-level," " which are %d and %d", complexity.value(), flacComplexity); return false; } } } // other audio parameters std::optional profile = std::nullopt; if (format->findInt32(KEY_PROFILE, &tmp)) { profile = tmp; } if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) { int aacProfile; if (format->findInt32(KEY_AAC_PROFILE, &aacProfile)) { if (!profile) { profile = aacProfile; } else if (aacProfile != profile.value()) { ALOGE("Conflicting values for profile and aac-profile, which are %d and %d", profile.value(), aacProfile); return false; } } } std::optional quality = std::nullopt; if (format->findInt32(KEY_QUALITY, &tmp)) { quality = tmp; } return supports(complexity, quality, profile); } } // namespace android