1 /* 2 * Copyright (C) 2017 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 "OmxInfoBuilder" 19 20 #ifdef __LP64__ 21 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS 22 #endif 23 24 #include <utils/Log.h> 25 #include <cutils/properties.h> 26 27 #include <binder/IServiceManager.h> 28 #include <media/IMediaCodecService.h> 29 #include <media/stagefright/OmxInfoBuilder.h> 30 #include <media/stagefright/ACodec.h> 31 32 #include <android/hardware/media/omx/1.0/IOmxStore.h> 33 #include <android/hardware/media/omx/1.0/IOmx.h> 34 #include <android/hardware/media/omx/1.0/IOmxNode.h> 35 #include <media/stagefright/omx/OMXUtils.h> 36 37 #include <media/IOMXStore.h> 38 #include <media/IOMX.h> 39 #include <media/MediaDefs.h> 40 #include <media/omx/1.0/WOmx.h> 41 42 #include <media/openmax/OMX_Index.h> 43 #include <media/openmax/OMX_IndexExt.h> 44 #include <media/openmax/OMX_Audio.h> 45 #include <media/openmax/OMX_AudioExt.h> 46 #include <media/openmax/OMX_Video.h> 47 #include <media/openmax/OMX_VideoExt.h> 48 49 namespace android { 50 51 namespace /* unnamed */ { 52 53 status_t queryCapabilities( 54 const IOMXStore::NodeInfo& node, const char* mime, bool isEncoder, 55 MediaCodecInfo::CapabilitiesWriter* caps) { 56 sp<ACodec> codec = new ACodec(); 57 status_t err = codec->queryCapabilities( 58 node.owner.c_str(), node.name.c_str(), mime, isEncoder, caps); 59 if (err != OK) { 60 return err; 61 } 62 for (const auto& attribute : node.attributes) { 63 // All features have an int32 value except 64 // "feature-bitrate-modes", which has a string value. 65 if ((attribute.key.compare(0, 8, "feature-") == 0) && 66 (attribute.key.compare(8, 15, "bitrate-modes") 67 != 0)) { 68 // If this attribute.key is a feature that is not a bitrate 69 // control, add an int32 value. 70 caps->addDetail( 71 attribute.key.c_str(), 72 attribute.value == "1" ? 1 : 0); 73 } else { 74 // Non-feature attributes 75 caps->addDetail( 76 attribute.key.c_str(), attribute.value.c_str()); 77 } 78 } 79 return OK; 80 } 81 82 } // unnamed namespace 83 84 OmxInfoBuilder::OmxInfoBuilder() { 85 } 86 87 status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) { 88 bool treble; 89 sp<IOMX> omx; 90 std::vector<IOMXStore::RoleInfo> roles; 91 92 treble = property_get_bool("persist.media.treble_omx", true); 93 if (treble) { 94 using namespace ::android::hardware::media::omx::V1_0; 95 using ::android::hardware::hidl_vec; 96 using ::android::hardware::hidl_string; 97 98 // Obtain IOmxStore 99 sp<IOmxStore> omxStore = IOmxStore::getService(); 100 if (omxStore == nullptr) { 101 ALOGE("Cannot connect to an IOmxStore instance."); 102 return NO_INIT; 103 } 104 105 // List service attributes (global settings) 106 Status status; 107 hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes; 108 auto transStatus = omxStore->listServiceAttributes( 109 [&status, &serviceAttributes] 110 (Status inStatus, const hidl_vec<IOmxStore::ServiceAttribute>& 111 inAttributes) { 112 status = inStatus; 113 serviceAttributes = inAttributes; 114 }); 115 if (!transStatus.isOk()) { 116 ALOGE("Fail to obtain global settings from IOmxStore."); 117 return NO_INIT; 118 } 119 if (status != Status::OK) { 120 ALOGE("IOmxStore reports parsing error."); 121 return NO_INIT; 122 } 123 for (const auto& p : serviceAttributes) { 124 writer->addGlobalSetting( 125 p.key.c_str(), p.value.c_str()); 126 } 127 128 // List roles and convert to IOMXStore's format 129 transStatus = omxStore->listRoles( 130 [&roles] 131 (const hidl_vec<IOmxStore::RoleInfo>& inRoleList) { 132 roles.reserve(inRoleList.size()); 133 for (const auto& inRole : inRoleList) { 134 IOMXStore::RoleInfo role; 135 role.role = inRole.role; 136 role.type = inRole.type; 137 role.isEncoder = inRole.isEncoder; 138 role.preferPlatformNodes = inRole.preferPlatformNodes; 139 std::vector<IOMXStore::NodeInfo>& nodes = 140 role.nodes; 141 nodes.reserve(inRole.nodes.size()); 142 for (const auto& inNode : inRole.nodes) { 143 IOMXStore::NodeInfo node; 144 node.name = inNode.name; 145 node.owner = inNode.owner; 146 std::vector<IOMXStore::Attribute>& attributes = 147 node.attributes; 148 attributes.reserve(inNode.attributes.size()); 149 for (const auto& inAttr : inNode.attributes) { 150 IOMXStore::Attribute attr; 151 attr.key = inAttr.key; 152 attr.value = inAttr.value; 153 attributes.push_back(std::move(attr)); 154 } 155 nodes.push_back(std::move(node)); 156 } 157 roles.push_back(std::move(role)); 158 } 159 }); 160 if (!transStatus.isOk()) { 161 ALOGE("Fail to obtain codec roles from IOmxStore."); 162 return NO_INIT; 163 } 164 } else { 165 // Obtain IOMXStore 166 sp<IServiceManager> sm = defaultServiceManager(); 167 if (sm == nullptr) { 168 ALOGE("Cannot obtain the default service manager."); 169 return NO_INIT; 170 } 171 sp<IBinder> codecBinder = sm->getService(String16("media.codec")); 172 if (codecBinder == nullptr) { 173 ALOGE("Cannot obtain the media codec service."); 174 return NO_INIT; 175 } 176 sp<IMediaCodecService> codecService = 177 interface_cast<IMediaCodecService>(codecBinder); 178 if (codecService == nullptr) { 179 ALOGE("Wrong type of media codec service obtained."); 180 return NO_INIT; 181 } 182 omx = codecService->getOMX(); 183 if (omx == nullptr) { 184 ALOGE("Cannot connect to an IOMX instance."); 185 } 186 sp<IOMXStore> omxStore = codecService->getOMXStore(); 187 if (omxStore == nullptr) { 188 ALOGE("Cannot connect to an IOMXStore instance."); 189 return NO_INIT; 190 } 191 192 // List service attributes (global settings) 193 std::vector<IOMXStore::Attribute> serviceAttributes; 194 status_t status = omxStore->listServiceAttributes(&serviceAttributes); 195 if (status != OK) { 196 ALOGE("Fail to obtain global settings from IOMXStore."); 197 return NO_INIT; 198 } 199 for (const auto& p : serviceAttributes) { 200 writer->addGlobalSetting( 201 p.key.c_str(), p.value.c_str()); 202 } 203 204 // List roles 205 status = omxStore->listRoles(&roles); 206 if (status != OK) { 207 ALOGE("Fail to obtain codec roles from IOMXStore."); 208 return NO_INIT; 209 } 210 } 211 212 // Convert roles to lists of codecs 213 214 // codec name -> index into swCodecs 215 std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> > 216 swCodecName2Info; 217 // codec name -> index into hwCodecs 218 std::map<std::string, std::unique_ptr<MediaCodecInfoWriter> > 219 hwCodecName2Info; 220 // owner name -> MediaCodecInfo 221 // This map will be used to obtain the correct IOmx service(s) needed for 222 // creating IOmxNode instances and querying capabilities. 223 std::map<std::string, std::vector<sp<MediaCodecInfo> > > 224 owner2CodecInfo; 225 226 for (const auto& role : roles) { 227 const auto& typeName = role.type; 228 bool isEncoder = role.isEncoder; 229 bool preferPlatformNodes = role.preferPlatformNodes; 230 // If preferPlatformNodes is true, hardware nodes must be added after 231 // platform (software) nodes. hwCodecs is used to hold hardware nodes 232 // that need to be added after software nodes for the same role. 233 std::vector<const IOMXStore::NodeInfo*> hwCodecs; 234 for (const auto& node : role.nodes) { 235 const auto& nodeName = node.name; 236 bool isSoftware = nodeName.compare(0, 10, "OMX.google") == 0; 237 MediaCodecInfoWriter* info; 238 if (isSoftware) { 239 auto c2i = swCodecName2Info.find(nodeName); 240 if (c2i == swCodecName2Info.end()) { 241 // Create a new MediaCodecInfo for a new node. 242 c2i = swCodecName2Info.insert(std::make_pair( 243 nodeName, writer->addMediaCodecInfo())).first; 244 info = c2i->second.get(); 245 info->setName(nodeName.c_str()); 246 info->setOwner(node.owner.c_str()); 247 info->setEncoder(isEncoder); 248 } else { 249 // The node has been seen before. Simply retrieve the 250 // existing MediaCodecInfoWriter. 251 info = c2i->second.get(); 252 } 253 } else { 254 auto c2i = hwCodecName2Info.find(nodeName); 255 if (c2i == hwCodecName2Info.end()) { 256 // Create a new MediaCodecInfo for a new node. 257 if (!preferPlatformNodes) { 258 c2i = hwCodecName2Info.insert(std::make_pair( 259 nodeName, writer->addMediaCodecInfo())).first; 260 info = c2i->second.get(); 261 info->setName(nodeName.c_str()); 262 info->setOwner(node.owner.c_str()); 263 info->setEncoder(isEncoder); 264 } else { 265 // If preferPlatformNodes is true, this node must be 266 // added after all software nodes. 267 hwCodecs.push_back(&node); 268 continue; 269 } 270 } else { 271 // The node has been seen before. Simply retrieve the 272 // existing MediaCodecInfoWriter. 273 info = c2i->second.get(); 274 } 275 } 276 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps = 277 info->addMime(typeName.c_str()); 278 if (queryCapabilities( 279 node, typeName.c_str(), isEncoder, caps.get()) != OK) { 280 ALOGW("Fail to add mime %s to codec %s", 281 typeName.c_str(), nodeName.c_str()); 282 info->removeMime(typeName.c_str()); 283 } 284 } 285 286 // If preferPlatformNodes is true, hardware nodes will not have been 287 // added in the loop above, but rather saved in hwCodecs. They are 288 // going to be added here. 289 if (preferPlatformNodes) { 290 for (const auto& node : hwCodecs) { 291 MediaCodecInfoWriter* info; 292 const auto& nodeName = node->name; 293 auto c2i = hwCodecName2Info.find(nodeName); 294 if (c2i == hwCodecName2Info.end()) { 295 // Create a new MediaCodecInfo for a new node. 296 c2i = hwCodecName2Info.insert(std::make_pair( 297 nodeName, writer->addMediaCodecInfo())).first; 298 info = c2i->second.get(); 299 info->setName(nodeName.c_str()); 300 info->setOwner(node->owner.c_str()); 301 info->setEncoder(isEncoder); 302 } else { 303 // The node has been seen before. Simply retrieve the 304 // existing MediaCodecInfoWriter. 305 info = c2i->second.get(); 306 } 307 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps = 308 info->addMime(typeName.c_str()); 309 if (queryCapabilities( 310 *node, typeName.c_str(), isEncoder, caps.get()) != OK) { 311 ALOGW("Fail to add mime %s to codec %s " 312 "after software codecs", 313 typeName.c_str(), nodeName.c_str()); 314 info->removeMime(typeName.c_str()); 315 } 316 } 317 } 318 } 319 return OK; 320 } 321 322 } // namespace android 323 324