Home | History | Annotate | Download | only in sfplugin
      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 <codec2/hidl/client.h>
     22 
     23 #include <C2Component.h>
     24 #include <C2Config.h>
     25 #include <C2Debug.h>
     26 #include <C2PlatformSupport.h>
     27 #include <C2V4l2Support.h>
     28 #include <Codec2Mapper.h>
     29 
     30 #include <android-base/properties.h>
     31 #include <media/stagefright/MediaCodecConstants.h>
     32 #include <media/stagefright/foundation/MediaDefs.h>
     33 #include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
     34 
     35 #include "Codec2InfoBuilder.h"
     36 
     37 namespace android {
     38 
     39 using Traits = C2Component::Traits;
     40 
     41 namespace /* unnamed */ {
     42 
     43 bool hasPrefix(const std::string& s, const char* prefix) {
     44     size_t prefixLen = strlen(prefix);
     45     return s.compare(0, prefixLen, prefix) == 0;
     46 }
     47 
     48 bool hasSuffix(const std::string& s, const char* suffix) {
     49     size_t suffixLen = strlen(suffix);
     50     return suffixLen > s.size() ? false :
     51             s.compare(s.size() - suffixLen, suffixLen, suffix) == 0;
     52 }
     53 
     54 } // unnamed namespace
     55 
     56 status_t Codec2InfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
     57     // TODO: Remove run-time configurations once all codecs are working
     58     // properly. (Assume "full" behavior eventually.)
     59     //
     60     // debug.stagefright.ccodec supports 5 values.
     61     //   0 - Only OMX components are available.
     62     //   1 - Codec2.0 software audio decoders/encoders are available and
     63     //       ranked 1st.
     64     //       Components with "c2.vda." prefix are available with their normal
     65     //       ranks.
     66     //       Other components with ".avc.decoder" or ".avc.encoder" suffix are
     67     //       available, but ranked last.
     68     //   2 - All Codec2.0 components are available.
     69     //       Codec2.0 software audio decoders are ranked 1st.
     70     //       The other Codec2.0 components have their normal ranks.
     71     //   3 - All Codec2.0 components are available.
     72     //       Codec2.0 software components are ranked 1st.
     73     //       The other Codec2.0 components have their normal ranks.
     74     //   4 - All Codec2.0 components are available with their normal ranks.
     75     //
     76     // The default value (boot time) is 1.
     77     //
     78     // Note: Currently, OMX components have default rank 0x100, while all
     79     // Codec2.0 software components have default rank 0x200.
     80     int option = ::android::base::GetIntProperty("debug.stagefright.ccodec", 1);
     81 
     82     // Obtain Codec2Client
     83     std::vector<Traits> traits = Codec2Client::ListComponents();
     84 
     85     MediaCodecsXmlParser parser(
     86             MediaCodecsXmlParser::defaultSearchDirs,
     87             "media_codecs_c2.xml");
     88     if (parser.getParsingStatus() != OK) {
     89         ALOGD("XML parser no good");
     90         return OK;
     91     }
     92     for (const Traits& trait : traits) {
     93         if (parser.getCodecMap().count(trait.name.c_str()) == 0) {
     94             ALOGD("%s not found in xml", trait.name.c_str());
     95             continue;
     96         }
     97 
     98         // TODO: Remove this block once all codecs are enabled by default.
     99         C2Component::rank_t rank = trait.rank;
    100         switch (option) {
    101         case 0:
    102             continue;
    103         case 1:
    104             if (hasPrefix(trait.name, "c2.vda.")) {
    105                 break;
    106             }
    107             if (hasPrefix(trait.name, "c2.android.")) {
    108                 if (trait.domain == C2Component::DOMAIN_AUDIO) {
    109                     rank = 1;
    110                     break;
    111                 }
    112                 continue;
    113             }
    114             if (hasSuffix(trait.name, ".avc.decoder") ||
    115                     hasSuffix(trait.name, ".avc.encoder")) {
    116                 rank = std::numeric_limits<decltype(rank)>::max();
    117                 break;
    118             }
    119             continue;
    120         case 2:
    121             if (trait.domain == C2Component::DOMAIN_AUDIO &&
    122                     trait.kind == C2Component::KIND_DECODER) {
    123         case 3:
    124                 if (hasPrefix(trait.name, "c2.android.")) {
    125                     rank = 1;
    126                 }
    127             }
    128             break;
    129         }
    130 
    131         const MediaCodecsXmlParser::CodecProperties &codec = parser.getCodecMap().at(trait.name);
    132         std::unique_ptr<MediaCodecInfoWriter> codecInfo = writer->addMediaCodecInfo();
    133         codecInfo->setName(trait.name.c_str());
    134         codecInfo->setOwner("dummy");
    135         // TODO: get this from trait.kind
    136         bool encoder = (trait.name.find("encoder") != std::string::npos);
    137         codecInfo->setEncoder(encoder);
    138         codecInfo->setRank(rank);
    139         for (auto typeIt = codec.typeMap.begin(); typeIt != codec.typeMap.end(); ++typeIt) {
    140             const std::string &mediaType = typeIt->first;
    141             const MediaCodecsXmlParser::AttributeMap &attrMap = typeIt->second;
    142             std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
    143                 codecInfo->addMime(mediaType.c_str());
    144             for (auto attrIt = attrMap.begin(); attrIt != attrMap.end(); ++attrIt) {
    145                 std::string key, value;
    146                 std::tie(key, value) = *attrIt;
    147                 if (key.find("feature-") == 0 && key.find("feature-bitrate-modes") != 0) {
    148                     caps->addDetail(key.c_str(), std::stoi(value));
    149                 } else {
    150                     caps->addDetail(key.c_str(), value.c_str());
    151                 }
    152             }
    153 
    154             bool gotProfileLevels = false;
    155             std::shared_ptr<Codec2Client::Interface> intf =
    156                 Codec2Client::CreateInterfaceByName(trait.name.c_str());
    157             if (intf) {
    158                 std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
    159                     C2Mapper::GetProfileLevelMapper(trait.mediaType);
    160                 // if we don't know the media type, pass through all values unmapped
    161 
    162                 // TODO: we cannot find levels that are local 'maxima' without knowing the coding
    163                 // e.g. H.263 level 45 and level 30 could be two values for highest level as
    164                 // they don't include one another. For now we use the last supported value.
    165                 C2StreamProfileLevelInfo pl(encoder /* output */, 0u);
    166                 std::vector<C2FieldSupportedValuesQuery> profileQuery = {
    167                     C2FieldSupportedValuesQuery::Possible(C2ParamField(&pl, &pl.profile))
    168                 };
    169 
    170                 c2_status_t err = intf->querySupportedValues(profileQuery, C2_DONT_BLOCK);
    171                 ALOGV("query supported profiles -> %s | %s",
    172                         asString(err), asString(profileQuery[0].status));
    173                 if (err == C2_OK && profileQuery[0].status == C2_OK) {
    174                     if (profileQuery[0].values.type == C2FieldSupportedValues::VALUES) {
    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",
    185                                     asString(err), asString(levelQuery[0].status));
    186                             if (err == C2_OK && levelQuery[0].status == C2_OK) {
    187                                 if (levelQuery[0].values.type == C2FieldSupportedValues::VALUES
    188                                         && levelQuery[0].values.values.size() > 0) {
    189                                     C2Value::Primitive level = levelQuery[0].values.values.back();
    190                                     pl.level = (C2Config::level_t)level.ref<uint32_t>();
    191                                     ALOGV("supporting level: %u", pl.level);
    192                                     int32_t sdkProfile, sdkLevel;
    193                                     if (mapper && mapper->mapProfile(pl.profile, &sdkProfile)
    194                                             && mapper->mapLevel(pl.level, &sdkLevel)) {
    195                                         caps->addProfileLevel(
    196                                                 (uint32_t)sdkProfile, (uint32_t)sdkLevel);
    197                                         gotProfileLevels = true;
    198                                     } else if (!mapper) {
    199                                         caps->addProfileLevel(pl.profile, pl.level);
    200                                         gotProfileLevels = true;
    201                                     }
    202                                 }
    203                             }
    204                         }
    205                     }
    206                 }
    207             }
    208 
    209             if (!gotProfileLevels) {
    210                 if (mediaType == MIMETYPE_VIDEO_VP9) {
    211                     if (encoder) {
    212                         caps->addProfileLevel(VP9Profile0,    VP9Level41);
    213                     } else {
    214                         caps->addProfileLevel(VP9Profile0,    VP9Level5);
    215                         caps->addProfileLevel(VP9Profile2,    VP9Level5);
    216                         caps->addProfileLevel(VP9Profile2HDR, VP9Level5);
    217                     }
    218                 } else if (mediaType == MIMETYPE_VIDEO_HEVC && !encoder) {
    219                     caps->addProfileLevel(HEVCProfileMain,      HEVCMainTierLevel51);
    220                     caps->addProfileLevel(HEVCProfileMainStill, HEVCMainTierLevel51);
    221                 } else if (mediaType == MIMETYPE_VIDEO_VP8) {
    222                     if (encoder) {
    223                         caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
    224                     } else {
    225                         caps->addProfileLevel(VP8ProfileMain, VP8Level_Version0);
    226                     }
    227                 } else if (mediaType == MIMETYPE_VIDEO_AVC) {
    228                     if (encoder) {
    229                         caps->addProfileLevel(AVCProfileBaseline,            AVCLevel41);
    230 //                      caps->addProfileLevel(AVCProfileConstrainedBaseline, AVCLevel41);
    231                         caps->addProfileLevel(AVCProfileMain,                AVCLevel41);
    232                     } else {
    233                         caps->addProfileLevel(AVCProfileBaseline,            AVCLevel52);
    234                         caps->addProfileLevel(AVCProfileConstrainedBaseline, AVCLevel52);
    235                         caps->addProfileLevel(AVCProfileMain,                AVCLevel52);
    236                         caps->addProfileLevel(AVCProfileConstrainedHigh,     AVCLevel52);
    237                         caps->addProfileLevel(AVCProfileHigh,                AVCLevel52);
    238                     }
    239                 } else if (mediaType == MIMETYPE_VIDEO_MPEG4) {
    240                     if (encoder) {
    241                         caps->addProfileLevel(MPEG4ProfileSimple,  MPEG4Level2);
    242                     } else {
    243                         caps->addProfileLevel(MPEG4ProfileSimple,  MPEG4Level3);
    244                     }
    245                 } else if (mediaType == MIMETYPE_VIDEO_H263) {
    246                     if (encoder) {
    247                         caps->addProfileLevel(H263ProfileBaseline, H263Level45);
    248                     } else {
    249                         caps->addProfileLevel(H263ProfileBaseline, H263Level30);
    250                         caps->addProfileLevel(H263ProfileBaseline, H263Level45);
    251                         caps->addProfileLevel(H263ProfileISWV2,    H263Level30);
    252                         caps->addProfileLevel(H263ProfileISWV2,    H263Level45);
    253                     }
    254                 } else if (mediaType == MIMETYPE_VIDEO_MPEG2 && !encoder) {
    255                     caps->addProfileLevel(MPEG2ProfileSimple, MPEG2LevelHL);
    256                     caps->addProfileLevel(MPEG2ProfileMain,   MPEG2LevelHL);
    257                 }
    258             }
    259 
    260             // TODO: get this from intf() as well, but how do we map them to
    261             // MediaCodec color formats?
    262             if (mediaType.find("video") != std::string::npos) {
    263                 // vendor video codecs prefer opaque format
    264                 if (trait.name.find("android") == std::string::npos) {
    265                     caps->addColorFormat(COLOR_FormatSurface);
    266                 }
    267                 caps->addColorFormat(COLOR_FormatYUV420Flexible);
    268                 caps->addColorFormat(COLOR_FormatYUV420Planar);
    269                 caps->addColorFormat(COLOR_FormatYUV420SemiPlanar);
    270                 caps->addColorFormat(COLOR_FormatYUV420PackedPlanar);
    271                 caps->addColorFormat(COLOR_FormatYUV420PackedSemiPlanar);
    272                 // framework video encoders must support surface format, though it is unclear
    273                 // that they will be able to map it if it is opaque
    274                 if (encoder && trait.name.find("android") != std::string::npos) {
    275                     caps->addColorFormat(COLOR_FormatSurface);
    276                 }
    277             }
    278         }
    279     }
    280     return OK;
    281 }
    282 
    283 }  // namespace android
    284 
    285 extern "C" android::MediaCodecListBuilderBase *CreateBuilder() {
    286     return new android::Codec2InfoBuilder;
    287 }
    288 
    289