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 "Codec2Client" 19 #include <log/log.h> 20 21 #include <codec2/hidl/client.h> 22 23 #include <deque> 24 #include <limits> 25 #include <map> 26 #include <type_traits> 27 #include <vector> 28 29 #include <bufferpool/ClientManager.h> 30 #include <cutils/properties.h> 31 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> 32 #include <hidl/HidlSupport.h> 33 #include <media/stagefright/bqhelper/WGraphicBufferProducer.h> 34 #undef LOG 35 36 #include <android/hardware/media/bufferpool/1.0/IClientManager.h> 37 #include <hardware/google/media/c2/1.0/IComponent.h> 38 #include <hardware/google/media/c2/1.0/IComponentInterface.h> 39 #include <hardware/google/media/c2/1.0/IComponentListener.h> 40 #include <hardware/google/media/c2/1.0/IComponentStore.h> 41 #include <hardware/google/media/c2/1.0/IConfigurable.h> 42 43 #include <C2Debug.h> 44 #include <C2BufferPriv.h> 45 #include <C2PlatformSupport.h> 46 47 namespace android { 48 49 using ::android::hardware::hidl_vec; 50 using ::android::hardware::hidl_string; 51 using ::android::hardware::Return; 52 using ::android::hardware::Void; 53 using ::android::TWGraphicBufferProducer; 54 55 using namespace ::hardware::google::media::c2::V1_0; 56 using namespace ::hardware::google::media::c2::V1_0::utils; 57 using namespace ::android::hardware::media::bufferpool::V1_0; 58 using namespace ::android::hardware::media::bufferpool::V1_0::implementation; 59 60 namespace /* unnamed */ { 61 62 // c2_status_t value that corresponds to hwbinder transaction failure. 63 constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED; 64 65 // List of known IComponentStore services. 66 constexpr const char* kClientNames[] = { 67 "default", 68 "software", 69 }; 70 71 typedef std::array< 72 std::shared_ptr<Codec2Client>, 73 std::extent<decltype(kClientNames)>::value> ClientList; 74 75 // Convenience methods to obtain known clients. 76 size_t getClientCount() { 77 // TODO: this may not work if there is no default service 78 return std::extent<decltype(kClientNames)>::value; 79 } 80 81 std::shared_ptr<Codec2Client> getClient(size_t index) { 82 return Codec2Client::CreateFromService(kClientNames[index]); 83 } 84 85 ClientList getClientList() { 86 ClientList list; 87 for (size_t i = 0; i < list.size(); ++i) { 88 list[i] = getClient(i); 89 } 90 return list; 91 } 92 93 } // unnamed 94 95 // Codec2ConfigurableClient 96 97 const C2String& Codec2ConfigurableClient::getName() const { 98 return mName; 99 } 100 101 Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const { 102 return static_cast<Base*>(mBase.get()); 103 } 104 105 Codec2ConfigurableClient::Codec2ConfigurableClient( 106 const sp<Codec2ConfigurableClient::Base>& base) : mBase(base) { 107 Return<void> transStatus = base->getName( 108 [this](const hidl_string& name) { 109 mName = name.c_str(); 110 }); 111 if (!transStatus.isOk()) { 112 ALOGE("Cannot obtain name from IConfigurable."); 113 } 114 } 115 116 c2_status_t Codec2ConfigurableClient::query( 117 const std::vector<C2Param*> &stackParams, 118 const std::vector<C2Param::Index> &heapParamIndices, 119 c2_blocking_t mayBlock, 120 std::vector<std::unique_ptr<C2Param>>* const heapParams) const { 121 hidl_vec<ParamIndex> indices( 122 stackParams.size() + heapParamIndices.size()); 123 size_t numIndices = 0; 124 for (C2Param* const& stackParam : stackParams) { 125 if (!stackParam) { 126 ALOGW("query -- null stack param encountered."); 127 continue; 128 } 129 indices[numIndices++] = static_cast<ParamIndex>(stackParam->index()); 130 } 131 size_t numStackIndices = numIndices; 132 for (const C2Param::Index& index : heapParamIndices) { 133 indices[numIndices++] = 134 static_cast<ParamIndex>(static_cast<uint32_t>(index)); 135 } 136 indices.resize(numIndices); 137 if (heapParams) { 138 heapParams->reserve(heapParams->size() + numIndices); 139 } 140 c2_status_t status; 141 Return<void> transStatus = base()->query( 142 indices, 143 mayBlock == C2_MAY_BLOCK, 144 [&status, &numStackIndices, &stackParams, heapParams]( 145 Status s, const Params& p) { 146 status = static_cast<c2_status_t>(s); 147 if (status != C2_OK && status != C2_BAD_INDEX) { 148 ALOGE("query -- call failed. " 149 "Error code = %d", static_cast<int>(status)); 150 return; 151 } 152 std::vector<C2Param*> paramPointers; 153 c2_status_t parseStatus = parseParamsBlob(¶mPointers, p); 154 if (parseStatus != C2_OK) { 155 ALOGE("query -- error while parsing params. " 156 "Error code = %d", static_cast<int>(status)); 157 status = parseStatus; 158 return; 159 } 160 size_t i = 0; 161 for (auto it = paramPointers.begin(); it != paramPointers.end(); ) { 162 C2Param* paramPointer = *it; 163 if (numStackIndices > 0) { 164 --numStackIndices; 165 if (!paramPointer) { 166 ALOGW("query -- null stack param."); 167 ++it; 168 continue; 169 } 170 for (; i < stackParams.size() && !stackParams[i]; ) { 171 ++i; 172 } 173 if (i >= stackParams.size()) { 174 ALOGE("query -- unexpected error."); 175 status = C2_CORRUPTED; 176 return; 177 } 178 if (stackParams[i]->index() != paramPointer->index()) { 179 ALOGW("query -- param skipped. index = %d", 180 static_cast<int>(stackParams[i]->index())); 181 stackParams[i++]->invalidate(); 182 continue; 183 } 184 if (!stackParams[i++]->updateFrom(*paramPointer)) { 185 ALOGW("query -- param update failed. index = %d", 186 static_cast<int>(paramPointer->index())); 187 } 188 } else { 189 if (!paramPointer) { 190 ALOGW("query -- null heap param."); 191 ++it; 192 continue; 193 } 194 if (!heapParams) { 195 ALOGW("query -- extra stack param."); 196 } 197 heapParams->emplace_back(C2Param::Copy(*paramPointer)); 198 } 199 ++it; 200 } 201 }); 202 if (!transStatus.isOk()) { 203 ALOGE("query -- transaction failed."); 204 return C2_TRANSACTION_FAILED; 205 } 206 return status; 207 } 208 209 c2_status_t Codec2ConfigurableClient::config( 210 const std::vector<C2Param*> ¶ms, 211 c2_blocking_t mayBlock, 212 std::vector<std::unique_ptr<C2SettingResult>>* const failures) { 213 Params hidlParams; 214 Status hidlStatus = createParamsBlob(&hidlParams, params); 215 if (hidlStatus != Status::OK) { 216 ALOGE("config -- bad input."); 217 return C2_TRANSACTION_FAILED; 218 } 219 c2_status_t status; 220 Return<void> transStatus = base()->config( 221 hidlParams, 222 mayBlock == C2_MAY_BLOCK, 223 [&status, ¶ms, failures]( 224 Status s, 225 const hidl_vec<SettingResult> f, 226 const Params& o) { 227 status = static_cast<c2_status_t>(s); 228 if (status != C2_OK) { 229 ALOGD("config -- call failed. " 230 "Error code = %d", static_cast<int>(status)); 231 } 232 size_t i = failures->size(); 233 failures->resize(i + f.size()); 234 for (const SettingResult& sf : f) { 235 status = objcpy(&(*failures)[i++], sf); 236 if (status != C2_OK) { 237 ALOGE("config -- invalid returned SettingResult. " 238 "Error code = %d", static_cast<int>(status)); 239 return; 240 } 241 } 242 status = updateParamsFromBlob(params, o); 243 }); 244 if (!transStatus.isOk()) { 245 ALOGE("config -- transaction failed."); 246 return C2_TRANSACTION_FAILED; 247 } 248 return status; 249 } 250 251 c2_status_t Codec2ConfigurableClient::querySupportedParams( 252 std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const { 253 // TODO: Cache and query properly! 254 c2_status_t status; 255 Return<void> transStatus = base()->querySupportedParams( 256 std::numeric_limits<uint32_t>::min(), 257 std::numeric_limits<uint32_t>::max(), 258 [&status, params]( 259 Status s, 260 const hidl_vec<ParamDescriptor>& p) { 261 status = static_cast<c2_status_t>(s); 262 if (status != C2_OK) { 263 ALOGE("querySupportedParams -- call failed. " 264 "Error code = %d", static_cast<int>(status)); 265 return; 266 } 267 size_t i = params->size(); 268 params->resize(i + p.size()); 269 for (const ParamDescriptor& sp : p) { 270 status = objcpy(&(*params)[i++], sp); 271 if (status != C2_OK) { 272 ALOGE("querySupportedParams -- " 273 "invalid returned ParamDescriptor. " 274 "Error code = %d", static_cast<int>(status)); 275 return; 276 } 277 } 278 }); 279 if (!transStatus.isOk()) { 280 ALOGE("querySupportedParams -- transaction failed."); 281 return C2_TRANSACTION_FAILED; 282 } 283 return status; 284 } 285 286 c2_status_t Codec2ConfigurableClient::querySupportedValues( 287 std::vector<C2FieldSupportedValuesQuery>& fields, 288 c2_blocking_t mayBlock) const { 289 hidl_vec<FieldSupportedValuesQuery> inFields(fields.size()); 290 for (size_t i = 0; i < fields.size(); ++i) { 291 Status hidlStatus = objcpy(&inFields[i], fields[i]); 292 if (hidlStatus != Status::OK) { 293 ALOGE("querySupportedValues -- bad input"); 294 return C2_TRANSACTION_FAILED; 295 } 296 } 297 298 c2_status_t status; 299 Return<void> transStatus = base()->querySupportedValues( 300 inFields, 301 mayBlock == C2_MAY_BLOCK, 302 [&status, &inFields, &fields]( 303 Status s, 304 const hidl_vec<FieldSupportedValuesQueryResult>& r) { 305 status = static_cast<c2_status_t>(s); 306 if (status != C2_OK) { 307 ALOGE("querySupportedValues -- call failed. " 308 "Error code = %d", static_cast<int>(status)); 309 return; 310 } 311 if (r.size() != fields.size()) { 312 ALOGE("querySupportedValues -- input and output lists " 313 "have different sizes."); 314 status = C2_CORRUPTED; 315 return; 316 } 317 for (size_t i = 0; i < fields.size(); ++i) { 318 status = objcpy(&fields[i], inFields[i], r[i]); 319 if (status != C2_OK) { 320 ALOGE("querySupportedValues -- invalid returned value. " 321 "Error code = %d", static_cast<int>(status)); 322 return; 323 } 324 } 325 }); 326 if (!transStatus.isOk()) { 327 ALOGE("querySupportedValues -- transaction failed."); 328 return C2_TRANSACTION_FAILED; 329 } 330 return status; 331 } 332 333 // Codec2Client 334 335 Codec2Client::Base* Codec2Client::base() const { 336 return static_cast<Base*>(mBase.get()); 337 } 338 339 Codec2Client::Codec2Client(const sp<Codec2Client::Base>& base, std::string instanceName) : 340 Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) { 341 Return<sp<IClientManager>> transResult = base->getPoolClientManager(); 342 if (!transResult.isOk()) { 343 ALOGE("getPoolClientManager -- failed transaction."); 344 } else { 345 mHostPoolManager = static_cast<sp<IClientManager>>(transResult); 346 } 347 } 348 349 c2_status_t Codec2Client::createComponent( 350 const C2String& name, 351 const std::shared_ptr<Codec2Client::Listener>& listener, 352 std::shared_ptr<Codec2Client::Component>* const component) { 353 354 // TODO: Add support for Bufferpool 355 356 struct HidlListener : public IComponentListener { 357 std::weak_ptr<Component> component; 358 std::weak_ptr<Listener> base; 359 360 virtual Return<void> onWorkDone(const WorkBundle& workBundle) override { 361 std::list<std::unique_ptr<C2Work>> workItems; 362 c2_status_t status = objcpy(&workItems, workBundle); 363 if (status != C2_OK) { 364 ALOGE("onWorkDone -- received corrupted WorkBundle. " 365 "status = %d.", static_cast<int>(status)); 366 return Void(); 367 } 368 // release input buffers potentially held by the component from queue 369 std::shared_ptr<Codec2Client::Component> strongComponent = component.lock(); 370 if (strongComponent) { 371 strongComponent->handleOnWorkDone(workItems); 372 } 373 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) { 374 listener->onWorkDone(component, workItems); 375 } else { 376 ALOGW("onWorkDone -- listener died."); 377 } 378 return Void(); 379 } 380 381 virtual Return<void> onTripped( 382 const hidl_vec<SettingResult>& settingResults) override { 383 std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults( 384 settingResults.size()); 385 c2_status_t status; 386 for (size_t i = 0; i < settingResults.size(); ++i) { 387 std::unique_ptr<C2SettingResult> c2SettingResult; 388 status = objcpy(&c2SettingResult, settingResults[i]); 389 if (status != C2_OK) { 390 ALOGE("onTripped -- received corrupted SettingResult. " 391 "status = %d.", static_cast<int>(status)); 392 return Void(); 393 } 394 c2SettingResults[i] = std::move(c2SettingResult); 395 } 396 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) { 397 listener->onTripped(component, c2SettingResults); 398 } else { 399 ALOGW("onTripped -- listener died."); 400 } 401 return Void(); 402 } 403 404 virtual Return<void> onError(Status s, uint32_t errorCode) override { 405 ALOGE("onError -- status = %d, errorCode = %u.", 406 static_cast<int>(s), 407 static_cast<unsigned>(errorCode)); 408 if (std::shared_ptr<Listener> listener = base.lock()) { 409 listener->onError(component, s == Status::OK ? 410 errorCode : static_cast<c2_status_t>(s)); 411 } else { 412 ALOGW("onError -- listener died."); 413 } 414 return Void(); 415 } 416 417 virtual Return<void> onFramesRendered( 418 const hidl_vec<RenderedFrame>& renderedFrames) override { 419 if (std::shared_ptr<Listener> listener = base.lock()) { 420 std::vector<Codec2Client::Listener::RenderedFrame> 421 rfs(renderedFrames.size()); 422 for (size_t i = 0; i < rfs.size(); ++i) { 423 rfs[i].bufferQueueId = static_cast<uint64_t>( 424 renderedFrames[i].bufferQueueId); 425 rfs[i].slotId = static_cast<int32_t>( 426 renderedFrames[i].slotId); 427 rfs[i].timestampNs = static_cast<int64_t>( 428 renderedFrames[i].timestampNs); 429 } 430 listener->onFramesRendered(rfs); 431 } else { 432 ALOGW("onFramesRendered -- listener died."); 433 } 434 return Void(); 435 } 436 437 }; 438 439 c2_status_t status; 440 sp<HidlListener> hidlListener = new HidlListener(); 441 hidlListener->base = listener; 442 Return<void> transStatus = base()->createComponent( 443 name, 444 hidlListener, 445 ClientManager::getInstance(), 446 [&status, component, hidlListener]( 447 Status s, 448 const sp<IComponent>& c) { 449 status = static_cast<c2_status_t>(s); 450 if (status != C2_OK) { 451 return; 452 } 453 *component = std::make_shared<Codec2Client::Component>(c); 454 hidlListener->component = *component; 455 }); 456 if (!transStatus.isOk()) { 457 ALOGE("createComponent -- failed transaction."); 458 return C2_TRANSACTION_FAILED; 459 } 460 461 if (status != C2_OK) { 462 return status; 463 } 464 465 if (!*component) { 466 ALOGE("createComponent -- null component."); 467 return C2_CORRUPTED; 468 } 469 470 status = (*component)->setDeathListener(*component, listener); 471 if (status != C2_OK) { 472 ALOGE("createComponent -- setDeathListener returned error: %d.", 473 static_cast<int>(status)); 474 } 475 476 (*component)->mBufferPoolSender.setReceiver(mHostPoolManager); 477 return status; 478 } 479 480 c2_status_t Codec2Client::createInterface( 481 const C2String& name, 482 std::shared_ptr<Codec2Client::Interface>* const interface) { 483 c2_status_t status; 484 Return<void> transStatus = base()->createInterface( 485 name, 486 [&status, interface]( 487 Status s, 488 const sp<IComponentInterface>& i) { 489 status = static_cast<c2_status_t>(s); 490 if (status != C2_OK) { 491 ALOGE("createInterface -- call failed. " 492 "Error code = %d", static_cast<int>(status)); 493 return; 494 } 495 *interface = std::make_shared<Codec2Client::Interface>(i); 496 }); 497 if (!transStatus.isOk()) { 498 ALOGE("createInterface -- failed transaction."); 499 return C2_TRANSACTION_FAILED; 500 } 501 return status; 502 } 503 504 c2_status_t Codec2Client::createInputSurface( 505 std::shared_ptr<Codec2Client::InputSurface>* const inputSurface) { 506 Return<sp<IInputSurface>> transResult = base()->createInputSurface(); 507 if (!transResult.isOk()) { 508 ALOGE("createInputSurface -- failed transaction."); 509 return C2_TRANSACTION_FAILED; 510 } 511 *inputSurface = std::make_shared<InputSurface>( 512 static_cast<sp<IInputSurface>>(transResult)); 513 if (!*inputSurface) { 514 ALOGE("createInputSurface -- failed to create client."); 515 return C2_CORRUPTED; 516 } 517 return C2_OK; 518 } 519 520 const std::vector<C2Component::Traits>& Codec2Client::listComponents() const { 521 std::lock_guard<std::mutex> lock(mMutex); 522 if (mListed) { 523 return mTraitsList; 524 } 525 Return<void> transStatus = base()->listComponents( 526 [this](const hidl_vec<IComponentStore::ComponentTraits>& t) { 527 mTraitsList.resize(t.size()); 528 mAliasesBuffer.resize(t.size()); 529 for (size_t i = 0; i < t.size(); ++i) { 530 c2_status_t status = objcpy( 531 &mTraitsList[i], &mAliasesBuffer[i], t[i]); 532 if (status != C2_OK) { 533 ALOGE("listComponents -- corrupted output."); 534 return; 535 } 536 } 537 }); 538 if (!transStatus.isOk()) { 539 ALOGE("listComponents -- failed transaction."); 540 } 541 mListed = true; 542 return mTraitsList; 543 } 544 545 c2_status_t Codec2Client::copyBuffer( 546 const std::shared_ptr<C2Buffer>& src, 547 const std::shared_ptr<C2Buffer>& dst) { 548 // TODO: Implement? 549 (void)src; 550 (void)dst; 551 ALOGE("copyBuffer not implemented"); 552 return C2_OMITTED; 553 } 554 555 std::shared_ptr<C2ParamReflector> 556 Codec2Client::getParamReflector() { 557 // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it 558 // should reflect the HAL API. 559 struct SimpleParamReflector : public C2ParamReflector { 560 virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const { 561 hidl_vec<ParamIndex> indices(1); 562 indices[0] = static_cast<ParamIndex>(coreIndex.coreIndex()); 563 std::unique_ptr<C2StructDescriptor> descriptor; 564 Return<void> transStatus = mBase->getStructDescriptors( 565 indices, 566 [&descriptor]( 567 Status s, 568 const hidl_vec<StructDescriptor>& sd) { 569 c2_status_t status = static_cast<c2_status_t>(s); 570 if (status != C2_OK) { 571 ALOGE("getStructDescriptors -- call failed. " 572 "Error code = %d", static_cast<int>(status)); 573 descriptor.reset(); 574 return; 575 } 576 if (sd.size() != 1) { 577 ALOGD("getStructDescriptors -- returned vector of size %zu.", 578 sd.size()); 579 descriptor.reset(); 580 return; 581 } 582 status = objcpy(&descriptor, sd[0]); 583 if (status != C2_OK) { 584 ALOGD("getStructDescriptors -- failed to convert. " 585 "Error code = %d", static_cast<int>(status)); 586 descriptor.reset(); 587 return; 588 } 589 }); 590 return descriptor; 591 } 592 593 SimpleParamReflector(sp<Base> base) 594 : mBase(base) { } 595 596 sp<Base> mBase; 597 }; 598 599 return std::make_shared<SimpleParamReflector>(base()); 600 }; 601 602 std::shared_ptr<Codec2Client> Codec2Client::CreateFromService( 603 const char* instanceName, bool waitForService) { 604 if (!instanceName) { 605 return nullptr; 606 } 607 sp<Base> baseStore = waitForService ? 608 Base::getService(instanceName) : 609 Base::tryGetService(instanceName); 610 if (!baseStore) { 611 if (waitForService) { 612 ALOGE("Codec2.0 service inaccessible. Check the device manifest."); 613 } else { 614 ALOGW("Codec2.0 service not available right now. Try again later."); 615 } 616 return nullptr; 617 } 618 return std::make_shared<Codec2Client>(baseStore, instanceName); 619 } 620 621 c2_status_t Codec2Client::ForAllStores( 622 const std::string &key, 623 std::function<c2_status_t(const std::shared_ptr<Codec2Client>&)> predicate) { 624 c2_status_t status = C2_NO_INIT; // no IComponentStores present 625 626 // Cache the mapping key -> index of Codec2Client in getClient(). 627 static std::mutex key2IndexMutex; 628 static std::map<std::string, size_t> key2Index; 629 630 // By default try all stores. However, try the last known client first. If the last known 631 // client fails, retry once. We do this by pushing the last known client in front of the 632 // list of all clients. 633 std::deque<size_t> indices; 634 for (size_t index = getClientCount(); index > 0; ) { 635 indices.push_front(--index); 636 } 637 638 bool wasMapped = false; 639 std::unique_lock<std::mutex> lock(key2IndexMutex); 640 auto it = key2Index.find(key); 641 if (it != key2Index.end()) { 642 indices.push_front(it->second); 643 wasMapped = true; 644 } 645 lock.unlock(); 646 647 for (size_t index : indices) { 648 std::shared_ptr<Codec2Client> client = getClient(index); 649 if (client) { 650 status = predicate(client); 651 if (status == C2_OK) { 652 lock.lock(); 653 key2Index[key] = index; // update last known client index 654 return status; 655 } 656 } 657 if (wasMapped) { 658 ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str()); 659 wasMapped = false; 660 } 661 } 662 return status; // return the last status from a valid client 663 } 664 665 std::shared_ptr<Codec2Client::Component> 666 Codec2Client::CreateComponentByName( 667 const char* componentName, 668 const std::shared_ptr<Listener>& listener, 669 std::shared_ptr<Codec2Client>* owner) { 670 std::shared_ptr<Component> component; 671 c2_status_t status = ForAllStores( 672 componentName, 673 [owner, &component, componentName, &listener]( 674 const std::shared_ptr<Codec2Client> &client) -> c2_status_t { 675 c2_status_t status = client->createComponent(componentName, listener, &component); 676 if (status == C2_OK) { 677 if (owner) { 678 *owner = client; 679 } 680 } else if (status != C2_NOT_FOUND) { 681 ALOGD("IComponentStore(%s)::createComponent('%s') returned %s", 682 client->getInstanceName().c_str(), componentName, asString(status)); 683 } 684 return status; 685 }); 686 if (status != C2_OK) { 687 ALOGI("Could not create component '%s' (%s)", componentName, asString(status)); 688 } 689 return component; 690 } 691 692 std::shared_ptr<Codec2Client::Interface> 693 Codec2Client::CreateInterfaceByName( 694 const char* interfaceName, 695 std::shared_ptr<Codec2Client>* owner) { 696 std::shared_ptr<Interface> interface; 697 c2_status_t status = ForAllStores( 698 interfaceName, 699 [owner, &interface, interfaceName]( 700 const std::shared_ptr<Codec2Client> &client) -> c2_status_t { 701 c2_status_t status = client->createInterface(interfaceName, &interface); 702 if (status == C2_OK) { 703 if (owner) { 704 *owner = client; 705 } 706 } else if (status != C2_NOT_FOUND) { 707 ALOGD("IComponentStore(%s)::createInterface('%s') returned %s", 708 client->getInstanceName().c_str(), interfaceName, asString(status)); 709 } 710 return status; 711 }); 712 if (status != C2_OK) { 713 ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status)); 714 } 715 return interface; 716 } 717 718 const std::vector<C2Component::Traits>& Codec2Client::ListComponents() { 719 static std::vector<C2Component::Traits> traitsList = [](){ 720 std::vector<C2Component::Traits> list; 721 size_t listSize = 0; 722 ClientList clientList = getClientList(); 723 for (const std::shared_ptr<Codec2Client>& client : clientList) { 724 if (!client) { 725 continue; 726 } 727 listSize += client->listComponents().size(); 728 } 729 list.reserve(listSize); 730 for (const std::shared_ptr<Codec2Client>& client : clientList) { 731 if (!client) { 732 continue; 733 } 734 list.insert( 735 list.end(), 736 client->listComponents().begin(), 737 client->listComponents().end()); 738 } 739 return list; 740 }(); 741 742 return traitsList; 743 } 744 745 // Codec2Client::Listener 746 747 Codec2Client::Listener::~Listener() { 748 } 749 750 // Codec2Client::Component 751 752 Codec2Client::Component::Base* Codec2Client::Component::base() const { 753 return static_cast<Base*>(mBase.get()); 754 } 755 756 Codec2Client::Component::Component(const sp<Codec2Client::Component::Base>& base) : 757 Codec2Client::Configurable(base), 758 mBufferPoolSender(nullptr) { 759 } 760 761 Codec2Client::Component::~Component() { 762 } 763 764 c2_status_t Codec2Client::Component::createBlockPool( 765 C2Allocator::id_t id, 766 C2BlockPool::local_id_t* blockPoolId, 767 std::shared_ptr<Codec2Client::Configurable>* configurable) { 768 c2_status_t status; 769 Return<void> transStatus = base()->createBlockPool( 770 static_cast<uint32_t>(id), 771 [&status, blockPoolId, configurable]( 772 Status s, 773 uint64_t pId, 774 const sp<IConfigurable>& c) { 775 status = static_cast<c2_status_t>(s); 776 configurable->reset(); 777 if (status != C2_OK) { 778 ALOGE("createBlockPool -- call failed. " 779 "Error code = %d", static_cast<int>(status)); 780 return; 781 } 782 *blockPoolId = static_cast<C2BlockPool::local_id_t>(pId); 783 *configurable = std::make_shared<Codec2Client::Configurable>(c); 784 }); 785 if (!transStatus.isOk()) { 786 ALOGE("createBlockPool -- transaction failed."); 787 return C2_TRANSACTION_FAILED; 788 } 789 return status; 790 } 791 792 c2_status_t Codec2Client::Component::destroyBlockPool( 793 C2BlockPool::local_id_t localId) { 794 Return<Status> transResult = base()->destroyBlockPool( 795 static_cast<uint64_t>(localId)); 796 if (!transResult.isOk()) { 797 ALOGE("destroyBlockPool -- transaction failed."); 798 return C2_TRANSACTION_FAILED; 799 } 800 return static_cast<c2_status_t>(static_cast<Status>(transResult)); 801 } 802 803 void Codec2Client::Component::handleOnWorkDone( 804 const std::list<std::unique_ptr<C2Work>> &workItems) { 805 // Input buffers' lifetime management 806 std::vector<uint64_t> inputDone; 807 for (const std::unique_ptr<C2Work> &work : workItems) { 808 if (work) { 809 inputDone.emplace_back(work->input.ordinal.frameIndex.peeku()); 810 } 811 } 812 813 { 814 std::lock_guard<std::mutex> lock(mInputBuffersMutex); 815 for (uint64_t inputIndex : inputDone) { 816 auto it = mInputBuffers.find(inputIndex); 817 if (it == mInputBuffers.end()) { 818 ALOGI("unknown input index %llu in onWorkDone", (long long)inputIndex); 819 } else { 820 ALOGV("done with input index %llu with %zu buffers", 821 (long long)inputIndex, it->second.size()); 822 mInputBuffers.erase(it); 823 } 824 } 825 } 826 827 // Output bufferqueue-based blocks' lifetime management 828 mOutputBufferQueueMutex.lock(); 829 sp<IGraphicBufferProducer> igbp = mOutputIgbp; 830 uint64_t bqId = mOutputBqId; 831 uint32_t generation = mOutputGeneration; 832 mOutputBufferQueueMutex.unlock(); 833 834 if (igbp) { 835 holdBufferQueueBlocks(workItems, igbp, bqId, generation); 836 } 837 } 838 839 c2_status_t Codec2Client::Component::queue( 840 std::list<std::unique_ptr<C2Work>>* const items) { 841 // remember input buffers queued to hold reference to them 842 { 843 std::lock_guard<std::mutex> lock(mInputBuffersMutex); 844 for (const std::unique_ptr<C2Work> &work : *items) { 845 if (!work) { 846 continue; 847 } 848 849 uint64_t inputIndex = work->input.ordinal.frameIndex.peeku(); 850 auto res = mInputBuffers.emplace(inputIndex, work->input.buffers); 851 if (!res.second) { 852 ALOGI("duplicate input index %llu in queue", (long long)inputIndex); 853 // TODO: append? - for now we are replacing 854 res.first->second = work->input.buffers; 855 } 856 ALOGV("qeueing input index %llu with %zu buffers", 857 (long long)inputIndex, work->input.buffers.size()); 858 } 859 } 860 861 WorkBundle workBundle; 862 Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender); 863 if (hidlStatus != Status::OK) { 864 ALOGE("queue -- bad input."); 865 return C2_TRANSACTION_FAILED; 866 } 867 Return<Status> transStatus = base()->queue(workBundle); 868 if (!transStatus.isOk()) { 869 ALOGE("queue -- transaction failed."); 870 return C2_TRANSACTION_FAILED; 871 } 872 c2_status_t status = 873 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 874 if (status != C2_OK) { 875 ALOGE("queue -- call failed. " 876 "Error code = %d", static_cast<int>(status)); 877 } 878 return status; 879 } 880 881 c2_status_t Codec2Client::Component::flush( 882 C2Component::flush_mode_t mode, 883 std::list<std::unique_ptr<C2Work>>* const flushedWork) { 884 (void)mode; // Flush mode isn't supported in HIDL yet. 885 c2_status_t status; 886 Return<void> transStatus = base()->flush( 887 [&status, flushedWork]( 888 Status s, const WorkBundle& wb) { 889 status = static_cast<c2_status_t>(s); 890 if (status != C2_OK) { 891 ALOGE("flush -- call failed. " 892 "Error code = %d", static_cast<int>(status)); 893 return; 894 } 895 status = objcpy(flushedWork, wb); 896 }); 897 if (!transStatus.isOk()) { 898 ALOGE("flush -- transaction failed."); 899 return C2_TRANSACTION_FAILED; 900 } 901 902 // Indices of flushed work items. 903 std::vector<uint64_t> flushedIndices; 904 for (const std::unique_ptr<C2Work> &work : *flushedWork) { 905 if (work) { 906 flushedIndices.emplace_back(work->input.ordinal.frameIndex.peeku()); 907 } 908 } 909 910 // Input buffers' lifetime management 911 for (uint64_t flushedIndex : flushedIndices) { 912 std::lock_guard<std::mutex> lock(mInputBuffersMutex); 913 auto it = mInputBuffers.find(flushedIndex); 914 if (it == mInputBuffers.end()) { 915 ALOGI("unknown input index %llu in flush", (long long)flushedIndex); 916 } else { 917 ALOGV("flushed input index %llu with %zu buffers", 918 (long long)flushedIndex, it->second.size()); 919 mInputBuffers.erase(it); 920 } 921 } 922 923 // Output bufferqueue-based blocks' lifetime management 924 mOutputBufferQueueMutex.lock(); 925 sp<IGraphicBufferProducer> igbp = mOutputIgbp; 926 uint64_t bqId = mOutputBqId; 927 uint32_t generation = mOutputGeneration; 928 mOutputBufferQueueMutex.unlock(); 929 930 if (igbp) { 931 holdBufferQueueBlocks(*flushedWork, igbp, bqId, generation); 932 } 933 934 return status; 935 } 936 937 c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) { 938 Return<Status> transStatus = base()->drain( 939 mode == C2Component::DRAIN_COMPONENT_WITH_EOS); 940 if (!transStatus.isOk()) { 941 ALOGE("drain -- transaction failed."); 942 return C2_TRANSACTION_FAILED; 943 } 944 c2_status_t status = 945 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 946 if (status != C2_OK) { 947 ALOGE("drain -- call failed. " 948 "Error code = %d", static_cast<int>(status)); 949 } 950 return status; 951 } 952 953 c2_status_t Codec2Client::Component::start() { 954 Return<Status> transStatus = base()->start(); 955 if (!transStatus.isOk()) { 956 ALOGE("start -- transaction failed."); 957 return C2_TRANSACTION_FAILED; 958 } 959 c2_status_t status = 960 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 961 if (status != C2_OK) { 962 ALOGE("start -- call failed. " 963 "Error code = %d", static_cast<int>(status)); 964 } 965 return status; 966 } 967 968 c2_status_t Codec2Client::Component::stop() { 969 Return<Status> transStatus = base()->stop(); 970 if (!transStatus.isOk()) { 971 ALOGE("stop -- transaction failed."); 972 return C2_TRANSACTION_FAILED; 973 } 974 c2_status_t status = 975 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 976 if (status != C2_OK) { 977 ALOGE("stop -- call failed. " 978 "Error code = %d", static_cast<int>(status)); 979 } 980 mInputBuffersMutex.lock(); 981 mInputBuffers.clear(); 982 mInputBuffersMutex.unlock(); 983 return status; 984 } 985 986 c2_status_t Codec2Client::Component::reset() { 987 Return<Status> transStatus = base()->reset(); 988 if (!transStatus.isOk()) { 989 ALOGE("reset -- transaction failed."); 990 return C2_TRANSACTION_FAILED; 991 } 992 c2_status_t status = 993 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 994 if (status != C2_OK) { 995 ALOGE("reset -- call failed. " 996 "Error code = %d", static_cast<int>(status)); 997 } 998 mInputBuffersMutex.lock(); 999 mInputBuffers.clear(); 1000 mInputBuffersMutex.unlock(); 1001 return status; 1002 } 1003 1004 c2_status_t Codec2Client::Component::release() { 1005 Return<Status> transStatus = base()->release(); 1006 if (!transStatus.isOk()) { 1007 ALOGE("release -- transaction failed."); 1008 return C2_TRANSACTION_FAILED; 1009 } 1010 c2_status_t status = 1011 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 1012 if (status != C2_OK) { 1013 ALOGE("release -- call failed. " 1014 "Error code = %d", static_cast<int>(status)); 1015 } 1016 mInputBuffersMutex.lock(); 1017 mInputBuffers.clear(); 1018 mInputBuffersMutex.unlock(); 1019 return status; 1020 } 1021 1022 c2_status_t Codec2Client::Component::setOutputSurface( 1023 C2BlockPool::local_id_t blockPoolId, 1024 const sp<IGraphicBufferProducer>& surface, 1025 uint32_t generation) { 1026 sp<HGraphicBufferProducer> igbp = surface->getHalInterface(); 1027 if (!igbp) { 1028 igbp = new TWGraphicBufferProducer<HGraphicBufferProducer>(surface); 1029 } 1030 1031 Return<Status> transStatus = base()->setOutputSurface( 1032 static_cast<uint64_t>(blockPoolId), igbp); 1033 if (!transStatus.isOk()) { 1034 ALOGE("setOutputSurface -- transaction failed."); 1035 return C2_TRANSACTION_FAILED; 1036 } 1037 c2_status_t status = 1038 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 1039 if (status != C2_OK) { 1040 ALOGE("setOutputSurface -- call failed. " 1041 "Error code = %d", static_cast<int>(status)); 1042 } else { 1043 std::lock_guard<std::mutex> lock(mOutputBufferQueueMutex); 1044 if (mOutputIgbp != surface) { 1045 mOutputIgbp = surface; 1046 if (!surface) { 1047 mOutputBqId = 0; 1048 } else if (surface->getUniqueId(&mOutputBqId) != OK) { 1049 ALOGE("setOutputSurface -- cannot obtain bufferqueue id."); 1050 } 1051 } 1052 mOutputGeneration = generation; 1053 } 1054 return status; 1055 } 1056 1057 status_t Codec2Client::Component::queueToOutputSurface( 1058 const C2ConstGraphicBlock& block, 1059 const QueueBufferInput& input, 1060 QueueBufferOutput* output) { 1061 uint64_t bqId; 1062 int32_t bqSlot; 1063 if (!getBufferQueueAssignment(block, &bqId, &bqSlot) || bqId == 0) { 1064 // Block not from bufferqueue -- it must be attached before queuing. 1065 1066 mOutputBufferQueueMutex.lock(); 1067 sp<IGraphicBufferProducer> outputIgbp = mOutputIgbp; 1068 uint32_t outputGeneration = mOutputGeneration; 1069 mOutputBufferQueueMutex.unlock(); 1070 1071 status_t status = !attachToBufferQueue(block, 1072 outputIgbp, 1073 outputGeneration, 1074 &bqSlot); 1075 if (status != OK) { 1076 ALOGW("queueToOutputSurface -- attaching failed."); 1077 return INVALID_OPERATION; 1078 } 1079 1080 status = outputIgbp->queueBuffer(static_cast<int>(bqSlot), 1081 input, output); 1082 if (status != OK) { 1083 ALOGE("queueToOutputSurface -- queueBuffer() failed " 1084 "on non-bufferqueue-based block. " 1085 "Error code = %d.", 1086 static_cast<int>(status)); 1087 return status; 1088 } 1089 return OK; 1090 } 1091 1092 mOutputBufferQueueMutex.lock(); 1093 sp<IGraphicBufferProducer> outputIgbp = mOutputIgbp; 1094 uint64_t outputBqId = mOutputBqId; 1095 mOutputBufferQueueMutex.unlock(); 1096 1097 if (!outputIgbp) { 1098 ALOGE("queueToOutputSurface -- output surface is null."); 1099 return NO_INIT; 1100 } 1101 1102 if (bqId != outputBqId) { 1103 ALOGE("queueToOutputSurface -- bufferqueue ids mismatch."); 1104 return DEAD_OBJECT; 1105 } 1106 1107 status_t status = outputIgbp->queueBuffer(static_cast<int>(bqSlot), 1108 input, output); 1109 if (status != OK) { 1110 ALOGE("queueToOutputSurface -- queueBuffer() failed " 1111 "on bufferqueue-based block. " 1112 "Error code = %d.", 1113 static_cast<int>(status)); 1114 return status; 1115 } 1116 if (!yieldBufferQueueBlock(block)) { 1117 ALOGE("queueToOutputSurface -- cannot yield bufferqueue-based block " 1118 "to the bufferqueue."); 1119 return UNKNOWN_ERROR; 1120 } 1121 return OK; 1122 } 1123 1124 c2_status_t Codec2Client::Component::connectToOmxInputSurface( 1125 const sp<HGraphicBufferProducer>& producer, 1126 const sp<HGraphicBufferSource>& source) { 1127 Return<Status> transStatus = base()->connectToOmxInputSurface( 1128 producer, source); 1129 if (!transStatus.isOk()) { 1130 ALOGE("connectToOmxInputSurface -- transaction failed."); 1131 return C2_TRANSACTION_FAILED; 1132 } 1133 c2_status_t status = 1134 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 1135 if (status != C2_OK) { 1136 ALOGE("connectToOmxInputSurface -- call failed. " 1137 "Error code = %d", static_cast<int>(status)); 1138 } 1139 return status; 1140 } 1141 1142 c2_status_t Codec2Client::Component::disconnectFromInputSurface() { 1143 Return<Status> transStatus = base()->disconnectFromInputSurface(); 1144 if (!transStatus.isOk()) { 1145 ALOGE("disconnectToInputSurface -- transaction failed."); 1146 return C2_TRANSACTION_FAILED; 1147 } 1148 c2_status_t status = 1149 static_cast<c2_status_t>(static_cast<Status>(transStatus)); 1150 if (status != C2_OK) { 1151 ALOGE("disconnectFromInputSurface -- call failed. " 1152 "Error code = %d", static_cast<int>(status)); 1153 } 1154 return status; 1155 } 1156 1157 c2_status_t Codec2Client::Component::setDeathListener( 1158 const std::shared_ptr<Component>& component, 1159 const std::shared_ptr<Listener>& listener) { 1160 1161 struct HidlDeathRecipient : public hardware::hidl_death_recipient { 1162 std::weak_ptr<Component> component; 1163 std::weak_ptr<Listener> base; 1164 1165 virtual void serviceDied( 1166 uint64_t /* cookie */, 1167 const wp<::android::hidl::base::V1_0::IBase>& /* who */ 1168 ) override { 1169 if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) { 1170 listener->onDeath(component); 1171 } else { 1172 ALOGW("onDeath -- listener died."); 1173 } 1174 } 1175 }; 1176 1177 sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient(); 1178 deathRecipient->base = listener; 1179 deathRecipient->component = component; 1180 1181 component->mDeathRecipient = deathRecipient; 1182 Return<bool> transResult = component->base()->linkToDeath( 1183 component->mDeathRecipient, 0); 1184 if (!transResult.isOk()) { 1185 ALOGE("setDeathListener -- failed transaction: linkToDeath."); 1186 return C2_TRANSACTION_FAILED; 1187 } 1188 if (!static_cast<bool>(transResult)) { 1189 ALOGE("setDeathListener -- linkToDeath call failed."); 1190 return C2_CORRUPTED; 1191 } 1192 return C2_OK; 1193 } 1194 1195 // Codec2Client::InputSurface 1196 1197 Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const { 1198 return static_cast<Base*>(mBase.get()); 1199 } 1200 1201 Codec2Client::InputSurface::InputSurface(const sp<IInputSurface>& base) : 1202 mBase(base), 1203 mGraphicBufferProducer(new 1204 ::android::hardware::graphics::bufferqueue::V1_0::utils:: 1205 H2BGraphicBufferProducer(base)) { 1206 } 1207 1208 c2_status_t Codec2Client::InputSurface::connectToComponent( 1209 const std::shared_ptr<Codec2Client::Component>& component, 1210 std::shared_ptr<Connection>* connection) { 1211 c2_status_t status; 1212 Return<void> transStatus = base()->connectToComponent( 1213 component->base(), 1214 [&status, connection]( 1215 Status s, 1216 const sp<IInputSurfaceConnection>& c) { 1217 status = static_cast<c2_status_t>(s); 1218 if (status != C2_OK) { 1219 ALOGE("connectToComponent -- call failed. " 1220 "Error code = %d", static_cast<int>(status)); 1221 return; 1222 } 1223 *connection = std::make_shared<Connection>(c); 1224 }); 1225 if (!transStatus.isOk()) { 1226 ALOGE("connect -- transaction failed."); 1227 return C2_TRANSACTION_FAILED; 1228 } 1229 return status; 1230 } 1231 1232 std::shared_ptr<Codec2Client::Configurable> 1233 Codec2Client::InputSurface::getConfigurable() const { 1234 Return<sp<IConfigurable>> transResult = base()->getConfigurable(); 1235 if (!transResult.isOk()) { 1236 ALOGW("getConfigurable -- transaction failed."); 1237 return nullptr; 1238 } 1239 if (!static_cast<sp<IConfigurable>>(transResult)) { 1240 ALOGW("getConfigurable -- null pointer."); 1241 return nullptr; 1242 } 1243 return std::make_shared<Configurable>(transResult); 1244 } 1245 1246 const sp<IGraphicBufferProducer>& 1247 Codec2Client::InputSurface::getGraphicBufferProducer() const { 1248 return mGraphicBufferProducer; 1249 } 1250 1251 // Codec2Client::InputSurfaceConnection 1252 1253 Codec2Client::InputSurfaceConnection::Base* 1254 Codec2Client::InputSurfaceConnection::base() const { 1255 return static_cast<Base*>(mBase.get()); 1256 } 1257 1258 Codec2Client::InputSurfaceConnection::InputSurfaceConnection( 1259 const sp<Codec2Client::InputSurfaceConnection::Base>& base) : 1260 mBase(base) { 1261 } 1262 1263 c2_status_t Codec2Client::InputSurfaceConnection::disconnect() { 1264 Return<Status> transResult = base()->disconnect(); 1265 return static_cast<c2_status_t>(static_cast<Status>(transResult)); 1266 } 1267 1268 } // namespace android 1269 1270