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