xref: /aosp_15_r20/frameworks/av/media/libmedia/EncoderCapabilities.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright 2024, The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *     http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "EncoderCapabilities"
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <android-base/strings.h>
21*ec779b8eSAndroid Build Coastguard Worker 
22*ec779b8eSAndroid Build Coastguard Worker #include <media/CodecCapabilities.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <media/EncoderCapabilities.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <media/stagefright/MediaCodecConstants.h>
25*ec779b8eSAndroid Build Coastguard Worker 
26*ec779b8eSAndroid Build Coastguard Worker namespace android {
27*ec779b8eSAndroid Build Coastguard Worker 
getQualityRange()28*ec779b8eSAndroid Build Coastguard Worker const Range<int>& EncoderCapabilities::getQualityRange() {
29*ec779b8eSAndroid Build Coastguard Worker     return mQualityRange;
30*ec779b8eSAndroid Build Coastguard Worker }
31*ec779b8eSAndroid Build Coastguard Worker 
getComplexityRange()32*ec779b8eSAndroid Build Coastguard Worker const Range<int>& EncoderCapabilities::getComplexityRange() {
33*ec779b8eSAndroid Build Coastguard Worker     return mComplexityRange;
34*ec779b8eSAndroid Build Coastguard Worker }
35*ec779b8eSAndroid Build Coastguard Worker 
36*ec779b8eSAndroid Build Coastguard Worker // static
ParseBitrateMode(std::string mode)37*ec779b8eSAndroid Build Coastguard Worker int EncoderCapabilities::ParseBitrateMode(std::string mode) {
38*ec779b8eSAndroid Build Coastguard Worker     for (Feature feat: sBitrateModes) {
39*ec779b8eSAndroid Build Coastguard Worker         if (base::EqualsIgnoreCase(feat.mName, mode)) {
40*ec779b8eSAndroid Build Coastguard Worker             return feat.mValue;
41*ec779b8eSAndroid Build Coastguard Worker         }
42*ec779b8eSAndroid Build Coastguard Worker     }
43*ec779b8eSAndroid Build Coastguard Worker     return 0;
44*ec779b8eSAndroid Build Coastguard Worker }
45*ec779b8eSAndroid Build Coastguard Worker 
isBitrateModeSupported(int mode)46*ec779b8eSAndroid Build Coastguard Worker bool EncoderCapabilities::isBitrateModeSupported(int mode) {
47*ec779b8eSAndroid Build Coastguard Worker     for (Feature feat : sBitrateModes) {
48*ec779b8eSAndroid Build Coastguard Worker         if (mode == feat.mValue) {
49*ec779b8eSAndroid Build Coastguard Worker             return (mBitControl & (1 << mode)) != 0;
50*ec779b8eSAndroid Build Coastguard Worker         }
51*ec779b8eSAndroid Build Coastguard Worker     }
52*ec779b8eSAndroid Build Coastguard Worker     return false;
53*ec779b8eSAndroid Build Coastguard Worker }
54*ec779b8eSAndroid Build Coastguard Worker 
55*ec779b8eSAndroid Build Coastguard Worker // static
Create(std::string mediaType,std::vector<ProfileLevel> profLevs,const sp<AMessage> & format)56*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<EncoderCapabilities> EncoderCapabilities::Create(std::string mediaType,
57*ec779b8eSAndroid Build Coastguard Worker         std::vector<ProfileLevel> profLevs, const sp<AMessage> &format) {
58*ec779b8eSAndroid Build Coastguard Worker     std::shared_ptr<EncoderCapabilities> caps(new EncoderCapabilities());
59*ec779b8eSAndroid Build Coastguard Worker     caps->init(mediaType, profLevs, format);
60*ec779b8eSAndroid Build Coastguard Worker     return caps;
61*ec779b8eSAndroid Build Coastguard Worker }
62*ec779b8eSAndroid Build Coastguard Worker 
init(std::string mediaType,std::vector<ProfileLevel> profLevs,const sp<AMessage> & format)63*ec779b8eSAndroid Build Coastguard Worker void EncoderCapabilities::init(std::string mediaType, std::vector<ProfileLevel> profLevs,
64*ec779b8eSAndroid Build Coastguard Worker         const sp<AMessage> &format) {
65*ec779b8eSAndroid Build Coastguard Worker     // no support for complexity or quality yet
66*ec779b8eSAndroid Build Coastguard Worker     mMediaType = mediaType;
67*ec779b8eSAndroid Build Coastguard Worker     mProfileLevels = profLevs;
68*ec779b8eSAndroid Build Coastguard Worker     mComplexityRange = Range(0, 0);
69*ec779b8eSAndroid Build Coastguard Worker     mQualityRange = Range(0, 0);
70*ec779b8eSAndroid Build Coastguard Worker     mBitControl = (1 << BITRATE_MODE_VBR);
71*ec779b8eSAndroid Build Coastguard Worker 
72*ec779b8eSAndroid Build Coastguard Worker     applyLevelLimits();
73*ec779b8eSAndroid Build Coastguard Worker     parseFromInfo(format);
74*ec779b8eSAndroid Build Coastguard Worker }
75*ec779b8eSAndroid Build Coastguard Worker 
applyLevelLimits()76*ec779b8eSAndroid Build Coastguard Worker void EncoderCapabilities::applyLevelLimits() {
77*ec779b8eSAndroid Build Coastguard Worker     if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
78*ec779b8eSAndroid Build Coastguard Worker         mComplexityRange = Range(0, 8);
79*ec779b8eSAndroid Build Coastguard Worker         mBitControl = (1 << BITRATE_MODE_CQ);
80*ec779b8eSAndroid Build Coastguard Worker     } else if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_NB)
81*ec779b8eSAndroid Build Coastguard Worker             || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AMR_WB)
82*ec779b8eSAndroid Build Coastguard Worker             || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_ALAW)
83*ec779b8eSAndroid Build Coastguard Worker             || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_G711_MLAW)
84*ec779b8eSAndroid Build Coastguard Worker             || base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_MSGSM)) {
85*ec779b8eSAndroid Build Coastguard Worker         mBitControl = (1 << BITRATE_MODE_CBR);
86*ec779b8eSAndroid Build Coastguard Worker     }
87*ec779b8eSAndroid Build Coastguard Worker }
88*ec779b8eSAndroid Build Coastguard Worker 
parseFromInfo(const sp<AMessage> & format)89*ec779b8eSAndroid Build Coastguard Worker void EncoderCapabilities::parseFromInfo(const sp<AMessage> &format) {
90*ec779b8eSAndroid Build Coastguard Worker     AString complexityRangeAStr;
91*ec779b8eSAndroid Build Coastguard Worker     if (format->findString("complexity-range", &complexityRangeAStr)) {
92*ec779b8eSAndroid Build Coastguard Worker         std::optional<Range<int>> complexityRangeOpt
93*ec779b8eSAndroid Build Coastguard Worker                 = Range<int32_t>::Parse(std::string(complexityRangeAStr.c_str()));
94*ec779b8eSAndroid Build Coastguard Worker         mComplexityRange = complexityRangeOpt.value_or(mComplexityRange);
95*ec779b8eSAndroid Build Coastguard Worker         // TODO should we limit this to level limits?
96*ec779b8eSAndroid Build Coastguard Worker     }
97*ec779b8eSAndroid Build Coastguard Worker     AString qualityRangeAStr;
98*ec779b8eSAndroid Build Coastguard Worker     if (format->findString("quality-range", &qualityRangeAStr)) {
99*ec779b8eSAndroid Build Coastguard Worker         std::optional<Range<int>> qualityRangeOpt
100*ec779b8eSAndroid Build Coastguard Worker                 = Range<int32_t>::Parse(std::string(qualityRangeAStr.c_str()));
101*ec779b8eSAndroid Build Coastguard Worker         mQualityRange = qualityRangeOpt.value_or(mQualityRange);
102*ec779b8eSAndroid Build Coastguard Worker     }
103*ec779b8eSAndroid Build Coastguard Worker     AString bitrateModesAStr;
104*ec779b8eSAndroid Build Coastguard Worker     if (format->findString("feature-bitrate-modes", &bitrateModesAStr)) {
105*ec779b8eSAndroid Build Coastguard Worker         mBitControl = 0;
106*ec779b8eSAndroid Build Coastguard Worker         for (std::string mode: base::Split(std::string(bitrateModesAStr.c_str()), ",")) {
107*ec779b8eSAndroid Build Coastguard Worker             mBitControl |= (1 << ParseBitrateMode(mode));
108*ec779b8eSAndroid Build Coastguard Worker         }
109*ec779b8eSAndroid Build Coastguard Worker     }
110*ec779b8eSAndroid Build Coastguard Worker     format->findInt32("complexity-default", &mDefaultComplexity);
111*ec779b8eSAndroid Build Coastguard Worker     format->findInt32("quality-default", &mDefaultQuality);
112*ec779b8eSAndroid Build Coastguard Worker     AString qualityScaleAStr;
113*ec779b8eSAndroid Build Coastguard Worker     if (format->findString("quality-scale", &qualityScaleAStr)) {
114*ec779b8eSAndroid Build Coastguard Worker         mQualityScale = std::string(qualityScaleAStr.c_str());
115*ec779b8eSAndroid Build Coastguard Worker     }
116*ec779b8eSAndroid Build Coastguard Worker }
117*ec779b8eSAndroid Build Coastguard Worker 
supports(std::optional<int> complexity,std::optional<int> quality,std::optional<int> profile)118*ec779b8eSAndroid Build Coastguard Worker bool EncoderCapabilities::supports(
119*ec779b8eSAndroid Build Coastguard Worker         std::optional<int> complexity, std::optional<int> quality, std::optional<int> profile) {
120*ec779b8eSAndroid Build Coastguard Worker     bool ok = true;
121*ec779b8eSAndroid Build Coastguard Worker     if (complexity) {
122*ec779b8eSAndroid Build Coastguard Worker         ok &= mComplexityRange.contains(complexity.value());
123*ec779b8eSAndroid Build Coastguard Worker     }
124*ec779b8eSAndroid Build Coastguard Worker     if (quality) {
125*ec779b8eSAndroid Build Coastguard Worker         ok &= mQualityRange.contains(quality.value());
126*ec779b8eSAndroid Build Coastguard Worker     }
127*ec779b8eSAndroid Build Coastguard Worker     if (profile) {
128*ec779b8eSAndroid Build Coastguard Worker         ok &= std::any_of(mProfileLevels.begin(), mProfileLevels.end(),
129*ec779b8eSAndroid Build Coastguard Worker                 [&profile](ProfileLevel pl){ return pl.mProfile == profile.value(); });
130*ec779b8eSAndroid Build Coastguard Worker     }
131*ec779b8eSAndroid Build Coastguard Worker     return ok;
132*ec779b8eSAndroid Build Coastguard Worker }
133*ec779b8eSAndroid Build Coastguard Worker 
getDefaultFormat(sp<AMessage> & format)134*ec779b8eSAndroid Build Coastguard Worker void EncoderCapabilities::getDefaultFormat(sp<AMessage> &format) {
135*ec779b8eSAndroid Build Coastguard Worker     // don't list trivial quality/complexity as default for now
136*ec779b8eSAndroid Build Coastguard Worker     if (mQualityRange.upper() != mQualityRange.lower()
137*ec779b8eSAndroid Build Coastguard Worker             && mDefaultQuality != 0) {
138*ec779b8eSAndroid Build Coastguard Worker         format->setInt32(KEY_QUALITY, mDefaultQuality);
139*ec779b8eSAndroid Build Coastguard Worker     }
140*ec779b8eSAndroid Build Coastguard Worker     if (mComplexityRange.upper() != mComplexityRange.lower()
141*ec779b8eSAndroid Build Coastguard Worker             && mDefaultComplexity != 0) {
142*ec779b8eSAndroid Build Coastguard Worker         format->setInt32(KEY_COMPLEXITY, mDefaultComplexity);
143*ec779b8eSAndroid Build Coastguard Worker     }
144*ec779b8eSAndroid Build Coastguard Worker     // bitrates are listed in order of preference
145*ec779b8eSAndroid Build Coastguard Worker     for (Feature feat : sBitrateModes) {
146*ec779b8eSAndroid Build Coastguard Worker         if ((mBitControl & (1 << feat.mValue)) != 0) {
147*ec779b8eSAndroid Build Coastguard Worker             format->setInt32(KEY_BITRATE_MODE, feat.mValue);
148*ec779b8eSAndroid Build Coastguard Worker             break;
149*ec779b8eSAndroid Build Coastguard Worker         }
150*ec779b8eSAndroid Build Coastguard Worker     }
151*ec779b8eSAndroid Build Coastguard Worker }
152*ec779b8eSAndroid Build Coastguard Worker 
supportsFormat(const sp<AMessage> & format)153*ec779b8eSAndroid Build Coastguard Worker bool EncoderCapabilities::supportsFormat(const sp<AMessage> &format) {
154*ec779b8eSAndroid Build Coastguard Worker     int32_t mode;
155*ec779b8eSAndroid Build Coastguard Worker     if (format->findInt32(KEY_BITRATE_MODE, &mode) && !isBitrateModeSupported(mode)) {
156*ec779b8eSAndroid Build Coastguard Worker         return false;
157*ec779b8eSAndroid Build Coastguard Worker     }
158*ec779b8eSAndroid Build Coastguard Worker 
159*ec779b8eSAndroid Build Coastguard Worker     int tmp;
160*ec779b8eSAndroid Build Coastguard Worker     std::optional<int> complexity = std::nullopt;
161*ec779b8eSAndroid Build Coastguard Worker     if (format->findInt32(KEY_COMPLEXITY, &tmp)) {
162*ec779b8eSAndroid Build Coastguard Worker         complexity = tmp;
163*ec779b8eSAndroid Build Coastguard Worker     }
164*ec779b8eSAndroid Build Coastguard Worker 
165*ec779b8eSAndroid Build Coastguard Worker     if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_FLAC)) {
166*ec779b8eSAndroid Build Coastguard Worker         int flacComplexity;
167*ec779b8eSAndroid Build Coastguard Worker         if (format->findInt32(KEY_FLAC_COMPRESSION_LEVEL, &flacComplexity)) {
168*ec779b8eSAndroid Build Coastguard Worker             if (!complexity) {
169*ec779b8eSAndroid Build Coastguard Worker                 complexity = flacComplexity;
170*ec779b8eSAndroid Build Coastguard Worker             } else if (flacComplexity != complexity.value()) {
171*ec779b8eSAndroid Build Coastguard Worker                 ALOGE("Conflicting values for complexity and flac-compression-level,"
172*ec779b8eSAndroid Build Coastguard Worker                         " which are %d and %d", complexity.value(), flacComplexity);
173*ec779b8eSAndroid Build Coastguard Worker                 return false;
174*ec779b8eSAndroid Build Coastguard Worker             }
175*ec779b8eSAndroid Build Coastguard Worker         }
176*ec779b8eSAndroid Build Coastguard Worker     }
177*ec779b8eSAndroid Build Coastguard Worker 
178*ec779b8eSAndroid Build Coastguard Worker     // other audio parameters
179*ec779b8eSAndroid Build Coastguard Worker     std::optional<int> profile = std::nullopt;
180*ec779b8eSAndroid Build Coastguard Worker     if (format->findInt32(KEY_PROFILE, &tmp)) {
181*ec779b8eSAndroid Build Coastguard Worker         profile = tmp;
182*ec779b8eSAndroid Build Coastguard Worker     }
183*ec779b8eSAndroid Build Coastguard Worker 
184*ec779b8eSAndroid Build Coastguard Worker     if (base::EqualsIgnoreCase(mMediaType, MIMETYPE_AUDIO_AAC)) {
185*ec779b8eSAndroid Build Coastguard Worker         int aacProfile;
186*ec779b8eSAndroid Build Coastguard Worker         if (format->findInt32(KEY_AAC_PROFILE, &aacProfile)) {
187*ec779b8eSAndroid Build Coastguard Worker             if (!profile) {
188*ec779b8eSAndroid Build Coastguard Worker                 profile = aacProfile;
189*ec779b8eSAndroid Build Coastguard Worker             } else if (aacProfile != profile.value()) {
190*ec779b8eSAndroid Build Coastguard Worker                 ALOGE("Conflicting values for profile and aac-profile, which are %d and %d",
191*ec779b8eSAndroid Build Coastguard Worker                         profile.value(), aacProfile);
192*ec779b8eSAndroid Build Coastguard Worker                 return false;
193*ec779b8eSAndroid Build Coastguard Worker             }
194*ec779b8eSAndroid Build Coastguard Worker         }
195*ec779b8eSAndroid Build Coastguard Worker     }
196*ec779b8eSAndroid Build Coastguard Worker 
197*ec779b8eSAndroid Build Coastguard Worker     std::optional<int> quality = std::nullopt;
198*ec779b8eSAndroid Build Coastguard Worker     if (format->findInt32(KEY_QUALITY, &tmp)) {
199*ec779b8eSAndroid Build Coastguard Worker         quality = tmp;
200*ec779b8eSAndroid Build Coastguard Worker     }
201*ec779b8eSAndroid Build Coastguard Worker 
202*ec779b8eSAndroid Build Coastguard Worker     return supports(complexity, quality, profile);
203*ec779b8eSAndroid Build Coastguard Worker }
204*ec779b8eSAndroid Build Coastguard Worker 
205*ec779b8eSAndroid Build Coastguard Worker }  // namespace android