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