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