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 "Codec2-ComponentStore" 19#include <log/log.h> 20 21#include <codec2/hidl/1.0/ComponentStore.h> 22#include <codec2/hidl/1.0/InputSurface.h> 23#include <codec2/hidl/1.0/Component.h> 24#include <codec2/hidl/1.0/ConfigurableC2Intf.h> 25#include <codec2/hidl/1.0/types.h> 26 27#include <media/stagefright/bqhelper/WGraphicBufferProducer.h> 28#include <media/stagefright/bqhelper/GraphicBufferSource.h> 29 30#include <C2PlatformSupport.h> 31 32#include <utils/Errors.h> 33 34#include <android-base/file.h> 35 36#ifdef LOG 37#undef LOG 38#endif 39 40#ifdef PLOG 41#undef PLOG 42#endif 43 44#include <android-base/logging.h> 45 46#include <ostream> 47#include <sstream> 48#include <iomanip> 49 50namespace hardware { 51namespace google { 52namespace media { 53namespace c2 { 54namespace V1_0 { 55namespace utils { 56 57using namespace ::android; 58using ::android::GraphicBufferSource; 59using namespace ::android::hardware::media::bufferpool::V1_0::implementation; 60 61namespace /* unnamed */ { 62 63struct StoreIntf : public ConfigurableC2Intf { 64 StoreIntf(const std::shared_ptr<C2ComponentStore>& store) : 65 ConfigurableC2Intf(store ? store->getName() : ""), 66 mStore(store) { 67 } 68 69 c2_status_t config( 70 const std::vector<C2Param*> ¶ms, 71 c2_blocking_t mayBlock, 72 std::vector<std::unique_ptr<C2SettingResult>> *const failures 73 ) override { 74 // Assume all params are blocking 75 // TODO: Filter for supported params 76 if (mayBlock == C2_DONT_BLOCK && params.size() != 0) { 77 return C2_BLOCKING; 78 } 79 return mStore->config_sm(params, failures); 80 } 81 82 c2_status_t query( 83 const std::vector<C2Param::Index> &indices, 84 c2_blocking_t mayBlock, 85 std::vector<std::unique_ptr<C2Param>> *const params) const override { 86 // Assume all params are blocking 87 // TODO: Filter for supported params 88 if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) { 89 return C2_BLOCKING; 90 } 91 return mStore->query_sm({}, indices, params); 92 } 93 94 c2_status_t querySupportedParams( 95 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params 96 ) const override { 97 return mStore->querySupportedParams_nb(params); 98 } 99 100 c2_status_t querySupportedValues( 101 std::vector<C2FieldSupportedValuesQuery> &fields, 102 c2_blocking_t mayBlock) const override { 103 // Assume all params are blocking 104 // TODO: Filter for supported params 105 if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) { 106 return C2_BLOCKING; 107 } 108 return mStore->querySupportedValues_sm(fields); 109 } 110 111protected: 112 std::shared_ptr<C2ComponentStore> mStore; 113}; 114 115} // unnamed namespace 116 117ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store) : 118 Configurable(new CachedConfigurable(std::make_unique<StoreIntf>(store))), 119 mStore(store) { 120 121 std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore(); 122 SetPreferredCodec2ComponentStore(store); 123 124 // Retrieve struct descriptors 125 mParamReflector = mStore->getParamReflector(); 126 127 // Retrieve supported parameters from store 128 mInit = init(this); 129} 130 131c2_status_t ComponentStore::validateSupportedParams( 132 const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) { 133 c2_status_t res = C2_OK; 134 135 for (const std::shared_ptr<C2ParamDescriptor> &desc : params) { 136 if (!desc) { 137 // All descriptors should be valid 138 res = res ? res : C2_BAD_VALUE; 139 continue; 140 } 141 C2Param::CoreIndex coreIndex = desc->index().coreIndex(); 142 std::lock_guard<std::mutex> lock(mStructDescriptorsMutex); 143 auto it = mStructDescriptors.find(coreIndex); 144 if (it == mStructDescriptors.end()) { 145 std::shared_ptr<C2StructDescriptor> structDesc = 146 mParamReflector->describe(coreIndex); 147 if (!structDesc) { 148 // All supported params must be described 149 res = C2_BAD_INDEX; 150 } 151 mStructDescriptors.insert({ coreIndex, structDesc }); 152 } 153 } 154 return res; 155} 156 157// Methods from ::android::hardware::media::c2::V1_0::IComponentStore 158Return<void> ComponentStore::createComponent( 159 const hidl_string& name, 160 const sp<IComponentListener>& listener, 161 const sp<IClientManager>& pool, 162 createComponent_cb _hidl_cb) { 163 164 sp<Component> component; 165 std::shared_ptr<C2Component> c2component; 166 Status status = static_cast<Status>( 167 mStore->createComponent(name, &c2component)); 168 169 if (status == Status::OK) { 170 onInterfaceLoaded(c2component->intf()); 171 component = new Component(c2component, listener, this, pool); 172 if (!component) { 173 status = Status::CORRUPTED; 174 } else if (component->status() != C2_OK) { 175 status = static_cast<Status>(component->status()); 176 } else { 177 component->initListener(component); 178 if (component->status() != C2_OK) { 179 status = static_cast<Status>(component->status()); 180 } else { 181 std::lock_guard<std::mutex> lock(mComponentRosterMutex); 182 component->setLocalId( 183 mComponentRoster.emplace( 184 Component::InterfaceKey(component), 185 c2component) 186 .first); 187 } 188 } 189 } 190 _hidl_cb(status, component); 191 return Void(); 192} 193 194Return<void> ComponentStore::createInterface( 195 const hidl_string& name, 196 createInterface_cb _hidl_cb) { 197 std::shared_ptr<C2ComponentInterface> c2interface; 198 c2_status_t res = mStore->createInterface(name, &c2interface); 199 sp<IComponentInterface> interface; 200 if (res == C2_OK) { 201 onInterfaceLoaded(c2interface); 202 interface = new ComponentInterface(c2interface, this); 203 } 204 _hidl_cb((Status)res, interface); 205 return Void(); 206} 207 208Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) { 209 std::vector<std::shared_ptr<const C2Component::Traits>> c2traits = 210 mStore->listComponents(); 211 hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size()); 212 size_t ix = 0; 213 for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) { 214 if (c2trait) { 215 objcpy(&traits[ix++], *c2trait); 216 } 217 } 218 traits.resize(ix); 219 _hidl_cb(traits); 220 return Void(); 221} 222 223Return<sp<IInputSurface>> ComponentStore::createInputSurface() { 224 sp<GraphicBufferSource> source = new GraphicBufferSource(); 225 if (source->initCheck() != OK) { 226 return nullptr; 227 } 228 typedef ::android::hardware::graphics::bufferqueue::V1_0:: 229 IGraphicBufferProducer HGBP; 230 typedef ::android::TWGraphicBufferProducer<HGBP> B2HGBP; 231 return new InputSurface( 232 this, 233 new B2HGBP(source->getIGraphicBufferProducer()), 234 source); 235} 236 237void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) { 238 // invalidate unsupported struct descriptors if a new interface is loaded as it may have 239 // exposed new descriptors 240 std::lock_guard<std::mutex> lock(mStructDescriptorsMutex); 241 if (!mLoadedInterfaces.count(intf->getName())) { 242 mUnsupportedStructDescriptors.clear(); 243 mLoadedInterfaces.emplace(intf->getName()); 244 } 245} 246 247Return<void> ComponentStore::getStructDescriptors( 248 const hidl_vec<uint32_t>& indices, 249 getStructDescriptors_cb _hidl_cb) { 250 hidl_vec<StructDescriptor> descriptors(indices.size()); 251 size_t dstIx = 0; 252 Status res = Status::OK; 253 for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) { 254 std::lock_guard<std::mutex> lock(mStructDescriptorsMutex); 255 const C2Param::CoreIndex coreIndex = C2Param::CoreIndex(indices[srcIx]).coreIndex(); 256 const auto item = mStructDescriptors.find(coreIndex); 257 if (item == mStructDescriptors.end()) { 258 // not in the cache, and not known to be unsupported, query local reflector 259 if (!mUnsupportedStructDescriptors.count(coreIndex)) { 260 std::shared_ptr<C2StructDescriptor> structDesc = 261 mParamReflector->describe(coreIndex); 262 if (!structDesc) { 263 mUnsupportedStructDescriptors.emplace(coreIndex); 264 } else { 265 mStructDescriptors.insert({ coreIndex, structDesc }); 266 objcpy(&descriptors[dstIx++], *structDesc); 267 continue; 268 } 269 } 270 res = Status::NOT_FOUND; 271 } else if (item->second) { 272 objcpy(&descriptors[dstIx++], *item->second); 273 } else { 274 res = Status::NO_MEMORY; 275 } 276 } 277 descriptors.resize(dstIx); 278 _hidl_cb(res, descriptors); 279 return Void(); 280} 281 282Return<sp<IClientManager>> ComponentStore::getPoolClientManager() { 283 return ClientManager::getInstance(); 284} 285 286Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) { 287 // TODO implement 288 (void)src; 289 (void)dst; 290 return Status::OMITTED; 291} 292 293void ComponentStore::reportComponentDeath( 294 const Component::LocalId& componentLocalId) { 295 std::lock_guard<std::mutex> lock(mComponentRosterMutex); 296 mComponentRoster.erase(componentLocalId); 297} 298 299std::shared_ptr<C2Component> ComponentStore::findC2Component( 300 const sp<IComponent>& component) const { 301 std::lock_guard<std::mutex> lock(mComponentRosterMutex); 302 Component::LocalId it = mComponentRoster.find( 303 Component::InterfaceKey(component)); 304 if (it == mComponentRoster.end()) { 305 return std::shared_ptr<C2Component>(); 306 } 307 return it->second.lock(); 308} 309 310// Debug dump 311 312namespace /* unnamed */ { 313 314// Dump component traits 315std::ostream& dump( 316 std::ostream& out, 317 const std::shared_ptr<const C2Component::Traits>& comp) { 318 319 constexpr const char indent[] = " "; 320 321 out << indent << "name: " << comp->name << std::endl; 322 out << indent << "domain: " << comp->domain << std::endl; 323 out << indent << "kind: " << comp->kind << std::endl; 324 out << indent << "rank: " << comp->rank << std::endl; 325 out << indent << "mediaType: " << comp->mediaType << std::endl; 326 out << indent << "aliases:"; 327 for (const auto& alias : comp->aliases) { 328 out << ' ' << alias; 329 } 330 out << std::endl; 331 332 return out; 333} 334 335// Dump component 336std::ostream& dump( 337 std::ostream& out, 338 const std::shared_ptr<C2Component>& comp) { 339 340 constexpr const char indent[] = " "; 341 342 std::shared_ptr<C2ComponentInterface> intf = comp->intf(); 343 if (!intf) { 344 out << indent << "Unknown -- null interface" << std::endl; 345 return out; 346 } 347 out << indent << "name: " << intf->getName() << std::endl; 348 out << indent << "id: " << intf->getId() << std::endl; 349 return out; 350} 351 352} // unnamed namespace 353 354Return<void> ComponentStore::debug( 355 const hidl_handle& handle, 356 const hidl_vec<hidl_string>& /* args */) { 357 LOG(INFO) << "debug -- dumping..."; 358 const native_handle_t *h = handle.getNativeHandle(); 359 if (!h || h->numFds != 1) { 360 LOG(ERROR) << "debug -- dumping failed -- " 361 "invalid file descriptor to dump to"; 362 return Void(); 363 } 364 std::ostringstream out; 365 366 { // Populate "out". 367 368 constexpr const char indent[] = " "; 369 370 // Show name. 371 out << "Beginning of dump -- C2ComponentStore: " 372 << mStore->getName() << std::endl << std::endl; 373 374 // Retrieve the list of supported components. 375 std::vector<std::shared_ptr<const C2Component::Traits>> traitsList = 376 mStore->listComponents(); 377 378 // Dump the traits of supported components. 379 out << indent << "Supported components:" << std::endl << std::endl; 380 if (traitsList.size() == 0) { 381 out << indent << indent << "NONE" << std::endl << std::endl; 382 } else { 383 for (const auto& traits : traitsList) { 384 dump(out, traits) << std::endl; 385 } 386 } 387 388 // Retrieve the list of active components. 389 std::list<std::shared_ptr<C2Component>> activeComps; 390 { 391 std::lock_guard<std::mutex> lock(mComponentRosterMutex); 392 auto i = mComponentRoster.begin(); 393 while (i != mComponentRoster.end()) { 394 std::shared_ptr<C2Component> c2comp = i->second.lock(); 395 if (!c2comp) { 396 auto j = i; 397 ++i; 398 mComponentRoster.erase(j); 399 } else { 400 ++i; 401 activeComps.emplace_back(c2comp); 402 } 403 } 404 } 405 406 // Dump active components. 407 out << indent << "Active components:" << std::endl << std::endl; 408 if (activeComps.size() == 0) { 409 out << indent << indent << "NONE" << std::endl << std::endl; 410 } else { 411 for (const std::shared_ptr<C2Component>& c2comp : activeComps) { 412 dump(out, c2comp) << std::endl; 413 } 414 } 415 416 out << "End of dump -- C2ComponentStore: " 417 << mStore->getName() << std::endl; 418 } 419 420 if (!android::base::WriteStringToFd(out.str(), h->data[0])) { 421 PLOG(WARNING) << "debug -- dumping failed -- write()"; 422 } else { 423 LOG(INFO) << "debug -- dumping succeeded"; 424 } 425 return Void(); 426} 427 428 429} // namespace utils 430} // namespace V1_0 431} // namespace c2 432} // namespace media 433} // namespace google 434} // namespace hardware 435