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