/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "Codec2Client" #include #include #include #include #include #include #include #include #include #include #include #include #undef LOG #include #include #include #include #include #include #include #include #include namespace android { using ::android::hardware::hidl_vec; using ::android::hardware::hidl_string; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::TWGraphicBufferProducer; using namespace ::hardware::google::media::c2::V1_0; using namespace ::hardware::google::media::c2::V1_0::utils; using namespace ::android::hardware::media::bufferpool::V1_0; using namespace ::android::hardware::media::bufferpool::V1_0::implementation; namespace /* unnamed */ { // c2_status_t value that corresponds to hwbinder transaction failure. constexpr c2_status_t C2_TRANSACTION_FAILED = C2_CORRUPTED; // List of known IComponentStore services. constexpr const char* kClientNames[] = { "default", "software", }; typedef std::array< std::shared_ptr, std::extent::value> ClientList; // Convenience methods to obtain known clients. size_t getClientCount() { // TODO: this may not work if there is no default service return std::extent::value; } std::shared_ptr getClient(size_t index) { return Codec2Client::CreateFromService(kClientNames[index]); } ClientList getClientList() { ClientList list; for (size_t i = 0; i < list.size(); ++i) { list[i] = getClient(i); } return list; } } // unnamed // Codec2ConfigurableClient const C2String& Codec2ConfigurableClient::getName() const { return mName; } Codec2ConfigurableClient::Base* Codec2ConfigurableClient::base() const { return static_cast(mBase.get()); } Codec2ConfigurableClient::Codec2ConfigurableClient( const sp& base) : mBase(base) { Return transStatus = base->getName( [this](const hidl_string& name) { mName = name.c_str(); }); if (!transStatus.isOk()) { ALOGE("Cannot obtain name from IConfigurable."); } } c2_status_t Codec2ConfigurableClient::query( const std::vector &stackParams, const std::vector &heapParamIndices, c2_blocking_t mayBlock, std::vector>* const heapParams) const { hidl_vec indices( stackParams.size() + heapParamIndices.size()); size_t numIndices = 0; for (C2Param* const& stackParam : stackParams) { if (!stackParam) { ALOGW("query -- null stack param encountered."); continue; } indices[numIndices++] = static_cast(stackParam->index()); } size_t numStackIndices = numIndices; for (const C2Param::Index& index : heapParamIndices) { indices[numIndices++] = static_cast(static_cast(index)); } indices.resize(numIndices); if (heapParams) { heapParams->reserve(heapParams->size() + numIndices); } c2_status_t status; Return transStatus = base()->query( indices, mayBlock == C2_MAY_BLOCK, [&status, &numStackIndices, &stackParams, heapParams]( Status s, const Params& p) { status = static_cast(s); if (status != C2_OK && status != C2_BAD_INDEX) { ALOGE("query -- call failed. " "Error code = %d", static_cast(status)); return; } std::vector paramPointers; c2_status_t parseStatus = parseParamsBlob(¶mPointers, p); if (parseStatus != C2_OK) { ALOGE("query -- error while parsing params. " "Error code = %d", static_cast(status)); status = parseStatus; return; } size_t i = 0; for (auto it = paramPointers.begin(); it != paramPointers.end(); ) { C2Param* paramPointer = *it; if (numStackIndices > 0) { --numStackIndices; if (!paramPointer) { ALOGW("query -- null stack param."); ++it; continue; } for (; i < stackParams.size() && !stackParams[i]; ) { ++i; } if (i >= stackParams.size()) { ALOGE("query -- unexpected error."); status = C2_CORRUPTED; return; } if (stackParams[i]->index() != paramPointer->index()) { ALOGW("query -- param skipped. index = %d", static_cast(stackParams[i]->index())); stackParams[i++]->invalidate(); continue; } if (!stackParams[i++]->updateFrom(*paramPointer)) { ALOGW("query -- param update failed. index = %d", static_cast(paramPointer->index())); } } else { if (!paramPointer) { ALOGW("query -- null heap param."); ++it; continue; } if (!heapParams) { ALOGW("query -- extra stack param."); } heapParams->emplace_back(C2Param::Copy(*paramPointer)); } ++it; } }); if (!transStatus.isOk()) { ALOGE("query -- transaction failed."); return C2_TRANSACTION_FAILED; } return status; } c2_status_t Codec2ConfigurableClient::config( const std::vector ¶ms, c2_blocking_t mayBlock, std::vector>* const failures) { Params hidlParams; Status hidlStatus = createParamsBlob(&hidlParams, params); if (hidlStatus != Status::OK) { ALOGE("config -- bad input."); return C2_TRANSACTION_FAILED; } c2_status_t status; Return transStatus = base()->config( hidlParams, mayBlock == C2_MAY_BLOCK, [&status, ¶ms, failures]( Status s, const hidl_vec f, const Params& o) { status = static_cast(s); if (status != C2_OK) { ALOGD("config -- call failed. " "Error code = %d", static_cast(status)); } size_t i = failures->size(); failures->resize(i + f.size()); for (const SettingResult& sf : f) { status = objcpy(&(*failures)[i++], sf); if (status != C2_OK) { ALOGE("config -- invalid returned SettingResult. " "Error code = %d", static_cast(status)); return; } } status = updateParamsFromBlob(params, o); }); if (!transStatus.isOk()) { ALOGE("config -- transaction failed."); return C2_TRANSACTION_FAILED; } return status; } c2_status_t Codec2ConfigurableClient::querySupportedParams( std::vector>* const params) const { // TODO: Cache and query properly! c2_status_t status; Return transStatus = base()->querySupportedParams( std::numeric_limits::min(), std::numeric_limits::max(), [&status, params]( Status s, const hidl_vec& p) { status = static_cast(s); if (status != C2_OK) { ALOGE("querySupportedParams -- call failed. " "Error code = %d", static_cast(status)); return; } size_t i = params->size(); params->resize(i + p.size()); for (const ParamDescriptor& sp : p) { status = objcpy(&(*params)[i++], sp); if (status != C2_OK) { ALOGE("querySupportedParams -- " "invalid returned ParamDescriptor. " "Error code = %d", static_cast(status)); return; } } }); if (!transStatus.isOk()) { ALOGE("querySupportedParams -- transaction failed."); return C2_TRANSACTION_FAILED; } return status; } c2_status_t Codec2ConfigurableClient::querySupportedValues( std::vector& fields, c2_blocking_t mayBlock) const { hidl_vec inFields(fields.size()); for (size_t i = 0; i < fields.size(); ++i) { Status hidlStatus = objcpy(&inFields[i], fields[i]); if (hidlStatus != Status::OK) { ALOGE("querySupportedValues -- bad input"); return C2_TRANSACTION_FAILED; } } c2_status_t status; Return transStatus = base()->querySupportedValues( inFields, mayBlock == C2_MAY_BLOCK, [&status, &inFields, &fields]( Status s, const hidl_vec& r) { status = static_cast(s); if (status != C2_OK) { ALOGE("querySupportedValues -- call failed. " "Error code = %d", static_cast(status)); return; } if (r.size() != fields.size()) { ALOGE("querySupportedValues -- input and output lists " "have different sizes."); status = C2_CORRUPTED; return; } for (size_t i = 0; i < fields.size(); ++i) { status = objcpy(&fields[i], inFields[i], r[i]); if (status != C2_OK) { ALOGE("querySupportedValues -- invalid returned value. " "Error code = %d", static_cast(status)); return; } } }); if (!transStatus.isOk()) { ALOGE("querySupportedValues -- transaction failed."); return C2_TRANSACTION_FAILED; } return status; } // Codec2Client Codec2Client::Base* Codec2Client::base() const { return static_cast(mBase.get()); } Codec2Client::Codec2Client(const sp& base, std::string instanceName) : Codec2ConfigurableClient(base), mListed(false), mInstanceName(instanceName) { Return> transResult = base->getPoolClientManager(); if (!transResult.isOk()) { ALOGE("getPoolClientManager -- failed transaction."); } else { mHostPoolManager = static_cast>(transResult); } } c2_status_t Codec2Client::createComponent( const C2String& name, const std::shared_ptr& listener, std::shared_ptr* const component) { // TODO: Add support for Bufferpool struct HidlListener : public IComponentListener { std::weak_ptr component; std::weak_ptr base; virtual Return onWorkDone(const WorkBundle& workBundle) override { std::list> workItems; c2_status_t status = objcpy(&workItems, workBundle); if (status != C2_OK) { ALOGE("onWorkDone -- received corrupted WorkBundle. " "status = %d.", static_cast(status)); return Void(); } // release input buffers potentially held by the component from queue std::shared_ptr strongComponent = component.lock(); if (strongComponent) { strongComponent->handleOnWorkDone(workItems); } if (std::shared_ptr listener = base.lock()) { listener->onWorkDone(component, workItems); } else { ALOGW("onWorkDone -- listener died."); } return Void(); } virtual Return onTripped( const hidl_vec& settingResults) override { std::vector> c2SettingResults( settingResults.size()); c2_status_t status; for (size_t i = 0; i < settingResults.size(); ++i) { std::unique_ptr c2SettingResult; status = objcpy(&c2SettingResult, settingResults[i]); if (status != C2_OK) { ALOGE("onTripped -- received corrupted SettingResult. " "status = %d.", static_cast(status)); return Void(); } c2SettingResults[i] = std::move(c2SettingResult); } if (std::shared_ptr listener = base.lock()) { listener->onTripped(component, c2SettingResults); } else { ALOGW("onTripped -- listener died."); } return Void(); } virtual Return onError(Status s, uint32_t errorCode) override { ALOGE("onError -- status = %d, errorCode = %u.", static_cast(s), static_cast(errorCode)); if (std::shared_ptr listener = base.lock()) { listener->onError(component, s == Status::OK ? errorCode : static_cast(s)); } else { ALOGW("onError -- listener died."); } return Void(); } virtual Return onFramesRendered( const hidl_vec& renderedFrames) override { if (std::shared_ptr listener = base.lock()) { std::vector rfs(renderedFrames.size()); for (size_t i = 0; i < rfs.size(); ++i) { rfs[i].bufferQueueId = static_cast( renderedFrames[i].bufferQueueId); rfs[i].slotId = static_cast( renderedFrames[i].slotId); rfs[i].timestampNs = static_cast( renderedFrames[i].timestampNs); } listener->onFramesRendered(rfs); } else { ALOGW("onFramesRendered -- listener died."); } return Void(); } }; c2_status_t status; sp hidlListener = new HidlListener(); hidlListener->base = listener; Return transStatus = base()->createComponent( name, hidlListener, ClientManager::getInstance(), [&status, component, hidlListener]( Status s, const sp& c) { status = static_cast(s); if (status != C2_OK) { return; } *component = std::make_shared(c); hidlListener->component = *component; }); if (!transStatus.isOk()) { ALOGE("createComponent -- failed transaction."); return C2_TRANSACTION_FAILED; } if (status != C2_OK) { return status; } if (!*component) { ALOGE("createComponent -- null component."); return C2_CORRUPTED; } status = (*component)->setDeathListener(*component, listener); if (status != C2_OK) { ALOGE("createComponent -- setDeathListener returned error: %d.", static_cast(status)); } (*component)->mBufferPoolSender.setReceiver(mHostPoolManager); return status; } c2_status_t Codec2Client::createInterface( const C2String& name, std::shared_ptr* const interface) { c2_status_t status; Return transStatus = base()->createInterface( name, [&status, interface]( Status s, const sp& i) { status = static_cast(s); if (status != C2_OK) { ALOGE("createInterface -- call failed. " "Error code = %d", static_cast(status)); return; } *interface = std::make_shared(i); }); if (!transStatus.isOk()) { ALOGE("createInterface -- failed transaction."); return C2_TRANSACTION_FAILED; } return status; } c2_status_t Codec2Client::createInputSurface( std::shared_ptr* const inputSurface) { Return> transResult = base()->createInputSurface(); if (!transResult.isOk()) { ALOGE("createInputSurface -- failed transaction."); return C2_TRANSACTION_FAILED; } *inputSurface = std::make_shared( static_cast>(transResult)); if (!*inputSurface) { ALOGE("createInputSurface -- failed to create client."); return C2_CORRUPTED; } return C2_OK; } const std::vector& Codec2Client::listComponents() const { std::lock_guard lock(mMutex); if (mListed) { return mTraitsList; } Return transStatus = base()->listComponents( [this](const hidl_vec& t) { mTraitsList.resize(t.size()); mAliasesBuffer.resize(t.size()); for (size_t i = 0; i < t.size(); ++i) { c2_status_t status = objcpy( &mTraitsList[i], &mAliasesBuffer[i], t[i]); if (status != C2_OK) { ALOGE("listComponents -- corrupted output."); return; } } }); if (!transStatus.isOk()) { ALOGE("listComponents -- failed transaction."); } mListed = true; return mTraitsList; } c2_status_t Codec2Client::copyBuffer( const std::shared_ptr& src, const std::shared_ptr& dst) { // TODO: Implement? (void)src; (void)dst; ALOGE("copyBuffer not implemented"); return C2_OMITTED; } std::shared_ptr Codec2Client::getParamReflector() { // TODO: this is not meant to be exposed as C2ParamReflector on the client side; instead, it // should reflect the HAL API. struct SimpleParamReflector : public C2ParamReflector { virtual std::unique_ptr describe(C2Param::CoreIndex coreIndex) const { hidl_vec indices(1); indices[0] = static_cast(coreIndex.coreIndex()); std::unique_ptr descriptor; Return transStatus = mBase->getStructDescriptors( indices, [&descriptor]( Status s, const hidl_vec& sd) { c2_status_t status = static_cast(s); if (status != C2_OK) { ALOGE("getStructDescriptors -- call failed. " "Error code = %d", static_cast(status)); descriptor.reset(); return; } if (sd.size() != 1) { ALOGD("getStructDescriptors -- returned vector of size %zu.", sd.size()); descriptor.reset(); return; } status = objcpy(&descriptor, sd[0]); if (status != C2_OK) { ALOGD("getStructDescriptors -- failed to convert. " "Error code = %d", static_cast(status)); descriptor.reset(); return; } }); return descriptor; } SimpleParamReflector(sp base) : mBase(base) { } sp mBase; }; return std::make_shared(base()); }; std::shared_ptr Codec2Client::CreateFromService( const char* instanceName, bool waitForService) { if (!instanceName) { return nullptr; } sp baseStore = waitForService ? Base::getService(instanceName) : Base::tryGetService(instanceName); if (!baseStore) { if (waitForService) { ALOGE("Codec2.0 service inaccessible. Check the device manifest."); } else { ALOGW("Codec2.0 service not available right now. Try again later."); } return nullptr; } return std::make_shared(baseStore, instanceName); } c2_status_t Codec2Client::ForAllStores( const std::string &key, std::function&)> predicate) { c2_status_t status = C2_NO_INIT; // no IComponentStores present // Cache the mapping key -> index of Codec2Client in getClient(). static std::mutex key2IndexMutex; static std::map key2Index; // By default try all stores. However, try the last known client first. If the last known // client fails, retry once. We do this by pushing the last known client in front of the // list of all clients. std::deque indices; for (size_t index = getClientCount(); index > 0; ) { indices.push_front(--index); } bool wasMapped = false; std::unique_lock lock(key2IndexMutex); auto it = key2Index.find(key); if (it != key2Index.end()) { indices.push_front(it->second); wasMapped = true; } lock.unlock(); for (size_t index : indices) { std::shared_ptr client = getClient(index); if (client) { status = predicate(client); if (status == C2_OK) { lock.lock(); key2Index[key] = index; // update last known client index return status; } } if (wasMapped) { ALOGI("Could not find '%s' in last instance. Retrying...", key.c_str()); wasMapped = false; } } return status; // return the last status from a valid client } std::shared_ptr Codec2Client::CreateComponentByName( const char* componentName, const std::shared_ptr& listener, std::shared_ptr* owner) { std::shared_ptr component; c2_status_t status = ForAllStores( componentName, [owner, &component, componentName, &listener]( const std::shared_ptr &client) -> c2_status_t { c2_status_t status = client->createComponent(componentName, listener, &component); if (status == C2_OK) { if (owner) { *owner = client; } } else if (status != C2_NOT_FOUND) { ALOGD("IComponentStore(%s)::createComponent('%s') returned %s", client->getInstanceName().c_str(), componentName, asString(status)); } return status; }); if (status != C2_OK) { ALOGI("Could not create component '%s' (%s)", componentName, asString(status)); } return component; } std::shared_ptr Codec2Client::CreateInterfaceByName( const char* interfaceName, std::shared_ptr* owner) { std::shared_ptr interface; c2_status_t status = ForAllStores( interfaceName, [owner, &interface, interfaceName]( const std::shared_ptr &client) -> c2_status_t { c2_status_t status = client->createInterface(interfaceName, &interface); if (status == C2_OK) { if (owner) { *owner = client; } } else if (status != C2_NOT_FOUND) { ALOGD("IComponentStore(%s)::createInterface('%s') returned %s", client->getInstanceName().c_str(), interfaceName, asString(status)); } return status; }); if (status != C2_OK) { ALOGI("Could not create interface '%s' (%s)", interfaceName, asString(status)); } return interface; } const std::vector& Codec2Client::ListComponents() { static std::vector traitsList = [](){ std::vector list; size_t listSize = 0; ClientList clientList = getClientList(); for (const std::shared_ptr& client : clientList) { if (!client) { continue; } listSize += client->listComponents().size(); } list.reserve(listSize); for (const std::shared_ptr& client : clientList) { if (!client) { continue; } list.insert( list.end(), client->listComponents().begin(), client->listComponents().end()); } return list; }(); return traitsList; } // Codec2Client::Listener Codec2Client::Listener::~Listener() { } // Codec2Client::Component Codec2Client::Component::Base* Codec2Client::Component::base() const { return static_cast(mBase.get()); } Codec2Client::Component::Component(const sp& base) : Codec2Client::Configurable(base), mBufferPoolSender(nullptr) { } Codec2Client::Component::~Component() { } c2_status_t Codec2Client::Component::createBlockPool( C2Allocator::id_t id, C2BlockPool::local_id_t* blockPoolId, std::shared_ptr* configurable) { c2_status_t status; Return transStatus = base()->createBlockPool( static_cast(id), [&status, blockPoolId, configurable]( Status s, uint64_t pId, const sp& c) { status = static_cast(s); configurable->reset(); if (status != C2_OK) { ALOGE("createBlockPool -- call failed. " "Error code = %d", static_cast(status)); return; } *blockPoolId = static_cast(pId); *configurable = std::make_shared(c); }); if (!transStatus.isOk()) { ALOGE("createBlockPool -- transaction failed."); return C2_TRANSACTION_FAILED; } return status; } c2_status_t Codec2Client::Component::destroyBlockPool( C2BlockPool::local_id_t localId) { Return transResult = base()->destroyBlockPool( static_cast(localId)); if (!transResult.isOk()) { ALOGE("destroyBlockPool -- transaction failed."); return C2_TRANSACTION_FAILED; } return static_cast(static_cast(transResult)); } void Codec2Client::Component::handleOnWorkDone( const std::list> &workItems) { // Input buffers' lifetime management std::vector inputDone; for (const std::unique_ptr &work : workItems) { if (work) { inputDone.emplace_back(work->input.ordinal.frameIndex.peeku()); } } { std::lock_guard lock(mInputBuffersMutex); for (uint64_t inputIndex : inputDone) { auto it = mInputBuffers.find(inputIndex); if (it == mInputBuffers.end()) { ALOGI("unknown input index %llu in onWorkDone", (long long)inputIndex); } else { ALOGV("done with input index %llu with %zu buffers", (long long)inputIndex, it->second.size()); mInputBuffers.erase(it); } } } // Output bufferqueue-based blocks' lifetime management mOutputBufferQueueMutex.lock(); sp igbp = mOutputIgbp; uint64_t bqId = mOutputBqId; uint32_t generation = mOutputGeneration; mOutputBufferQueueMutex.unlock(); if (igbp) { holdBufferQueueBlocks(workItems, igbp, bqId, generation); } } c2_status_t Codec2Client::Component::queue( std::list>* const items) { // remember input buffers queued to hold reference to them { std::lock_guard lock(mInputBuffersMutex); for (const std::unique_ptr &work : *items) { if (!work) { continue; } uint64_t inputIndex = work->input.ordinal.frameIndex.peeku(); auto res = mInputBuffers.emplace(inputIndex, work->input.buffers); if (!res.second) { ALOGI("duplicate input index %llu in queue", (long long)inputIndex); // TODO: append? - for now we are replacing res.first->second = work->input.buffers; } ALOGV("qeueing input index %llu with %zu buffers", (long long)inputIndex, work->input.buffers.size()); } } WorkBundle workBundle; Status hidlStatus = objcpy(&workBundle, *items, &mBufferPoolSender); if (hidlStatus != Status::OK) { ALOGE("queue -- bad input."); return C2_TRANSACTION_FAILED; } Return transStatus = base()->queue(workBundle); if (!transStatus.isOk()) { ALOGE("queue -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("queue -- call failed. " "Error code = %d", static_cast(status)); } return status; } c2_status_t Codec2Client::Component::flush( C2Component::flush_mode_t mode, std::list>* const flushedWork) { (void)mode; // Flush mode isn't supported in HIDL yet. c2_status_t status; Return transStatus = base()->flush( [&status, flushedWork]( Status s, const WorkBundle& wb) { status = static_cast(s); if (status != C2_OK) { ALOGE("flush -- call failed. " "Error code = %d", static_cast(status)); return; } status = objcpy(flushedWork, wb); }); if (!transStatus.isOk()) { ALOGE("flush -- transaction failed."); return C2_TRANSACTION_FAILED; } // Indices of flushed work items. std::vector flushedIndices; for (const std::unique_ptr &work : *flushedWork) { if (work) { flushedIndices.emplace_back(work->input.ordinal.frameIndex.peeku()); } } // Input buffers' lifetime management for (uint64_t flushedIndex : flushedIndices) { std::lock_guard lock(mInputBuffersMutex); auto it = mInputBuffers.find(flushedIndex); if (it == mInputBuffers.end()) { ALOGI("unknown input index %llu in flush", (long long)flushedIndex); } else { ALOGV("flushed input index %llu with %zu buffers", (long long)flushedIndex, it->second.size()); mInputBuffers.erase(it); } } // Output bufferqueue-based blocks' lifetime management mOutputBufferQueueMutex.lock(); sp igbp = mOutputIgbp; uint64_t bqId = mOutputBqId; uint32_t generation = mOutputGeneration; mOutputBufferQueueMutex.unlock(); if (igbp) { holdBufferQueueBlocks(*flushedWork, igbp, bqId, generation); } return status; } c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) { Return transStatus = base()->drain( mode == C2Component::DRAIN_COMPONENT_WITH_EOS); if (!transStatus.isOk()) { ALOGE("drain -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("drain -- call failed. " "Error code = %d", static_cast(status)); } return status; } c2_status_t Codec2Client::Component::start() { Return transStatus = base()->start(); if (!transStatus.isOk()) { ALOGE("start -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("start -- call failed. " "Error code = %d", static_cast(status)); } return status; } c2_status_t Codec2Client::Component::stop() { Return transStatus = base()->stop(); if (!transStatus.isOk()) { ALOGE("stop -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("stop -- call failed. " "Error code = %d", static_cast(status)); } mInputBuffersMutex.lock(); mInputBuffers.clear(); mInputBuffersMutex.unlock(); return status; } c2_status_t Codec2Client::Component::reset() { Return transStatus = base()->reset(); if (!transStatus.isOk()) { ALOGE("reset -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("reset -- call failed. " "Error code = %d", static_cast(status)); } mInputBuffersMutex.lock(); mInputBuffers.clear(); mInputBuffersMutex.unlock(); return status; } c2_status_t Codec2Client::Component::release() { Return transStatus = base()->release(); if (!transStatus.isOk()) { ALOGE("release -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("release -- call failed. " "Error code = %d", static_cast(status)); } mInputBuffersMutex.lock(); mInputBuffers.clear(); mInputBuffersMutex.unlock(); return status; } c2_status_t Codec2Client::Component::setOutputSurface( C2BlockPool::local_id_t blockPoolId, const sp& surface, uint32_t generation) { sp igbp = surface->getHalInterface(); if (!igbp) { igbp = new TWGraphicBufferProducer(surface); } Return transStatus = base()->setOutputSurface( static_cast(blockPoolId), igbp); if (!transStatus.isOk()) { ALOGE("setOutputSurface -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("setOutputSurface -- call failed. " "Error code = %d", static_cast(status)); } else { std::lock_guard lock(mOutputBufferQueueMutex); if (mOutputIgbp != surface) { mOutputIgbp = surface; if (!surface) { mOutputBqId = 0; } else if (surface->getUniqueId(&mOutputBqId) != OK) { ALOGE("setOutputSurface -- cannot obtain bufferqueue id."); } } mOutputGeneration = generation; } return status; } status_t Codec2Client::Component::queueToOutputSurface( const C2ConstGraphicBlock& block, const QueueBufferInput& input, QueueBufferOutput* output) { uint64_t bqId; int32_t bqSlot; if (!getBufferQueueAssignment(block, &bqId, &bqSlot) || bqId == 0) { // Block not from bufferqueue -- it must be attached before queuing. mOutputBufferQueueMutex.lock(); sp outputIgbp = mOutputIgbp; uint32_t outputGeneration = mOutputGeneration; mOutputBufferQueueMutex.unlock(); status_t status = !attachToBufferQueue(block, outputIgbp, outputGeneration, &bqSlot); if (status != OK) { ALOGW("queueToOutputSurface -- attaching failed."); return INVALID_OPERATION; } status = outputIgbp->queueBuffer(static_cast(bqSlot), input, output); if (status != OK) { ALOGE("queueToOutputSurface -- queueBuffer() failed " "on non-bufferqueue-based block. " "Error code = %d.", static_cast(status)); return status; } return OK; } mOutputBufferQueueMutex.lock(); sp outputIgbp = mOutputIgbp; uint64_t outputBqId = mOutputBqId; mOutputBufferQueueMutex.unlock(); if (!outputIgbp) { ALOGE("queueToOutputSurface -- output surface is null."); return NO_INIT; } if (bqId != outputBqId) { ALOGE("queueToOutputSurface -- bufferqueue ids mismatch."); return DEAD_OBJECT; } status_t status = outputIgbp->queueBuffer(static_cast(bqSlot), input, output); if (status != OK) { ALOGE("queueToOutputSurface -- queueBuffer() failed " "on bufferqueue-based block. " "Error code = %d.", static_cast(status)); return status; } if (!yieldBufferQueueBlock(block)) { ALOGE("queueToOutputSurface -- cannot yield bufferqueue-based block " "to the bufferqueue."); return UNKNOWN_ERROR; } return OK; } c2_status_t Codec2Client::Component::connectToOmxInputSurface( const sp& producer, const sp& source) { Return transStatus = base()->connectToOmxInputSurface( producer, source); if (!transStatus.isOk()) { ALOGE("connectToOmxInputSurface -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("connectToOmxInputSurface -- call failed. " "Error code = %d", static_cast(status)); } return status; } c2_status_t Codec2Client::Component::disconnectFromInputSurface() { Return transStatus = base()->disconnectFromInputSurface(); if (!transStatus.isOk()) { ALOGE("disconnectToInputSurface -- transaction failed."); return C2_TRANSACTION_FAILED; } c2_status_t status = static_cast(static_cast(transStatus)); if (status != C2_OK) { ALOGE("disconnectFromInputSurface -- call failed. " "Error code = %d", static_cast(status)); } return status; } c2_status_t Codec2Client::Component::setDeathListener( const std::shared_ptr& component, const std::shared_ptr& listener) { struct HidlDeathRecipient : public hardware::hidl_death_recipient { std::weak_ptr component; std::weak_ptr base; virtual void serviceDied( uint64_t /* cookie */, const wp<::android::hidl::base::V1_0::IBase>& /* who */ ) override { if (std::shared_ptr listener = base.lock()) { listener->onDeath(component); } else { ALOGW("onDeath -- listener died."); } } }; sp deathRecipient = new HidlDeathRecipient(); deathRecipient->base = listener; deathRecipient->component = component; component->mDeathRecipient = deathRecipient; Return transResult = component->base()->linkToDeath( component->mDeathRecipient, 0); if (!transResult.isOk()) { ALOGE("setDeathListener -- failed transaction: linkToDeath."); return C2_TRANSACTION_FAILED; } if (!static_cast(transResult)) { ALOGE("setDeathListener -- linkToDeath call failed."); return C2_CORRUPTED; } return C2_OK; } // Codec2Client::InputSurface Codec2Client::InputSurface::Base* Codec2Client::InputSurface::base() const { return static_cast(mBase.get()); } Codec2Client::InputSurface::InputSurface(const sp& base) : mBase(base), mGraphicBufferProducer(new ::android::hardware::graphics::bufferqueue::V1_0::utils:: H2BGraphicBufferProducer(base)) { } c2_status_t Codec2Client::InputSurface::connectToComponent( const std::shared_ptr& component, std::shared_ptr* connection) { c2_status_t status; Return transStatus = base()->connectToComponent( component->base(), [&status, connection]( Status s, const sp& c) { status = static_cast(s); if (status != C2_OK) { ALOGE("connectToComponent -- call failed. " "Error code = %d", static_cast(status)); return; } *connection = std::make_shared(c); }); if (!transStatus.isOk()) { ALOGE("connect -- transaction failed."); return C2_TRANSACTION_FAILED; } return status; } std::shared_ptr Codec2Client::InputSurface::getConfigurable() const { Return> transResult = base()->getConfigurable(); if (!transResult.isOk()) { ALOGW("getConfigurable -- transaction failed."); return nullptr; } if (!static_cast>(transResult)) { ALOGW("getConfigurable -- null pointer."); return nullptr; } return std::make_shared(transResult); } const sp& Codec2Client::InputSurface::getGraphicBufferProducer() const { return mGraphicBufferProducer; } // Codec2Client::InputSurfaceConnection Codec2Client::InputSurfaceConnection::Base* Codec2Client::InputSurfaceConnection::base() const { return static_cast(mBase.get()); } Codec2Client::InputSurfaceConnection::InputSurfaceConnection( const sp& base) : mBase(base) { } c2_status_t Codec2Client::InputSurfaceConnection::disconnect() { Return transResult = base()->disconnect(); return static_cast(static_cast(transResult)); } } // namespace android