• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #include <SurfaceFlingerProperties.sysprop.h>
37 
38 #include <android/hardware/media/omx/1.0/IOmx.h>
39 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
40 #include <android/hardware/media/omx/1.0/IOmxNode.h>
41 #include <android/hardware/media/omx/1.0/types.h>
42 
43 #include <android-base/properties.h>
44 #include <codec2/hidl/client.h>
45 #include <cutils/native_handle.h>
46 #include <media/omx/1.0/WOmxNode.h>
47 #include <media/stagefright/foundation/ALookup.h>
48 #include <media/stagefright/foundation/MediaDefs.h>
49 #include <media/stagefright/omx/OMXUtils.h>
50 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
51 #include <media/stagefright/Codec2InfoBuilder.h>
52 #include <media/stagefright/MediaCodecConstants.h>
53 
54 namespace android {
55 
56 using Traits = C2Component::Traits;
57 
58 // HAL pixel format -> framework color format
59 typedef std::map<uint32_t, int32_t> PixelFormatMap;
60 
61 namespace /* unnamed */ {
62 
hasPrefix(const std::string & s,const char * prefix)63 bool hasPrefix(const std::string& s, const char* prefix) {
64     size_t prefixLen = strlen(prefix);
65     return s.compare(0, prefixLen, prefix) == 0;
66 }
67 
hasSuffix(const std::string & s,const char * suffix)68 bool hasSuffix(const std::string& s, const char* suffix) {
69     size_t suffixLen = strlen(suffix);
70     return suffixLen > s.size() ? false :
71             s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
72 }
73 
findFrameworkColorFormat(const C2FlexiblePixelFormatDescriptorStruct & desc)74 std::optional<int32_t> findFrameworkColorFormat(
75         const C2FlexiblePixelFormatDescriptorStruct &desc) {
76     switch (desc.bitDepth) {
77         case 8u:
78             if (desc.layout == C2Color::PLANAR_PACKED
79                     || desc.layout == C2Color::SEMIPLANAR_PACKED) {
80                 return COLOR_FormatYUV420Flexible;
81             }
82             break;
83         case 10u:
84             if (desc.layout == C2Color::SEMIPLANAR_PACKED) {
85                 return COLOR_FormatYUVP010;
86             }
87             break;
88         default:
89             break;
90     }
91     return std::nullopt;
92 }
93 
94 // returns true if component advertised supported profile level(s)
addSupportedProfileLevels(std::shared_ptr<Codec2Client::Interface> intf,MediaCodecInfo::CapabilitiesWriter * caps,const Traits & trait,const std::string & mediaType)95 bool addSupportedProfileLevels(
96         std::shared_ptr<Codec2Client::Interface> intf,
97         MediaCodecInfo::CapabilitiesWriter *caps,
98         const Traits& trait, const std::string &mediaType) {
99     std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
100         C2Mapper::GetProfileLevelMapper(trait.mediaType);
101     // if we don't know the media type, pass through all values unmapped
102 
103     // TODO: we cannot find levels that are local 'maxima' without knowing the coding
104     // e.g. H.263 level 45 and level 30 could be two values for highest level as
105     // they don't include one another. For now we use the last supported value.
106     bool encoder = trait.kind == C2Component::KIND_ENCODER;
107     C2StreamProfileLevelInfo pl(encoder /* output */, 0u);
108     std::vector<C2FieldSupportedValuesQuery> profileQuery = {
109         C2FieldSupportedValuesQuery::Possible(C2ParamField(&pl, &pl.profile))
110     };
111 
112     c2_status_t err = intf->querySupportedValues(profileQuery, C2_DONT_BLOCK);
113     ALOGV("query supported profiles -> %s | %s", asString(err), asString(profileQuery[0].status));
114     if (err != C2_OK || profileQuery[0].status != C2_OK) {
115         return false;
116     }
117 
118     // we only handle enumerated values
119     if (profileQuery[0].values.type != C2FieldSupportedValues::VALUES) {
120         return false;
121     }
122 
123     // determine if codec supports HDR; imply 10-bit support
124     bool supportsHdr = false;
125     // determine if codec supports HDR10Plus; imply 10-bit support
126     bool supportsHdr10Plus = false;
127     // determine if codec supports 10-bit format
128     bool supports10Bit = false;
129 
130     std::vector<std::shared_ptr<C2ParamDescriptor>> paramDescs;
131     c2_status_t err1 = intf->querySupportedParams(&paramDescs);
132     if (err1 == C2_OK) {
133         for (const std::shared_ptr<C2ParamDescriptor> &desc : paramDescs) {
134             C2Param::Type type = desc->index();
135             // only consider supported parameters on raw ports
136             if (!(encoder ? type.forInput() : type.forOutput())) {
137                 continue;
138             }
139             switch (type.coreIndex()) {
140             case C2StreamHdrDynamicMetadataInfo::CORE_INDEX:
141                 [[fallthrough]];
142             case C2StreamHdr10PlusInfo::CORE_INDEX:  // will be deprecated
143                 supportsHdr10Plus = true;
144                 break;
145             case C2StreamHdrStaticInfo::CORE_INDEX:
146                 supportsHdr = true;
147                 break;
148             default:
149                 break;
150             }
151         }
152     }
153 
154     // VP9 does not support HDR metadata in the bitstream and static metadata
155     // can always be carried by the framework. (The framework does not propagate
156     // dynamic metadata as that needs to be frame accurate.)
157     supportsHdr |= (mediaType == MIMETYPE_VIDEO_VP9);
158 
159     // HDR support implies 10-bit support. AV1 codecs are also required to
160     // support 10-bit per CDD.
161     // TODO: directly check this from the component interface
162     supports10Bit = (supportsHdr || supportsHdr10Plus) || (mediaType == MIMETYPE_VIDEO_AV1);
163 
164     // If the device doesn't support HDR display, then no codec on the device
165     // can advertise support for HDR profiles.
166     // Default to true to maintain backward compatibility
167     auto ret = sysprop::SurfaceFlingerProperties::has_HDR_display();
168     bool hasHDRDisplay = ret.has_value() ? *ret : true;
169 
170     bool added = false;
171 
172     for (C2Value::Primitive profile : profileQuery[0].values.values) {
173         pl.profile = (C2Config::profile_t)profile.ref<uint32_t>();
174         std::vector<std::unique_ptr<C2SettingResult>> failures;
175         err = intf->config({&pl}, C2_DONT_BLOCK, &failures);
176         ALOGV("set profile to %u -> %s", pl.profile, asString(err));
177         std::vector<C2FieldSupportedValuesQuery> levelQuery = {
178             C2FieldSupportedValuesQuery::Current(C2ParamField(&pl, &pl.level))
179         };
180         err = intf->querySupportedValues(levelQuery, C2_DONT_BLOCK);
181         ALOGV("query supported levels -> %s | %s", asString(err), asString(levelQuery[0].status));
182         if (err != C2_OK || levelQuery[0].status != C2_OK
183                 || levelQuery[0].values.type != C2FieldSupportedValues::VALUES
184                 || levelQuery[0].values.values.size() == 0) {
185             continue;
186         }
187 
188         C2Value::Primitive level = levelQuery[0].values.values.back();
189         pl.level = (C2Config::level_t)level.ref<uint32_t>();
190         ALOGV("supporting level: %u", pl.level);
191         int32_t sdkProfile, sdkLevel;
192         if (mapper && mapper->mapProfile(pl.profile, &sdkProfile)
193                 && mapper->mapLevel(pl.level, &sdkLevel)) {
194             caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
195             // also list HDR profiles if component supports HDR and device has HDR display
196             if (supportsHdr && hasHDRDisplay) {
197                 auto hdrMapper = C2Mapper::GetHdrProfileLevelMapper(trait.mediaType);
198                 if (hdrMapper && hdrMapper->mapProfile(pl.profile, &sdkProfile)) {
199                     caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
200                 }
201                 if (supportsHdr10Plus) {
202                     hdrMapper = C2Mapper::GetHdrProfileLevelMapper(
203                             trait.mediaType, true /*isHdr10Plus*/);
204                     if (hdrMapper && hdrMapper->mapProfile(pl.profile, &sdkProfile)) {
205                         caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
206                     }
207                 }
208             }
209             if (supports10Bit) {
210                 auto bitnessMapper = C2Mapper::GetBitDepthProfileLevelMapper(trait.mediaType, 10);
211                 if (bitnessMapper && bitnessMapper->mapProfile(pl.profile, &sdkProfile)) {
212                     caps->addProfileLevel((uint32_t)sdkProfile, (uint32_t)sdkLevel);
213                 }
214             }
215         } else if (!mapper) {
216             caps->addProfileLevel(pl.profile, pl.level);
217         }
218         added = true;
219 
220         // for H.263 also advertise the second highest level if the
221         // codec supports level 45, as level 45 only covers level 10
222         // TODO: move this to some form of a setting so it does not
223         // have to be here
224         if (mediaType == MIMETYPE_VIDEO_H263) {
225             C2Config::level_t nextLevel = C2Config::LEVEL_UNUSED;
226             for (C2Value::Primitive v : levelQuery[0].values.values) {
227                 C2Config::level_t level = (C2Config::level_t)v.ref<uint32_t>();
228                 if (level < C2Config::LEVEL_H263_45 && level > nextLevel) {
229                     nextLevel = level;
230                 }
231             }
232             if (nextLevel != C2Config::LEVEL_UNUSED
233                     && nextLevel != pl.level
234                     && mapper
235                     && mapper->mapProfile(pl.profile, &sdkProfile)
236                     && mapper->mapLevel(nextLevel, &sdkLevel)) {
237                 caps->addProfileLevel(
238                         (uint32_t)sdkProfile, (uint32_t)sdkLevel);
239             }
240         }
241     }
242     return added;
243 }
244 
addSupportedColorFormats(std::shared_ptr<Codec2Client::Interface> intf,MediaCodecInfo::CapabilitiesWriter * caps,const Traits & trait,const std::string & mediaType,const PixelFormatMap & pixelFormatMap)245 void addSupportedColorFormats(
246         std::shared_ptr<Codec2Client::Interface> intf,
247         MediaCodecInfo::CapabilitiesWriter *caps,
248         const Traits& trait, const std::string &mediaType,
249         const PixelFormatMap &pixelFormatMap) {
250     // TODO: get this from intf() as well, but how do we map them to
251     // MediaCodec color formats?
252     bool encoder = trait.kind == C2Component::KIND_ENCODER;
253     if (mediaType.find("video") != std::string::npos
254             || mediaType.find("image") != std::string::npos) {
255 
256         std::vector<C2FieldSupportedValuesQuery> query;
257         if (encoder) {
258             C2StreamPixelFormatInfo::input pixelFormat;
259             query.push_back(C2FieldSupportedValuesQuery::Possible(
260                     C2ParamField::Make(pixelFormat, pixelFormat.value)));
261         } else {
262             C2StreamPixelFormatInfo::output pixelFormat;
263             query.push_back(C2FieldSupportedValuesQuery::Possible(
264                     C2ParamField::Make(pixelFormat, pixelFormat.value)));
265         }
266         std::list<int32_t> supportedColorFormats;
267         if (intf->querySupportedValues(query, C2_DONT_BLOCK) == C2_OK) {
268             if (query[0].status == C2_OK) {
269                 const C2FieldSupportedValues &fsv = query[0].values;
270                 if (fsv.type == C2FieldSupportedValues::VALUES) {
271                     for (C2Value::Primitive value : fsv.values) {
272                         auto it = pixelFormatMap.find(value.u32);
273                         if (it != pixelFormatMap.end()) {
274                             auto it2 = std::find(
275                                     supportedColorFormats.begin(),
276                                     supportedColorFormats.end(),
277                                     it->second);
278                             if (it2 == supportedColorFormats.end()) {
279                                 supportedColorFormats.push_back(it->second);
280                             }
281                         }
282                     }
283                 }
284             }
285         }
286         auto addDefaultColorFormat = [caps, &supportedColorFormats](int32_t colorFormat) {
287             caps->addColorFormat(colorFormat);
288             auto it = std::find(
289                     supportedColorFormats.begin(), supportedColorFormats.end(), colorFormat);
290             if (it != supportedColorFormats.end()) {
291                 supportedColorFormats.erase(it);
292             }
293         };
294 
295         // The color format is ordered by preference. The intention here is to advertise:
296         //   c2.android.* codecs: YUV420s, Surface, <the rest>
297         //   all other codecs:    Surface, YUV420s, <the rest>
298         // TODO: get this preference via Codec2 API
299 
300         // vendor video codecs prefer opaque format
301         if (trait.name.find("android") == std::string::npos) {
302             addDefaultColorFormat(COLOR_FormatSurface);
303         }
304         addDefaultColorFormat(COLOR_FormatYUV420Flexible);
305         addDefaultColorFormat(COLOR_FormatYUV420Planar);
306         addDefaultColorFormat(COLOR_FormatYUV420SemiPlanar);
307         addDefaultColorFormat(COLOR_FormatYUV420PackedPlanar);
308         addDefaultColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
309         // Android video codecs prefer CPU-readable formats
310         if (trait.name.find("android") != std::string::npos) {
311             addDefaultColorFormat(COLOR_FormatSurface);
312         }
313 
314         static const int kVendorSdkVersion = ::android::base::GetIntProperty(
315                 "ro.vendor.build.version.sdk", android_get_device_api_level());
316         if (kVendorSdkVersion >= __ANDROID_API_T__) {
317             for (int32_t colorFormat : supportedColorFormats) {
318                 caps->addColorFormat(colorFormat);
319             }
320         }
321     }
322 }
323 
324 class Switch {
325     enum Flags : uint8_t {
326         // flags
327         IS_ENABLED = (1 << 0),
328         BY_DEFAULT = (1 << 1),
329     };
330 
Switch(uint8_t flags)331     constexpr Switch(uint8_t flags) : mFlags(flags) {}
332 
333     uint8_t mFlags;
334 
335 public:
336     // have to create class due to this bool conversion operator...
operator bool() const337     constexpr operator bool() const {
338         return mFlags & IS_ENABLED;
339     }
340 
operator !() const341     constexpr Switch operator!() const {
342         return Switch(mFlags ^ IS_ENABLED);
343     }
344 
DISABLED()345     static constexpr Switch DISABLED() { return 0; };
ENABLED()346     static constexpr Switch ENABLED() { return IS_ENABLED; };
DISABLED_BY_DEFAULT()347     static constexpr Switch DISABLED_BY_DEFAULT() { return BY_DEFAULT; };
ENABLED_BY_DEFAULT()348     static constexpr Switch ENABLED_BY_DEFAULT() { return IS_ENABLED | BY_DEFAULT; };
349 
toString(const char * def="??") const350     const char *toString(const char *def = "??") const {
351         switch (mFlags) {
352         case 0:                         return "0";
353         case IS_ENABLED:                return "1";
354         case BY_DEFAULT:                return "(0)";
355         case IS_ENABLED | BY_DEFAULT:   return "(1)";
356         default: return def;
357         }
358     }
359 
360 };
361 
asString(const Switch & s,const char * def="??")362 const char *asString(const Switch &s, const char *def = "??") {
363     return s.toString(def);
364 }
365 
isSettingEnabled(std::string setting,const MediaCodecsXmlParser::AttributeMap & settings,Switch def=Switch::DISABLED_BY_DEFAULT ())366 Switch isSettingEnabled(
367         std::string setting, const MediaCodecsXmlParser::AttributeMap &settings,
368         Switch def = Switch::DISABLED_BY_DEFAULT()) {
369     const auto enablement = settings.find(setting);
370     if (enablement == settings.end()) {
371         return def;
372     }
373     return enablement->second == "1" ? Switch::ENABLED() : Switch::DISABLED();
374 }
375 
isVariantEnabled(std::string variant,const MediaCodecsXmlParser::AttributeMap & settings)376 Switch isVariantEnabled(
377         std::string variant, const MediaCodecsXmlParser::AttributeMap &settings) {
378     return isSettingEnabled("variant-" + variant, settings);
379 }
380 
isVariantExpressionEnabled(std::string exp,const MediaCodecsXmlParser::AttributeMap & settings)381 Switch isVariantExpressionEnabled(
382         std::string exp, const MediaCodecsXmlParser::AttributeMap &settings) {
383     if (!exp.empty() && exp.at(0) == '!') {
384         return !isVariantEnabled(exp.substr(1, exp.size() - 1), settings);
385     }
386     return isVariantEnabled(exp, settings);
387 }
388 
isDomainEnabled(std::string domain,const MediaCodecsXmlParser::AttributeMap & settings)389 Switch isDomainEnabled(
390         std::string domain, const MediaCodecsXmlParser::AttributeMap &settings) {
391     return isSettingEnabled("domain-" + domain, settings);
392 }
393 
394 } // unnamed namespace
395 
buildMediaCodecList(MediaCodecListWriter * writer)396 status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
397     // TODO: Remove run-time configurations once all codecs are working
398     // properly. (Assume "full" behavior eventually.)
399     //
400     // debug.stagefright.ccodec supports 5 values.
401     //   0 - No Codec 2.0 components are available.
402     //   1 - Audio decoders and encoders with prefix "c2.android." are available
403     //       and ranked first.
404     //       All other components with prefix "c2.android." are available with
405     //       their normal ranks.
406     //       Components with prefix "c2.vda." are available with their normal
407     //       ranks.
408     //       All other components with suffix ".avc.decoder" or ".avc.encoder"
409     //       are available but ranked last.
410     //   2 - Components with prefix "c2.android." are available and ranked
411     //       first.
412     //       Components with prefix "c2.vda." are available with their normal
413     //       ranks.
414     //       All other components with suffix ".avc.decoder" or ".avc.encoder"
415     //       are available but ranked last.
416     //   3 - Components with prefix "c2.android." are available and ranked
417     //       first.
418     //       All other components are available with their normal ranks.
419     //   4 - All components are available with their normal ranks.
420     //
421     // The default value (boot time) is 1.
422     //
423     // Note: Currently, OMX components have default rank 0x100, while all
424     // Codec2.0 software components have default rank 0x200.
425     int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 4);
426 
427     // Obtain Codec2Client
428     std::vector<Traits> traits = Codec2Client::ListComponents();
429 
430     // parse APEX XML first, followed by vendor XML.
431     // Note: APEX XML names do not depend on ro.media.xml_variant.* properties.
432     MediaCodecsXmlParser parser;
433     parser.parseXmlFilesInSearchDirs(
434             { "media_codecs.xml", "media_codecs_performance.xml" },
435             { "/apex/com.android.media.swcodec/etc" });
436 
437     // TODO: remove these c2-specific files once product moved to default file names
438     parser.parseXmlFilesInSearchDirs(
439             { "media_codecs_c2.xml", "media_codecs_performance_c2.xml" });
440 
441     // parse default XML files
442     parser.parseXmlFilesInSearchDirs();
443 
444     // The mainline modules for media may optionally include some codec shaping information.
445     // Based on vendor partition SDK, and the brand/product/device information
446     // (expect to be empty in almost always)
447     //
448     {
449         // get build info so we know what file to search
450         // ro.vendor.build.fingerprint
451         std::string fingerprint = base::GetProperty("ro.vendor.build.fingerprint",
452                                                "brand/product/device:");
453         ALOGV("property_get for ro.vendor.build.fingerprint == '%s'", fingerprint.c_str());
454 
455         // ro.vendor.build.version.sdk
456         std::string sdk = base::GetProperty("ro.vendor.build.version.sdk", "0");
457         ALOGV("property_get for ro.vendor.build.version.sdk == '%s'", sdk.c_str());
458 
459         std::string brand;
460         std::string product;
461         std::string device;
462         size_t pos1;
463         pos1 = fingerprint.find('/');
464         if (pos1 != std::string::npos) {
465             brand = fingerprint.substr(0, pos1);
466             size_t pos2 = fingerprint.find('/', pos1+1);
467             if (pos2 != std::string::npos) {
468                 product = fingerprint.substr(pos1+1, pos2 - pos1 - 1);
469                 size_t pos3 = fingerprint.find('/', pos2+1);
470                 if (pos3 != std::string::npos) {
471                     device = fingerprint.substr(pos2+1, pos3 - pos2 - 1);
472                     size_t pos4 = device.find(':');
473                     if (pos4 != std::string::npos) {
474                         device.resize(pos4);
475                     }
476                 }
477             }
478         }
479 
480         ALOGV("parsed: sdk '%s' brand '%s' product '%s' device '%s'",
481             sdk.c_str(), brand.c_str(), product.c_str(), device.c_str());
482 
483         std::string base = "/apex/com.android.media/etc/formatshaper";
484 
485         // looking in these directories within the apex
486         const std::vector<std::string> modulePathnames = {
487             base + "/" + sdk + "/" + brand + "/" + product + "/" + device,
488             base + "/" + sdk + "/" + brand + "/" + product,
489             base + "/" + sdk + "/" + brand,
490             base + "/" + sdk,
491             base
492         };
493 
494         parser.parseXmlFilesInSearchDirs( { "media_codecs_shaping.xml" }, modulePathnames);
495     }
496 
497     if (parser.getParsingStatus() != OK) {
498         ALOGD("XML parser no good");
499         return OK;
500     }
501 
502     MediaCodecsXmlParser::AttributeMap settings = parser.getServiceAttributeMap();
503     for (const auto &v : settings) {
504         if (!hasPrefix(v.first, "media-type-")
505                 && !hasPrefix(v.first, "domain-")
506                 && !hasPrefix(v.first, "variant-")) {
507             writer->addGlobalSetting(v.first.c_str(), v.second.c_str());
508         }
509     }
510 
511     std::map<std::string, PixelFormatMap> nameToPixelFormatMap;
512     for (const Traits& trait : traits) {
513         C2Component::rank_t rank = trait.rank;
514 
515         // Interface must be accessible for us to list the component, and there also
516         // must be an XML entry for the codec. Codec aliases listed in the traits
517         // allow additional XML entries to be specified for each alias. These will
518         // be listed as separate codecs. If no XML entry is specified for an alias,
519         // those will be treated as an additional alias specified in the XML entry
520         // for the interface name.
521         std::vector<std::string> nameAndAliases = trait.aliases;
522         nameAndAliases.insert(nameAndAliases.begin(), trait.name);
523         for (const std::string &nameOrAlias : nameAndAliases) {
524             bool isAlias = trait.name != nameOrAlias;
525             std::shared_ptr<Codec2Client> client;
526             std::shared_ptr<Codec2Client::Interface> intf =
527                 Codec2Client::CreateInterfaceByName(nameOrAlias.c_str(), &client);
528             if (!intf) {
529                 ALOGD("could not create interface for %s'%s'",
530                         isAlias ? "alias " : "",
531                         nameOrAlias.c_str());
532                 continue;
533             }
534             if (parser.getCodecMap().count(nameOrAlias) == 0) {
535                 if (isAlias) {
536                     std::unique_ptr<MediaCodecInfoWriter> baseCodecInfo =
537                         writer->findMediaCodecInfo(trait.name.c_str());
538                     if (!baseCodecInfo) {
539                         ALOGD("alias '%s' not found in xml but canonical codec info '%s' missing",
540                                 nameOrAlias.c_str(),
541                                 trait.name.c_str());
542                     } else {
543                         ALOGD("alias '%s' not found in xml; use an XML <Alias> tag for this",
544                                 nameOrAlias.c_str());
545                         // merge alias into existing codec
546                         baseCodecInfo->addAlias(nameOrAlias.c_str());
547                     }
548                 } else {
549                     ALOGD("component '%s' not found in xml", trait.name.c_str());
550                 }
551                 continue;
552             }
553             std::string canonName = trait.name;
554 
555             // TODO: Remove this block once all codecs are enabled by default.
556             switch (option) {
557             case 0:
558                 continue;
559             case 1:
560                 if (hasPrefix(canonName, "c2.vda.")) {
561                     break;
562                 }
563                 if (hasPrefix(canonName, "c2.android.")) {
564                     if (trait.domain == C2Component::DOMAIN_AUDIO) {
565                         rank = 1;
566                         break;
567                     }
568                     break;
569                 }
570                 if (hasSuffix(canonName, ".avc.decoder") ||
571                         hasSuffix(canonName, ".avc.encoder")) {
572                     rank = std::numeric_limits<decltype(rank)>::max();
573                     break;
574                 }
575                 continue;
576             case 2:
577                 if (hasPrefix(canonName, "c2.vda.")) {
578                     break;
579                 }
580                 if (hasPrefix(canonName, "c2.android.")) {
581                     rank = 1;
582                     break;
583                 }
584                 if (hasSuffix(canonName, ".avc.decoder") ||
585                         hasSuffix(canonName, ".avc.encoder")) {
586                     rank = std::numeric_limits<decltype(rank)>::max();
587                     break;
588                 }
589                 continue;
590             case 3:
591                 if (hasPrefix(canonName, "c2.android.")) {
592                     rank = 1;
593                 }
594                 break;
595             }
596 
597             const MediaCodecsXmlParser::CodecProperties &codec =
598                 parser.getCodecMap().at(nameOrAlias);
599 
600             // verify that either the codec is explicitly enabled, or one of its domains is
601             bool codecEnabled = codec.quirkSet.find("attribute::disabled") == codec.quirkSet.end();
602             if (!codecEnabled) {
603                 for (const std::string &domain : codec.domainSet) {
604                     const Switch enabled = isDomainEnabled(domain, settings);
605                     ALOGV("codec entry '%s' is in domain '%s' that is '%s'",
606                             nameOrAlias.c_str(), domain.c_str(), asString(enabled));
607                     if (enabled) {
608                         codecEnabled = true;
609                         break;
610                     }
611                 }
612             }
613             // if codec has variants, also check that at least one of them is enabled
614             bool variantEnabled = codec.variantSet.empty();
615             for (const std::string &variant : codec.variantSet) {
616                 const Switch enabled = isVariantExpressionEnabled(variant, settings);
617                 ALOGV("codec entry '%s' has a variant '%s' that is '%s'",
618                         nameOrAlias.c_str(), variant.c_str(), asString(enabled));
619                 if (enabled) {
620                     variantEnabled = true;
621                     break;
622                 }
623             }
624             if (!codecEnabled || !variantEnabled) {
625                 ALOGD("codec entry for '%s' is disabled", nameOrAlias.c_str());
626                 continue;
627             }
628 
629             ALOGV("adding codec entry for '%s'", nameOrAlias.c_str());
630             std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
631             codecInfo->setName(nameOrAlias.c_str());
632             codecInfo->setOwner(("codec2::" + trait.owner).c_str());
633 
634             bool encoder = trait.kind == C2Component::KIND_ENCODER;
635             typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
636 
637             if (encoder) {
638                 attrs |= MediaCodecInfo::kFlagIsEncoder;
639             }
640             if (trait.owner == "software") {
641                 attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
642             } else {
643                 attrs |= MediaCodecInfo::kFlagIsVendor;
644                 if (trait.owner == "vendor-software") {
645                     attrs |= MediaCodecInfo::kFlagIsSoftwareOnly;
646                 } else if (codec.quirkSet.find("attribute::software-codec")
647                         == codec.quirkSet.end()) {
648                     attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
649                 }
650             }
651             codecInfo->setAttributes(attrs);
652             if (!codec.rank.empty()) {
653                 uint32_t xmlRank;
654                 char dummy;
655                 if (sscanf(codec.rank.c_str(), "%u%c", &xmlRank, &dummy) == 1) {
656                     rank = xmlRank;
657                 }
658             }
659             ALOGV("rank: %u", (unsigned)rank);
660             codecInfo->setRank(rank);
661 
662             for (const std::string &alias : codec.aliases) {
663                 ALOGV("adding alias '%s'", alias.c_str());
664                 codecInfo->addAlias(alias.c_str());
665             }
666 
667             for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
668                 const std::string &mediaType = typeIt->first;
669                 const Switch typeEnabled = isSettingEnabled(
670                         "media-type-" + mediaType, settings, Switch::ENABLED_BY_DEFAULT());
671                 const Switch domainTypeEnabled = isSettingEnabled(
672                         "media-type-" + mediaType + (encoder ? "-encoder" : "-decoder"),
673                         settings, Switch::ENABLED_BY_DEFAULT());
674                 ALOGV("type '%s-%s' is '%s/%s'",
675                         mediaType.c_str(), (encoder ? "encoder" : "decoder"),
676                         asString(typeEnabled), asString(domainTypeEnabled));
677                 if (!typeEnabled || !domainTypeEnabled) {
678                     ALOGD("media type '%s' for codec entry '%s' is disabled", mediaType.c_str(),
679                             nameOrAlias.c_str());
680                     continue;
681                 }
682 
683                 ALOGI("adding type '%s'", typeIt->first.c_str());
684                 const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
685                 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
686                     codecInfo->addMediaType(mediaType.c_str());
687                 for (const auto &v : attrMap) {
688                     std::string key = v.first;
689                     std::string value = v.second;
690 
691                     size_t variantSep = key.find(":::");
692                     if (variantSep != std::string::npos) {
693                         std::string variant = key.substr(0, variantSep);
694                         const Switch enabled = isVariantExpressionEnabled(variant, settings);
695                         ALOGV("variant '%s' is '%s'", variant.c_str(), asString(enabled));
696                         if (!enabled) {
697                             continue;
698                         }
699                         key = key.substr(variantSep + 3);
700                     }
701 
702                     if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
703                         int32_t intValue = 0;
704                         // Ignore trailing bad characters and default to 0.
705                         (void)sscanf(value.c_str(), "%d", &intValue);
706                         caps->addDetail(key.c_str(), intValue);
707                     } else {
708                         caps->addDetail(key.c_str(), value.c_str());
709                     }
710                 }
711 
712                 if (!addSupportedProfileLevels(intf, caps.get(), trait, mediaType)) {
713                     // TODO(b/193279646) This will get fixed in C2InterfaceHelper
714                     // Some components may not advertise supported values if they use a const
715                     // param for profile/level (they support only one profile). For now cover
716                     // only VP8 here until it is fixed.
717                     if (mediaType == MIMETYPE_VIDEO_VP8) {
718                         caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
719                     }
720                 }
721 
722                 auto it = nameToPixelFormatMap.find(client->getServiceName());
723                 if (it == nameToPixelFormatMap.end()) {
724                     it = nameToPixelFormatMap.try_emplace(client->getServiceName()).first;
725                     PixelFormatMap &pixelFormatMap = it->second;
726                     pixelFormatMap[HAL_PIXEL_FORMAT_YCBCR_420_888] = COLOR_FormatYUV420Flexible;
727                     pixelFormatMap[HAL_PIXEL_FORMAT_YCBCR_P010]    = COLOR_FormatYUVP010;
728                     pixelFormatMap[HAL_PIXEL_FORMAT_RGBA_1010102]  = COLOR_Format32bitABGR2101010;
729                     pixelFormatMap[HAL_PIXEL_FORMAT_RGBA_FP16]     = COLOR_Format64bitABGRFloat;
730 
731                     std::shared_ptr<C2StoreFlexiblePixelFormatDescriptorsInfo> pixelFormatInfo;
732                     std::vector<std::unique_ptr<C2Param>> heapParams;
733                     if (client->query(
734                                 {},
735                                 {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
736                                 C2_MAY_BLOCK,
737                                 &heapParams) == C2_OK
738                             && heapParams.size() == 1u) {
739                         pixelFormatInfo.reset(C2StoreFlexiblePixelFormatDescriptorsInfo::From(
740                                 heapParams[0].release()));
741                     }
742                     if (pixelFormatInfo && *pixelFormatInfo) {
743                         for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
744                             C2FlexiblePixelFormatDescriptorStruct &desc =
745                                 pixelFormatInfo->m.values[i];
746                             std::optional<int32_t> colorFormat = findFrameworkColorFormat(desc);
747                             if (colorFormat) {
748                                 pixelFormatMap[desc.pixelFormat] = *colorFormat;
749                             }
750                         }
751                     }
752                 }
753                 addSupportedColorFormats(
754                         intf, caps.get(), trait, mediaType, it->second);
755             }
756         }
757     }
758     return OK;
759 }
760 
761 }  // namespace android
762 
CreateBuilder()763 extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
764     return new android::Codec2InfoBuilder;
765 }
766