blob: 67d7ed2be2034a46da5d236c5eac0b70f4ed57a7 [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "Codec2InfoBuilder"
19#include <log/log.h>
20
21#include <strings.h>
22
23#include <C2Component.h>
24#include <C2Config.h>
25#include <C2Debug.h>
26#include <C2PlatformSupport.h>
27#include <Codec2Mapper.h>
28
29#include <OMX_Audio.h>
30#include <OMX_AudioExt.h>
31#include <OMX_IndexExt.h>
32#include <OMX_Types.h>
33#include <OMX_Video.h>
34#include <OMX_VideoExt.h>
35#include <OMX_AsString.h>
36
37#include <android/hardware/media/omx/1.0/IOmx.h>
38#include <android/hardware/media/omx/1.0/IOmxObserver.h>
39#include <android/hardware/media/omx/1.0/IOmxNode.h>
40#include <android/hardware/media/omx/1.0/types.h>
41
42#include <android-base/properties.h>
43#include <codec2/hidl/client.h>
44#include <cutils/native_handle.h>
45#include <media/omx/1.0/WOmxNode.h>
Pawin Vongmasa1f213362019-01-24 06:59:16 -080046#include <media/stagefright/foundation/ALookup.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080047#include <media/stagefright/foundation/MediaDefs.h>
48#include <media/stagefright/omx/OMXUtils.h>
49#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070050#include <media/stagefright/Codec2InfoBuilder.h>
51#include <media/stagefright/MediaCodecConstants.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080052
53namespace android {
54
55using Traits = C2Component::Traits;
56
57namespace /* unnamed */ {
58
59bool hasPrefix(const std::string& s, const char* prefix) {
60 size_t prefixLen = strlen(prefix);
61 return s.compare(0, prefixLen, prefix) == 0;
62}
63
64bool hasSuffix(const std::string& s, const char* suffix) {
65 size_t suffixLen = strlen(suffix);
66 return suffixLen > s.size() ? false :
67 s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
68}
69
Lajos Molnar59f4a4e2021-07-09 18:23:54 -070070// returns true if component advertised supported profile level(s)
71bool addSupportedProfileLevels(
Lajos Molnardb5751f2019-01-31 17:01:49 -080072 std::shared_ptr<Codec2Client::Interface> intf,
73 MediaCodecInfo::CapabilitiesWriter *caps,
74 const Traits& trait, const std::string &mediaType) {
75 std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
76 C2Mapper::GetProfileLevelMapper(trait.mediaType);
77 // if we don't know the media type, pass through all values unmapped
Pawin Vongmasa36653902018-11-15 00:10:25 -080078
Lajos Molnardb5751f2019-01-31 17:01:49 -080079 // TODO: we cannot find levels that are local 'maxima' without knowing the coding
80 // e.g. H.263 level 45 and level 30 could be two values for highest level as
81 // they don't include one another. For now we use the last supported value.
82 bool encoder = trait.kind == C2Component::KIND_ENCODER;
83 C2StreamProfileLevelInfo pl(encoder /* output */, 0u);
84 std::vector<C2FieldSupportedValuesQuery> profileQuery = {
85 C2FieldSupportedValuesQuery::Possible(C2ParamField(&pl, &pl.profile))
Pawin Vongmasa36653902018-11-15 00:10:25 -080086 };
87
Lajos Molnardb5751f2019-01-31 17:01:49 -080088 c2_status_t err = intf->querySupportedValues(profileQuery, C2_DONT_BLOCK);
89 ALOGV("query supported profiles -> %s | %s", asString(err), asString(profileQuery[0].status));
90 if (err != C2_OK || profileQuery[0].status != C2_OK) {
Lajos Molnar59f4a4e2021-07-09 18:23:54 -070091 return false;
Pawin Vongmasa36653902018-11-15 00:10:25 -080092 }
93
Lajos Molnardb5751f2019-01-31 17:01:49 -080094 // we only handle enumerated values
95 if (profileQuery[0].values.type != C2FieldSupportedValues::VALUES) {
Lajos Molnar59f4a4e2021-07-09 18:23:54 -070096 return false;
Pawin Vongmasa36653902018-11-15 00:10:25 -080097 }
98
Wonsik Kim4b7bb0a2021-11-03 11:43:48 -070099 // determine if codec supports HDR; imply 10-bit support
Lajos Molnardb5751f2019-01-31 17:01:49 -0800100 bool supportsHdr = false;
Wonsik Kim4b7bb0a2021-11-03 11:43:48 -0700101 // determine if codec supports HDR10Plus; imply 10-bit support
Lajos Molnardb5751f2019-01-31 17:01:49 -0800102 bool supportsHdr10Plus = false;
Wonsik Kim4b7bb0a2021-11-03 11:43:48 -0700103 // determine if codec supports 10-bit format
104 bool supports10Bit = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800105
Lajos Molnardb5751f2019-01-31 17:01:49 -0800106 std::vector<std::shared_ptr<C2ParamDescriptor>> paramDescs;
107 c2_status_t err1 = intf->querySupportedParams(&paramDescs);
108 if (err1 == C2_OK) {
109 for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
Lajos Molnar739fe732021-02-07 13:06:10 -0800110 C2Param::Type type = desc->index();
111 // only consider supported parameters on raw ports
112 if (!(encoder ? type.forInput() : type.forOutput())) {
113 continue;
114 }
115 switch (type.coreIndex()) {
116 case C2StreamHdr10PlusInfo::CORE_INDEX:
Lajos Molnardb5751f2019-01-31 17:01:49 -0800117 supportsHdr10Plus = true;
118 break;
Lajos Molnar739fe732021-02-07 13:06:10 -0800119 case C2StreamHdrStaticInfo::CORE_INDEX:
Lajos Molnardb5751f2019-01-31 17:01:49 -0800120 supportsHdr = true;
121 break;
122 default:
Pawin Vongmasa36653902018-11-15 00:10:25 -0800123 break;
124 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800125 }
126 }
127
Chong Zhang0702d1f2019-08-15 11:45:36 -0700128 // For VP9/AV1, the static info is always propagated by framework.
Lajos Molnardb5751f2019-01-31 17:01:49 -0800129 supportsHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
Chong Zhang0702d1f2019-08-15 11:45:36 -0700130 supportsHdr |= (mediaType == MIMETYPE_VIDEO_AV1);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800131
Wonsik Kim4b7bb0a2021-11-03 11:43:48 -0700132 // HDR support implies 10-bit support.
133 // TODO: directly check this from the component interface
134 supports10Bit = (supportsHdr || supportsHdr10Plus);
135
Lajos Molnar59f4a4e2021-07-09 18:23:54 -0700136 bool added = false;
137
Lajos Molnardb5751f2019-01-31 17:01:49 -0800138 for (C2Value::Primitive profile : profileQuery[0].values.values) {
139 pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
140 std::vector<std::unique_ptr<C2SettingResult>> failures;
141 err = intf->config({&pl}, C2_DONT_BLOCK, &failures);
142 ALOGV("set profile to %u -> %s", pl.profile, asString(err));
143 std::vector<C2FieldSupportedValuesQuery> levelQuery = {
144 C2FieldSupportedValuesQuery::Current(C2ParamField(&pl, &pl.level))
145 };
146 err = intf->querySupportedValues(levelQuery, C2_DONT_BLOCK);
147 ALOGV("query supported levels -> %s | %s", asString(err), asString(levelQuery[0].status));
148 if (err != C2_OK || levelQuery[0].status != C2_OK
149 || levelQuery[0].values.type != C2FieldSupportedValues::VALUES
150 || levelQuery[0].values.values.size() == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800151 continue;
152 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800153
154 C2Value::Primitive level = levelQuery[0].values.values.back();
155 pl.level = (C2Config::level_t)level.ref<uint32_t>();
156 ALOGV("supporting level: %u", pl.level);
157 int32_t sdkProfile, sdkLevel;
158 if (mapper && mapper->mapProfile(pl.profile, &sdkProfile)
159 && mapper->mapLevel(pl.level, &sdkLevel)) {
160 caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
161 // also list HDR profiles if component supports HDR
162 if (supportsHdr) {
163 auto hdrMapper = C2Mapper::GetHdrProfileLevelMapper(trait.mediaType);
164 if (hdrMapper && hdrMapper->mapProfile(pl.profile, &sdkProfile)) {
165 caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
166 }
167 if (supportsHdr10Plus) {
168 hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
169 trait.mediaType, true /*isHdr10Plus*/);
170 if (hdrMapper && hdrMapper->mapProfile(pl.profile, &sdkProfile)) {
171 caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
172 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800173 }
174 }
Wonsik Kim4b7bb0a2021-11-03 11:43:48 -0700175 if (supports10Bit) {
176 auto bitnessMapper = C2Mapper::GetBitDepthProfileLevelMapper(trait.mediaType, 10);
177 if (bitnessMapper && bitnessMapper->mapProfile(pl.profile, &sdkProfile)) {
178 caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
179 }
180 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800181 } else if (!mapper) {
182 caps->addProfileLevel(pl.profile, pl.level);
183 }
Lajos Molnar59f4a4e2021-07-09 18:23:54 -0700184 added = true;
Lajos Molnardb5751f2019-01-31 17:01:49 -0800185
186 // for H.263 also advertise the second highest level if the
187 // codec supports level 45, as level 45 only covers level 10
188 // TODO: move this to some form of a setting so it does not
189 // have to be here
190 if (mediaType == MIMETYPE_VIDEO_H263) {
191 C2Config::level_t nextLevel = C2Config::LEVEL_UNUSED;
192 for (C2Value::Primitive v : levelQuery[0].values.values) {
193 C2Config::level_t level = (C2Config::level_t)v.ref<uint32_t>();
194 if (level < C2Config::LEVEL_H263_45 && level > nextLevel) {
195 nextLevel = level;
196 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800197 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800198 if (nextLevel != C2Config::LEVEL_UNUSED
199 && nextLevel != pl.level
200 && mapper
201 && mapper->mapProfile(pl.profile, &sdkProfile)
202 && mapper->mapLevel(nextLevel, &sdkLevel)) {
203 caps->addProfileLevel(
204 (uint32_t)sdkProfile, (uint32_t)sdkLevel);
205 }
206 }
207 }
Lajos Molnar59f4a4e2021-07-09 18:23:54 -0700208 return added;
Lajos Molnardb5751f2019-01-31 17:01:49 -0800209}
210
211void addSupportedColorFormats(
212 std::shared_ptr<Codec2Client::Interface> intf,
213 MediaCodecInfo::CapabilitiesWriter *caps,
214 const Traits& trait, const std::string &mediaType) {
215 (void)intf;
216
217 // TODO: get this from intf() as well, but how do we map them to
218 // MediaCodec color formats?
219 bool encoder = trait.kind == C2Component::KIND_ENCODER;
Wonsik Kim16223262019-06-14 14:40:57 -0700220 if (mediaType.find("video") != std::string::npos
221 || mediaType.find("image") != std::string::npos) {
Lajos Molnardb5751f2019-01-31 17:01:49 -0800222 // vendor video codecs prefer opaque format
223 if (trait.name.find("android") == std::string::npos) {
224 caps->addColorFormat(COLOR_FormatSurface);
225 }
226 caps->addColorFormat(COLOR_FormatYUV420Flexible);
227 caps->addColorFormat(COLOR_FormatYUV420Planar);
228 caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
229 caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
230 caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
231 // framework video encoders must support surface format, though it is unclear
232 // that they will be able to map it if it is opaque
233 if (encoder && trait.name.find("android") != std::string::npos) {
234 caps->addColorFormat(COLOR_FormatSurface);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800235 }
236 }
237}
238
Lajos Molnar424cfb52019-04-08 17:48:00 -0700239class Switch {
240 enum Flags : uint8_t {
241 // flags
242 IS_ENABLED = (1 << 0),
243 BY_DEFAULT = (1 << 1),
244 };
245
246 constexpr Switch(uint8_t flags) : mFlags(flags) {}
247
248 uint8_t mFlags;
249
250public:
251 // have to create class due to this bool conversion operator...
252 constexpr operator bool() const {
253 return mFlags & IS_ENABLED;
254 }
255
256 constexpr Switch operator!() const {
257 return Switch(mFlags ^ IS_ENABLED);
258 }
259
260 static constexpr Switch DISABLED() { return 0; };
261 static constexpr Switch ENABLED() { return IS_ENABLED; };
262 static constexpr Switch DISABLED_BY_DEFAULT() { return BY_DEFAULT; };
263 static constexpr Switch ENABLED_BY_DEFAULT() { return IS_ENABLED | BY_DEFAULT; };
264
265 const char *toString(const char *def = "??") const {
266 switch (mFlags) {
267 case 0: return "0";
268 case IS_ENABLED: return "1";
269 case BY_DEFAULT: return "(0)";
270 case IS_ENABLED | BY_DEFAULT: return "(1)";
271 default: return def;
272 }
273 }
274
275};
276
277const char *asString(const Switch &s, const char *def = "??") {
278 return s.toString(def);
279}
280
281Switch isSettingEnabled(
282 std::string setting, const MediaCodecsXmlParser::AttributeMap &settings,
283 Switch def = Switch::DISABLED_BY_DEFAULT()) {
284 const auto enablement = settings.find(setting);
285 if (enablement == settings.end()) {
286 return def;
287 }
288 return enablement->second == "1" ? Switch::ENABLED() : Switch::DISABLED();
289}
290
291Switch isVariantEnabled(
292 std::string variant, const MediaCodecsXmlParser::AttributeMap &settings) {
293 return isSettingEnabled("variant-" + variant, settings);
294}
295
296Switch isVariantExpressionEnabled(
297 std::string exp, const MediaCodecsXmlParser::AttributeMap &settings) {
298 if (!exp.empty() && exp.at(0) == '!') {
299 return !isVariantEnabled(exp.substr(1, exp.size() - 1), settings);
300 }
301 return isVariantEnabled(exp, settings);
302}
303
304Switch isDomainEnabled(
305 std::string domain, const MediaCodecsXmlParser::AttributeMap &settings) {
306 return isSettingEnabled("domain-" + domain, settings);
307}
308
Pawin Vongmasa36653902018-11-15 00:10:25 -0800309} // unnamed namespace
310
311status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
312 // TODO: Remove run-time configurations once all codecs are working
313 // properly. (Assume "full" behavior eventually.)
314 //
315 // debug.stagefright.ccodec supports 5 values.
Lajos Molnardb5751f2019-01-31 17:01:49 -0800316 // 0 - No Codec 2.0 components are available.
Pawin Vongmasa36653902018-11-15 00:10:25 -0800317 // 1 - Audio decoders and encoders with prefix "c2.android." are available
318 // and ranked first.
319 // All other components with prefix "c2.android." are available with
320 // their normal ranks.
321 // Components with prefix "c2.vda." are available with their normal
322 // ranks.
323 // All other components with suffix ".avc.decoder" or ".avc.encoder"
324 // are available but ranked last.
325 // 2 - Components with prefix "c2.android." are available and ranked
326 // first.
327 // Components with prefix "c2.vda." are available with their normal
328 // ranks.
329 // All other components with suffix ".avc.decoder" or ".avc.encoder"
330 // are available but ranked last.
331 // 3 - Components with prefix "c2.android." are available and ranked
332 // first.
333 // All other components are available with their normal ranks.
334 // 4 - All components are available with their normal ranks.
335 //
336 // The default value (boot time) is 1.
337 //
338 // Note: Currently, OMX components have default rank 0x100, while all
339 // Codec2.0 software components have default rank 0x200.
Lajos Molnar8635fc82019-05-17 17:35:10 +0000340 int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 4);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800341
342 // Obtain Codec2Client
343 std::vector<Traits> traits = Codec2Client::ListComponents();
344
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -0800345 // parse APEX XML first, followed by vendor XML.
346 // Note: APEX XML names do not depend on ro.media.xml_variant.* properties.
Lajos Molnarda666892019-04-08 17:25:34 -0700347 MediaCodecsXmlParser parser;
348 parser.parseXmlFilesInSearchDirs(
Pawin Vongmasa7f5e10e2020-03-07 04:09:55 -0800349 { "media_codecs.xml", "media_codecs_performance.xml" },
Lajos Molnar424cfb52019-04-08 17:48:00 -0700350 { "/apex/com.android.media.swcodec/etc" });
351
352 // TODO: remove these c2-specific files once product moved to default file names
353 parser.parseXmlFilesInSearchDirs(
Lajos Molnarda666892019-04-08 17:25:34 -0700354 { "media_codecs_c2.xml", "media_codecs_performance_c2.xml" });
Lajos Molnar424cfb52019-04-08 17:48:00 -0700355
356 // parse default XML files
357 parser.parseXmlFilesInSearchDirs();
358
Ray Essick8c4e9c72021-03-15 15:25:21 -0700359 // The mainline modules for media may optionally include some codec shaping information.
360 // Based on vendor partition SDK, and the brand/product/device information
361 // (expect to be empty in almost always)
362 //
363 {
364 // get build info so we know what file to search
365 // ro.vendor.build.fingerprint
366 std::string fingerprint = base::GetProperty("ro.vendor.build.fingerprint",
367 "brand/product/device:");
368 ALOGV("property_get for ro.vendor.build.fingerprint == '%s'", fingerprint.c_str());
369
370 // ro.vendor.build.version.sdk
371 std::string sdk = base::GetProperty("ro.vendor.build.version.sdk", "0");
372 ALOGV("property_get for ro.vendor.build.version.sdk == '%s'", sdk.c_str());
373
374 std::string brand;
375 std::string product;
376 std::string device;
377 size_t pos1;
378 pos1 = fingerprint.find('/');
379 if (pos1 != std::string::npos) {
380 brand = fingerprint.substr(0, pos1);
381 size_t pos2 = fingerprint.find('/', pos1+1);
382 if (pos2 != std::string::npos) {
383 product = fingerprint.substr(pos1+1, pos2 - pos1 - 1);
384 size_t pos3 = fingerprint.find('/', pos2+1);
385 if (pos3 != std::string::npos) {
386 device = fingerprint.substr(pos2+1, pos3 - pos2 - 1);
387 size_t pos4 = device.find(':');
388 if (pos4 != std::string::npos) {
389 device.resize(pos4);
390 }
391 }
392 }
393 }
394
395 ALOGV("parsed: sdk '%s' brand '%s' product '%s' device '%s'",
396 sdk.c_str(), brand.c_str(), product.c_str(), device.c_str());
397
398 std::string base = "/apex/com.android.media/etc/formatshaper";
399
400 // looking in these directories within the apex
401 const std::vector<std::string> modulePathnames = {
402 base + "/" + sdk + "/" + brand + "/" + product + "/" + device,
403 base + "/" + sdk + "/" + brand + "/" + product,
404 base + "/" + sdk + "/" + brand,
405 base + "/" + sdk,
406 base
407 };
408
409 parser.parseXmlFilesInSearchDirs( { "media_codecs_shaping.xml" }, modulePathnames);
410 }
411
Pawin Vongmasa36653902018-11-15 00:10:25 -0800412 if (parser.getParsingStatus() != OK) {
413 ALOGD("XML parser no good");
414 return OK;
415 }
416
Lajos Molnar424cfb52019-04-08 17:48:00 -0700417 MediaCodecsXmlParser::AttributeMap settings = parser.getServiceAttributeMap();
418 for (const auto &v : settings) {
419 if (!hasPrefix(v.first, "media-type-")
420 && !hasPrefix(v.first, "domain-")
421 && !hasPrefix(v.first, "variant-")) {
422 writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
423 }
424 }
425
Pawin Vongmasa36653902018-11-15 00:10:25 -0800426 for (const Traits& trait : traits) {
427 C2Component::rank_t rank = trait.rank;
428
Lajos Molnardb5751f2019-01-31 17:01:49 -0800429 // Interface must be accessible for us to list the component, and there also
430 // must be an XML entry for the codec. Codec aliases listed in the traits
431 // allow additional XML entries to be specified for each alias. These will
432 // be listed as separate codecs. If no XML entry is specified for an alias,
433 // those will be treated as an additional alias specified in the XML entry
434 // for the interface name.
435 std::vector<std::string> nameAndAliases = trait.aliases;
436 nameAndAliases.insert(nameAndAliases.begin(), trait.name);
437 for (const std::string &nameOrAlias : nameAndAliases) {
438 bool isAlias = trait.name != nameOrAlias;
439 std::shared_ptr<Codec2Client::Interface> intf =
440 Codec2Client::CreateInterfaceByName(nameOrAlias.c_str());
441 if (!intf) {
442 ALOGD("could not create interface for %s'%s'",
443 isAlias ? "alias " : "",
444 nameOrAlias.c_str());
445 continue;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800446 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800447 if (parser.getCodecMap().count(nameOrAlias) == 0) {
448 if (isAlias) {
449 std::unique_ptr<MediaCodecInfoWriter> baseCodecInfo =
450 writer->findMediaCodecInfo(trait.name.c_str());
451 if (!baseCodecInfo) {
452 ALOGD("alias '%s' not found in xml but canonical codec info '%s' missing",
453 nameOrAlias.c_str(),
454 trait.name.c_str());
455 } else {
456 ALOGD("alias '%s' not found in xml; use an XML <Alias> tag for this",
457 nameOrAlias.c_str());
458 // merge alias into existing codec
459 baseCodecInfo->addAlias(nameOrAlias.c_str());
460 }
461 } else {
462 ALOGD("component '%s' not found in xml", trait.name.c_str());
463 }
464 continue;
465 }
466 std::string canonName = trait.name;
467
468 // TODO: Remove this block once all codecs are enabled by default.
469 switch (option) {
470 case 0:
471 continue;
472 case 1:
473 if (hasPrefix(canonName, "c2.vda.")) {
474 break;
475 }
476 if (hasPrefix(canonName, "c2.android.")) {
477 if (trait.domain == C2Component::DOMAIN_AUDIO) {
478 rank = 1;
479 break;
480 }
481 break;
482 }
483 if (hasSuffix(canonName, ".avc.decoder") ||
484 hasSuffix(canonName, ".avc.encoder")) {
485 rank = std::numeric_limits<decltype(rank)>::max();
486 break;
487 }
488 continue;
489 case 2:
490 if (hasPrefix(canonName, "c2.vda.")) {
491 break;
492 }
493 if (hasPrefix(canonName, "c2.android.")) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800494 rank = 1;
495 break;
496 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800497 if (hasSuffix(canonName, ".avc.decoder") ||
498 hasSuffix(canonName, ".avc.encoder")) {
499 rank = std::numeric_limits<decltype(rank)>::max();
500 break;
501 }
502 continue;
503 case 3:
504 if (hasPrefix(canonName, "c2.android.")) {
505 rank = 1;
506 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800507 break;
508 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800509
Lajos Molnar424cfb52019-04-08 17:48:00 -0700510 const MediaCodecsXmlParser::CodecProperties &codec =
511 parser.getCodecMap().at(nameOrAlias);
512
513 // verify that either the codec is explicitly enabled, or one of its domains is
514 bool codecEnabled = codec.quirkSet.find("attribute::disabled") == codec.quirkSet.end();
515 if (!codecEnabled) {
516 for (const std::string &domain : codec.domainSet) {
517 const Switch enabled = isDomainEnabled(domain, settings);
518 ALOGV("codec entry '%s' is in domain '%s' that is '%s'",
519 nameOrAlias.c_str(), domain.c_str(), asString(enabled));
520 if (enabled) {
521 codecEnabled = true;
522 break;
523 }
524 }
525 }
526 // if codec has variants, also check that at least one of them is enabled
527 bool variantEnabled = codec.variantSet.empty();
528 for (const std::string &variant : codec.variantSet) {
529 const Switch enabled = isVariantExpressionEnabled(variant, settings);
530 ALOGV("codec entry '%s' has a variant '%s' that is '%s'",
531 nameOrAlias.c_str(), variant.c_str(), asString(enabled));
532 if (enabled) {
533 variantEnabled = true;
534 break;
535 }
536 }
537 if (!codecEnabled || !variantEnabled) {
538 ALOGD("codec entry for '%s' is disabled", nameOrAlias.c_str());
539 continue;
540 }
541
Lajos Molnardb5751f2019-01-31 17:01:49 -0800542 ALOGV("adding codec entry for '%s'", nameOrAlias.c_str());
543 std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
544 codecInfo->setName(nameOrAlias.c_str());
545 codecInfo->setOwner(("codec2::" + trait.owner).c_str());
Lajos Molnar8d4bdfd2018-11-13 14:23:49 -0800546
Lajos Molnardb5751f2019-01-31 17:01:49 -0800547 bool encoder = trait.kind == C2Component::KIND_ENCODER;
548 typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
Lajos Molnar8d4bdfd2018-11-13 14:23:49 -0800549
Lajos Molnardb5751f2019-01-31 17:01:49 -0800550 if (encoder) {
551 attrs |= MediaCodecInfo::kFlagIsEncoder;
552 }
553 if (trait.owner == "software") {
Lajos Molnar8d4bdfd2018-11-13 14:23:49 -0800554 attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
Lajos Molnardb5751f2019-01-31 17:01:49 -0800555 } else {
556 attrs |= MediaCodecInfo::kFlagIsVendor;
557 if (trait.owner == "vendor-software") {
558 attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
559 } else if (codec.quirkSet.find("attribute::software-codec")
560 == codec.quirkSet.end()) {
561 attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800562 }
563 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800564 codecInfo->setAttributes(attrs);
565 if (!codec.rank.empty()) {
566 uint32_t xmlRank;
567 char dummy;
568 if (sscanf(codec.rank.c_str(), "%u%c", &xmlRank, &dummy) == 1) {
569 rank = xmlRank;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800570 }
571 }
Lajos Molnar424cfb52019-04-08 17:48:00 -0700572 ALOGV("rank: %u", (unsigned)rank);
Lajos Molnardb5751f2019-01-31 17:01:49 -0800573 codecInfo->setRank(rank);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800574
Lajos Molnardb5751f2019-01-31 17:01:49 -0800575 for (const std::string &alias : codec.aliases) {
576 ALOGV("adding alias '%s'", alias.c_str());
577 codecInfo->addAlias(alias.c_str());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800578 }
579
Lajos Molnardb5751f2019-01-31 17:01:49 -0800580 for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
581 const std::string &mediaType = typeIt->first;
Lajos Molnar424cfb52019-04-08 17:48:00 -0700582 const Switch typeEnabled = isSettingEnabled(
583 "media-type-" + mediaType, settings, Switch::ENABLED_BY_DEFAULT());
584 const Switch domainTypeEnabled = isSettingEnabled(
585 "media-type-" + mediaType + (encoder ? "-encoder" : "-decoder"),
586 settings, Switch::ENABLED_BY_DEFAULT());
587 ALOGV("type '%s-%s' is '%s/%s'",
588 mediaType.c_str(), (encoder ? "encoder" : "decoder"),
589 asString(typeEnabled), asString(domainTypeEnabled));
590 if (!typeEnabled || !domainTypeEnabled) {
591 ALOGD("media type '%s' for codec entry '%s' is disabled", mediaType.c_str(),
592 nameOrAlias.c_str());
593 continue;
594 }
595
596 ALOGI("adding type '%s'", typeIt->first.c_str());
Lajos Molnardb5751f2019-01-31 17:01:49 -0800597 const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
598 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
599 codecInfo->addMediaType(mediaType.c_str());
Lajos Molnar424cfb52019-04-08 17:48:00 -0700600 for (const auto &v : attrMap) {
601 std::string key = v.first;
602 std::string value = v.second;
603
604 size_t variantSep = key.find(":::");
605 if (variantSep != std::string::npos) {
606 std::string variant = key.substr(0, variantSep);
607 const Switch enabled = isVariantExpressionEnabled(variant, settings);
608 ALOGV("variant '%s' is '%s'", variant.c_str(), asString(enabled));
609 if (!enabled) {
610 continue;
611 }
612 key = key.substr(variantSep + 3);
613 }
614
Lajos Molnardb5751f2019-01-31 17:01:49 -0800615 if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
616 int32_t intValue = 0;
617 // Ignore trailing bad characters and default to 0.
618 (void)sscanf(value.c_str(), "%d", &intValue);
619 caps->addDetail(key.c_str(), intValue);
620 } else {
621 caps->addDetail(key.c_str(), value.c_str());
622 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800623 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800624
Lajos Molnar59f4a4e2021-07-09 18:23:54 -0700625 if (!addSupportedProfileLevels(intf, caps.get(), trait, mediaType)) {
626 // TODO(b/193279646) This will get fixed in C2InterfaceHelper
627 // Some components may not advertise supported values if they use a const
628 // param for profile/level (they support only one profile). For now cover
629 // only VP8 here until it is fixed.
630 if (mediaType == MIMETYPE_VIDEO_VP8) {
631 caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
632 }
633 }
Lajos Molnardb5751f2019-01-31 17:01:49 -0800634 addSupportedColorFormats(intf, caps.get(), trait, mediaType);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800635 }
636 }
637 }
638 return OK;
639}
640
641} // namespace android
642
643extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
644 return new android::Codec2InfoBuilder;
645}