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 <gui/IGraphicBufferProducer.h> 22 #include <media/openmax/OMX_Core.h> 23 #include <media/openmax/OMX_AsString.h> 24 25 #include <media/stagefright/omx/OMXUtils.h> 26 #include <media/stagefright/omx/OMXMaster.h> 27 #include <media/stagefright/omx/GraphicBufferSource.h> 28 29 #include <media/stagefright/omx/1.0/WOmxNode.h> 30 #include <media/stagefright/omx/1.0/WOmxObserver.h> 31 #include <media/stagefright/omx/1.0/WGraphicBufferProducer.h> 32 #include <media/stagefright/omx/1.0/WGraphicBufferSource.h> 33 #include <media/stagefright/omx/1.0/Conversion.h> 34 #include <media/stagefright/omx/1.0/Omx.h> 35 36 namespace android { 37 namespace hardware { 38 namespace media { 39 namespace omx { 40 namespace V1_0 { 41 namespace implementation { 42 43 constexpr size_t kMaxNodeInstances = (1 << 16); 44 45 Omx::Omx() : 46 mMaster(new OMXMaster()), 47 mParser() { 48 } 49 50 Omx::~Omx() { 51 delete mMaster; 52 } 53 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 mMaster->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 mMaster->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 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 = mMaster->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 == "requires-allocate-on-input-ports") { 128 quirks |= OMXNodeInstance:: 129 kRequiresAllocateBufferOnInputPorts; 130 } 131 if (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 148 Return<void> Omx::createInputSurface(createInputSurface_cb _hidl_cb) { 149 sp<::android::IGraphicBufferProducer> bufferProducer; 150 151 sp<GraphicBufferSource> graphicBufferSource = new GraphicBufferSource(); 152 status_t err = graphicBufferSource->initCheck(); 153 if (err != OK) { 154 LOG(ERROR) << "Failed to create persistent input surface: " 155 << strerror(-err) << " " 156 "(" << int(err) << ")"; 157 _hidl_cb(toStatus(err), nullptr, nullptr); 158 return Void(); 159 } 160 bufferProducer = graphicBufferSource->getIGraphicBufferProducer(); 161 162 _hidl_cb(toStatus(OK), 163 new TWGraphicBufferProducer(bufferProducer), 164 new TWGraphicBufferSource(graphicBufferSource)); 165 return Void(); 166 } 167 168 void Omx::serviceDied(uint64_t /* cookie */, wp<IBase> const& who) { 169 sp<OMXNodeInstance> instance; 170 { 171 Mutex::Autolock autoLock(mLock); 172 173 ssize_t index = mLiveNodes.indexOfKey(who); 174 175 if (index < 0) { 176 LOG(ERROR) << "b/27597103, nonexistent observer on serviceDied"; 177 android_errorWriteLog(0x534e4554, "27597103"); 178 return; 179 } 180 181 instance = mLiveNodes.editValueAt(index); 182 mLiveNodes.removeItemsAt(index); 183 mNode2Observer.removeItem(instance.get()); 184 } 185 instance->onObserverDied(); 186 } 187 188 status_t Omx::freeNode(sp<OMXNodeInstance> const& instance) { 189 if (instance == NULL) { 190 return OK; 191 } 192 193 { 194 Mutex::Autolock autoLock(mLock); 195 ssize_t observerIndex = mNode2Observer.indexOfKey(instance.get()); 196 if (observerIndex >= 0) { 197 wp<IBase> observer = mNode2Observer.valueAt(observerIndex); 198 ssize_t nodeIndex = mLiveNodes.indexOfKey(observer); 199 if (nodeIndex >= 0) { 200 mNode2Observer.removeItemsAt(observerIndex); 201 mLiveNodes.removeItemsAt(nodeIndex); 202 sp<IBase> sObserver = observer.promote(); 203 if (sObserver != nullptr) { 204 sObserver->unlinkToDeath(this); 205 } 206 } else { 207 LOG(WARNING) << "Inconsistent observer record"; 208 } 209 } 210 } 211 212 OMX_ERRORTYPE err = OMX_ErrorNone; 213 if (instance->handle() != NULL) { 214 err = mMaster->destroyComponentInstance( 215 static_cast<OMX_COMPONENTTYPE*>(instance->handle())); 216 } 217 return StatusFromOMXError(err); 218 } 219 220 // Methods from ::android::hidl::base::V1_0::IBase follow. 221 222 IOmx* HIDL_FETCH_IOmx(const char* /* name */) { 223 return new Omx(); 224 } 225 226 } // namespace implementation 227 } // namespace V1_0 228 } // namespace omx 229 } // namespace media 230 } // namespace hardware 231 } // namespace android 232