1 /*
2 * Copyright 2016, 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 #include <ios>
18 #include <list>
19
20 #include <android-base/logging.h>
21 #include <media/openmax/OMX_Core.h>
22 #include <media/openmax/OMX_AsString.h>
23
24 #include <media/stagefright/omx/OMXUtils.h>
25 #include <media/stagefright/omx/OMXStore.h>
26 #include <media/stagefright/omx/OmxGraphicBufferSource.h>
27
28 #include <media/stagefright/omx/1.0/WOmxNode.h>
29 #include <media/stagefright/omx/1.0/WOmxObserver.h>
30 #include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
31 #include <media/stagefright/omx/1.0/Conversion.h>
32 #include <media/stagefright/omx/1.0/Omx.h>
33
34 namespace android {
35 namespace hardware {
36 namespace media {
37 namespace omx {
38 namespace V1_0 {
39 namespace implementation {
40
41 constexpr size_t kMaxNodeInstances = (1 << 16);
42
Omx()43 Omx::Omx() :
44 mStore(new OMXStore()),
45 mParser() {
46 (void)mParser.parseXmlFilesInSearchDirs();
47 (void)mParser.parseXmlPath(mParser.defaultProfilingResultsXmlPath);
48 }
49
~Omx()50 Omx::~Omx() {
51 delete mStore;
52 }
53
listNodes(listNodes_cb _hidl_cb)54 Return<void> Omx::listNodes(listNodes_cb _hidl_cb) {
55 std::list<::android::IOMX::ComponentInfo> list;
56 char componentName[256];
57 for (OMX_U32 index = 0;
58 mStore->enumerateComponents(
59 componentName, sizeof(componentName), index) == OMX_ErrorNone;
60 ++index) {
61 list.push_back(::android::IOMX::ComponentInfo());
62 ::android::IOMX::ComponentInfo& info = list.back();
63 info.mName = componentName;
64 ::android::Vector<::android::String8> roles;
65 OMX_ERRORTYPE err =
66 mStore->getRolesOfComponent(componentName, &roles);
67 if (err == OMX_ErrorNone) {
68 for (OMX_U32 i = 0; i < roles.size(); ++i) {
69 info.mRoles.push_back(roles[i]);
70 }
71 }
72 }
73
74 hidl_vec<ComponentInfo> tList;
75 tList.resize(list.size());
76 size_t i = 0;
77 for (auto const& info : list) {
78 convertTo(&(tList[i++]), info);
79 }
80 _hidl_cb(toStatus(OK), tList);
81 return Void();
82 }
83
allocateNode(const hidl_string & name,const sp<IOmxObserver> & observer,allocateNode_cb _hidl_cb)84 Return<void> Omx::allocateNode(
85 const hidl_string& name,
86 const sp<IOmxObserver>& observer,
87 allocateNode_cb _hidl_cb) {
88
89 using ::android::IOMXNode;
90 using ::android::IOMXObserver;
91
92 sp<OMXNodeInstance> instance;
93 {
94 Mutex::Autolock autoLock(mLock);
95 if (mLiveNodes.size() == kMaxNodeInstances) {
96 _hidl_cb(toStatus(NO_MEMORY), nullptr);
97 return Void();
98 }
99
100 instance = new OMXNodeInstance(
101 this, new LWOmxObserver(observer), name.c_str());
102
103 OMX_COMPONENTTYPE *handle;
104 OMX_ERRORTYPE err = mStore->makeComponentInstance(
105 name.c_str(), &OMXNodeInstance::kCallbacks,
106 instance.get(), &handle);
107
108 if (err != OMX_ErrorNone) {
109 LOG(ERROR) << "Failed to allocate omx component "
110 "'" << name.c_str() << "' "
111 " err=" << asString(err) <<
112 "(0x" << std::hex << unsigned(err) << ")";
113 _hidl_cb(toStatus(StatusFromOMXError(err)), nullptr);
114 return Void();
115 }
116 instance->setHandle(handle);
117
118 // Find quirks from mParser
119 const auto& codec = mParser.getCodecMap().find(name.c_str());
120 if (codec == mParser.getCodecMap().cend()) {
121 LOG(WARNING) << "Failed to obtain quirks for omx component "
122 "'" << name.c_str() << "' "
123 "from XML files";
124 } else {
125 uint32_t quirks = 0;
126 for (const auto& quirk : codec->second.quirkSet) {
127 if (quirk == "quirk::requires-allocate-on-input-ports") {
128 quirks |= OMXNodeInstance::
129 kRequiresAllocateBufferOnInputPorts;
130 }
131 if (quirk == "quirk::requires-allocate-on-output-ports") {
132 quirks |= OMXNodeInstance::
133 kRequiresAllocateBufferOnOutputPorts;
134 }
135 }
136 instance->setQuirks(quirks);
137 }
138
139 mLiveNodes.add(observer.get(), instance);
140 mNode2Observer.add(instance.get(), observer.get());
141 }
142 observer->linkToDeath(this, 0);
143
144 _hidl_cb(toStatus(OK), new TWOmxNode(instance));
145 return Void();
146 }
147
createInputSurface(createInputSurface_cb _hidl_cb)148 Return<void> Omx::createInputSurface(createInputSurface_cb _hidl_cb) {
149 sp<OmxGraphicBufferSource> graphicBufferSource = new OmxGraphicBufferSource();
150 status_t err = graphicBufferSource->initCheck();
151 if (err != OK) {
152 LOG(ERROR) << "Failed to create persistent input surface: "
153 << strerror(-err) << " "
154 "(" << int(err) << ")";
155 _hidl_cb(toStatus(err), nullptr, nullptr);
156 return Void();
157 }
158
159 _hidl_cb(toStatus(OK),
160 graphicBufferSource->getHGraphicBufferProducer_V1_0(),
161 new TWGraphicBufferSource(graphicBufferSource));
162 return Void();
163 }
164
serviceDied(uint64_t,wp<IBase> const & who)165 void Omx::serviceDied(uint64_t /* cookie */, wp<IBase> const& who) {
166 sp<OMXNodeInstance> instance;
167 {
168 Mutex::Autolock autoLock(mLock);
169
170 ssize_t index = mLiveNodes.indexOfKey(who);
171
172 if (index < 0) {
173 LOG(ERROR) << "b/27597103, nonexistent observer on serviceDied";
174 android_errorWriteLog(0x534e4554, "27597103");
175 return;
176 }
177
178 instance = mLiveNodes.editValueAt(index);
179 mLiveNodes.removeItemsAt(index);
180 mNode2Observer.removeItem(instance.get());
181 }
182 instance->onObserverDied();
183 }
184
freeNode(sp<OMXNodeInstance> const & instance)185 status_t Omx::freeNode(sp<OMXNodeInstance> const& instance) {
186 if (instance == NULL) {
187 return OK;
188 }
189
190 {
191 Mutex::Autolock autoLock(mLock);
192 ssize_t observerIndex = mNode2Observer.indexOfKey(instance.get());
193 if (observerIndex >= 0) {
194 wp<IBase> observer = mNode2Observer.valueAt(observerIndex);
195 ssize_t nodeIndex = mLiveNodes.indexOfKey(observer);
196 if (nodeIndex >= 0) {
197 mNode2Observer.removeItemsAt(observerIndex);
198 mLiveNodes.removeItemsAt(nodeIndex);
199 sp<IBase> sObserver = observer.promote();
200 if (sObserver != nullptr) {
201 sObserver->unlinkToDeath(this);
202 }
203 } else {
204 LOG(WARNING) << "Inconsistent observer record";
205 }
206 }
207 }
208
209 OMX_ERRORTYPE err = OMX_ErrorNone;
210 if (instance->handle() != NULL) {
211 err = mStore->destroyComponentInstance(
212 static_cast<OMX_COMPONENTTYPE*>(instance->handle()));
213 }
214 return StatusFromOMXError(err);
215 }
216
217 // Methods from ::android::hidl::base::V1_0::IBase follow.
218
HIDL_FETCH_IOmx(const char *)219 IOmx* HIDL_FETCH_IOmx(const char* /* name */) {
220 return new Omx();
221 }
222
223 } // namespace implementation
224 } // namespace V1_0
225 } // namespace omx
226 } // namespace media
227 } // namespace hardware
228 } // namespace android
229