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