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 <android-base/properties.h>
25 #include <utils/Log.h>
26
27 #include <media/stagefright/foundation/MediaDefs.h>
28 #include <media/stagefright/OmxInfoBuilder.h>
29 #include <media/stagefright/ACodec.h>
30
31 #include <android/hardware/media/omx/1.0/IOmxStore.h>
32 #include <android/hardware/media/omx/1.0/IOmx.h>
33 #include <android/hardware/media/omx/1.0/IOmxNode.h>
34 #include <media/stagefright/omx/OMXUtils.h>
35
36 #include <media/IOMX.h>
37 #include <media/omx/1.0/WOmx.h>
38 #include <media/stagefright/omx/1.0/OmxStore.h>
39
40 #include <media/openmax/OMX_Index.h>
41 #include <media/openmax/OMX_IndexExt.h>
42 #include <media/openmax/OMX_Audio.h>
43 #include <media/openmax/OMX_AudioExt.h>
44 #include <media/openmax/OMX_Video.h>
45 #include <media/openmax/OMX_VideoExt.h>
46
47 namespace android {
48
49 using ::android::hardware::hidl_string;
50 using ::android::hardware::hidl_vec;
51 using namespace ::android::hardware::media::omx::V1_0;
52
53 namespace /* unnamed */ {
54
hasPrefix(const hidl_string & s,const char * prefix)55 bool hasPrefix(const hidl_string& s, const char* prefix) {
56 return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
57 }
58
queryCapabilities(const IOmxStore::NodeInfo & node,const char * mediaType,bool isEncoder,MediaCodecInfo::CapabilitiesWriter * caps)59 status_t queryCapabilities(
60 const IOmxStore::NodeInfo& node, const char* mediaType, bool isEncoder,
61 MediaCodecInfo::CapabilitiesWriter* caps) {
62 sp<ACodec> codec = new ACodec();
63 for (const auto& attribute : node.attributes) {
64 // All features have an int32 value except
65 // "feature-bitrate-modes", which has a string value.
66 if (hasPrefix(attribute.key, "feature-") &&
67 !hasPrefix(attribute.key, "feature-bitrate-modes")) {
68 // If this attribute.key is a feature that is not bitrate modes,
69 // add an int32 value.
70 caps->addDetail(
71 attribute.key.c_str(),
72 hasPrefix(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 // query capabilities may remove capabilities that are not actually supported by the codec
80 status_t err = codec->queryCapabilities(
81 node.owner.c_str(), node.name.c_str(), mediaType, isEncoder, caps);
82 if (err != OK) {
83 return err;
84 }
85 return OK;
86 }
87
88 } // unnamed namespace
89
OmxInfoBuilder(bool allowSurfaceEncoders)90 OmxInfoBuilder::OmxInfoBuilder(bool allowSurfaceEncoders)
91 : mAllowSurfaceEncoders(allowSurfaceEncoders) {
92 }
93
buildMediaCodecList(MediaCodecListWriter * writer)94 status_t OmxInfoBuilder::buildMediaCodecList(MediaCodecListWriter* writer) {
95 // Obtain IOmxStore
96 sp<IOmxStore> omxStore = IOmxStore::getService();
97 if (omxStore == nullptr) {
98 ALOGE("Cannot find an IOmxStore service.");
99 return NO_INIT;
100 }
101
102 // List service attributes (global settings)
103 Status status;
104 hidl_vec<IOmxStore::RoleInfo> roles;
105 auto transStatus = omxStore->listRoles(
106 [&roles] (
107 const hidl_vec<IOmxStore::RoleInfo>& inRoleList) {
108 roles = inRoleList;
109 });
110 if (!transStatus.isOk()) {
111 ALOGE("Fail to obtain codec roles from IOmxStore.");
112 return NO_INIT;
113 }
114
115 hidl_vec<IOmxStore::ServiceAttribute> serviceAttributes;
116 transStatus = omxStore->listServiceAttributes(
117 [&status, &serviceAttributes] (
118 Status inStatus,
119 const hidl_vec<IOmxStore::ServiceAttribute>& inAttributes) {
120 status = inStatus;
121 serviceAttributes = inAttributes;
122 });
123 if (!transStatus.isOk()) {
124 ALOGE("Fail to obtain global settings from IOmxStore.");
125 return NO_INIT;
126 }
127 if (status != Status::OK) {
128 ALOGE("IOmxStore reports parsing error.");
129 return NO_INIT;
130 }
131 for (const auto& p : serviceAttributes) {
132 writer->addGlobalSetting(
133 p.key.c_str(), p.value.c_str());
134 }
135
136 // Convert roles to lists of codecs
137
138 // codec name -> index into swCodecs/hwCodecs
139 std::map<hidl_string, std::unique_ptr<MediaCodecInfoWriter>> codecName2Info;
140
141 uint32_t defaultRank =
142 ::android::base::GetUintProperty("debug.stagefright.omx_default_rank", 0x100u);
143 uint32_t defaultSwAudioRank =
144 ::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-audio", 0x10u);
145 uint32_t defaultSwOtherRank =
146 ::android::base::GetUintProperty("debug.stagefright.omx_default_rank.sw-other", 0x210u);
147
148 for (const IOmxStore::RoleInfo& role : roles) {
149 const hidl_string& typeName = role.type;
150 bool isEncoder = role.isEncoder;
151 bool isAudio = hasPrefix(role.type, "audio/");
152 bool isVideoOrImage = hasPrefix(role.type, "video/") || hasPrefix(role.type, "image/");
153
154 for (const IOmxStore::NodeInfo &node : role.nodes) {
155 const hidl_string& nodeName = node.name;
156
157 // currently image and video encoders use surface input
158 if (!mAllowSurfaceEncoders && isVideoOrImage && isEncoder) {
159 ALOGD("disabling %s for media type %s because we are not using OMX input surface",
160 nodeName.c_str(), role.type.c_str());
161 continue;
162 }
163
164 bool isSoftware = hasPrefix(nodeName, "OMX.google");
165 uint32_t rank = isSoftware
166 ? (isAudio ? defaultSwAudioRank : defaultSwOtherRank)
167 : defaultRank;
168 // get rank from IOmxStore via attribute
169 for (const IOmxStore::Attribute& attribute : node.attributes) {
170 if (attribute.key == "rank") {
171 uint32_t oldRank = rank;
172 char dummy;
173 if (sscanf(attribute.value.c_str(), "%u%c", &rank, &dummy) != 1) {
174 rank = oldRank;
175 }
176 break;
177 }
178 }
179
180 MediaCodecInfoWriter* info;
181 auto c2i = codecName2Info.find(nodeName);
182 if (c2i == codecName2Info.end()) {
183 // Create a new MediaCodecInfo for a new node.
184 c2i = codecName2Info.insert(std::make_pair(
185 nodeName, writer->addMediaCodecInfo())).first;
186 info = c2i->second.get();
187 info->setName(nodeName.c_str());
188 info->setOwner(node.owner.c_str());
189 info->setRank(rank);
190
191 typename std::underlying_type<MediaCodecInfo::Attributes>::type attrs = 0;
192 // all OMX codecs are vendor codecs (in the vendor partition), but
193 // treat OMX.google codecs as non-hardware-accelerated and non-vendor
194 if (!isSoftware) {
195 attrs |= MediaCodecInfo::kFlagIsVendor;
196 if (!std::count_if(
197 node.attributes.begin(), node.attributes.end(),
198 [](const IOmxStore::Attribute &i) -> bool {
199 return i.key == "attribute::software-codec";
200 })) {
201 attrs |= MediaCodecInfo::kFlagIsHardwareAccelerated;
202 }
203 }
204 if (isEncoder) {
205 attrs |= MediaCodecInfo::kFlagIsEncoder;
206 }
207 info->setAttributes(attrs);
208 } else {
209 // The node has been seen before. Simply retrieve the
210 // existing MediaCodecInfoWriter.
211 info = c2i->second.get();
212 }
213 std::unique_ptr<MediaCodecInfo::CapabilitiesWriter> caps =
214 info->addMediaType(typeName.c_str());
215 if (queryCapabilities(
216 node, typeName.c_str(), isEncoder, caps.get()) != OK) {
217 ALOGW("Fail to add media type %s to codec %s",
218 typeName.c_str(), nodeName.c_str());
219 info->removeMediaType(typeName.c_str());
220 }
221 }
222 }
223 return OK;
224 }
225
226 } // namespace android
227