Merge "AudioFlinger: clean up ctor initialization" into main
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
new file mode 100644
index 0000000..7994d32
--- /dev/null
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright 2021 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 "Codec2-Component@1.2"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.2/Component.h>
+#include <codec2/hidl/1.2/ComponentStore.h>
+#include <codec2/hidl/1.2/InputBufferManager.h>
+
+#ifndef __ANDROID_APEX__
+#include <FilterWrapper.h>
+#endif
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_2 {
+namespace utils {
+
+using namespace ::android;
+
+// ComponentListener wrapper
+struct Component::Listener : public C2Component::Listener {
+
+ Listener(const sp<Component>& component) :
+ mComponent(component),
+ mListener(component->mListener) {
+ }
+
+ virtual void onError_nb(
+ std::weak_ptr<C2Component> /* c2component */,
+ uint32_t errorCode) override {
+ sp<IComponentListener> listener = mListener.promote();
+ if (listener) {
+ Return<void> transStatus = listener->onError(Status::OK, errorCode);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Component::Listener::onError_nb -- "
+ << "transaction failed.";
+ }
+ }
+ }
+
+ virtual void onTripped_nb(
+ std::weak_ptr<C2Component> /* c2component */,
+ std::vector<std::shared_ptr<C2SettingResult>> c2settingResult
+ ) override {
+ sp<IComponentListener> listener = mListener.promote();
+ if (listener) {
+ hidl_vec<SettingResult> settingResults(c2settingResult.size());
+ size_t ix = 0;
+ for (const std::shared_ptr<C2SettingResult> &c2result :
+ c2settingResult) {
+ if (c2result) {
+ if (!objcpy(&settingResults[ix++], *c2result)) {
+ break;
+ }
+ }
+ }
+ settingResults.resize(ix);
+ Return<void> transStatus = listener->onTripped(settingResults);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Component::Listener::onTripped_nb -- "
+ << "transaction failed.";
+ }
+ }
+ }
+
+ virtual void onWorkDone_nb(
+ std::weak_ptr<C2Component> /* c2component */,
+ std::list<std::unique_ptr<C2Work>> c2workItems) override {
+ for (const std::unique_ptr<C2Work>& work : c2workItems) {
+ if (work) {
+ if (work->worklets.empty()
+ || !work->worklets.back()
+ || (work->worklets.back()->output.flags &
+ C2FrameData::FLAG_INCOMPLETE) == 0) {
+ InputBufferManager::
+ unregisterFrameData(mListener, work->input);
+ }
+ }
+ }
+
+ sp<IComponentListener> listener = mListener.promote();
+ if (listener) {
+ WorkBundle workBundle;
+
+ sp<Component> strongComponent = mComponent.promote();
+ beginTransferBufferQueueBlocks(c2workItems, true);
+ if (!objcpy(&workBundle, c2workItems, strongComponent ?
+ &strongComponent->mBufferPoolSender : nullptr)) {
+ LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+ << "received corrupted work items.";
+ endTransferBufferQueueBlocks(c2workItems, false, true);
+ return;
+ }
+ Return<void> transStatus = listener->onWorkDone(workBundle);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Component::Listener::onWorkDone_nb -- "
+ << "transaction failed.";
+ endTransferBufferQueueBlocks(c2workItems, false, true);
+ return;
+ }
+ endTransferBufferQueueBlocks(c2workItems, true, true);
+ }
+ }
+
+protected:
+ wp<Component> mComponent;
+ wp<IComponentListener> mListener;
+};
+
+// Component::Sink
+struct Component::Sink : public IInputSink {
+ std::shared_ptr<Component> mComponent;
+ sp<IConfigurable> mConfigurable;
+
+ virtual Return<Status> queue(const WorkBundle& workBundle) override {
+ return mComponent->queue(workBundle);
+ }
+
+ virtual Return<sp<IConfigurable>> getConfigurable() override {
+ return mConfigurable;
+ }
+
+ Sink(const std::shared_ptr<Component>& component);
+ virtual ~Sink() override;
+
+ // Process-wide map: Component::Sink -> C2Component.
+ static std::mutex sSink2ComponentMutex;
+ static std::map<IInputSink*, std::weak_ptr<C2Component>> sSink2Component;
+
+ static std::shared_ptr<C2Component> findLocalComponent(
+ const sp<IInputSink>& sink);
+};
+
+std::mutex
+ Component::Sink::sSink2ComponentMutex{};
+std::map<IInputSink*, std::weak_ptr<C2Component>>
+ Component::Sink::sSink2Component{};
+
+Component::Sink::Sink(const std::shared_ptr<Component>& component)
+ : mComponent{component},
+ mConfigurable{[&component]() -> sp<IConfigurable> {
+ Return<sp<IComponentInterface>> ret1 = component->getInterface();
+ if (!ret1.isOk()) {
+ LOG(ERROR) << "Sink::Sink -- component's transaction failed.";
+ return nullptr;
+ }
+ Return<sp<IConfigurable>> ret2 =
+ static_cast<sp<IComponentInterface>>(ret1)->
+ getConfigurable();
+ if (!ret2.isOk()) {
+ LOG(ERROR) << "Sink::Sink -- interface's transaction failed.";
+ return nullptr;
+ }
+ return static_cast<sp<IConfigurable>>(ret2);
+ }()} {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ sSink2Component.emplace(this, component->mComponent);
+}
+
+Component::Sink::~Sink() {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ sSink2Component.erase(this);
+}
+
+std::shared_ptr<C2Component> Component::Sink::findLocalComponent(
+ const sp<IInputSink>& sink) {
+ std::lock_guard<std::mutex> lock(sSink2ComponentMutex);
+ auto i = sSink2Component.find(sink.get());
+ if (i == sSink2Component.end()) {
+ return nullptr;
+ }
+ return i->second.lock();
+}
+
+// Component
+Component::Component(
+ const std::shared_ptr<C2Component>& component,
+ const sp<IComponentListener>& listener,
+ const sp<ComponentStore>& store,
+ const sp<::android::hardware::media::bufferpool::V2_0::
+ IClientManager>& clientPoolManager)
+ : mComponent{component},
+ mInterface{new ComponentInterface(component->intf(),
+ store->getParameterCache())},
+ mListener{listener},
+ mStore{store},
+ mBufferPoolSender{clientPoolManager} {
+ // Retrieve supported parameters from store
+ // TODO: We could cache this per component/interface type
+ mInit = mInterface->status();
+}
+
+c2_status_t Component::status() const {
+ return mInit;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponent
+Return<Status> Component::queue(const WorkBundle& workBundle) {
+ std::list<std::unique_ptr<C2Work>> c2works;
+
+ if (!objcpy(&c2works, workBundle)) {
+ return Status::CORRUPTED;
+ }
+
+ // Register input buffers.
+ for (const std::unique_ptr<C2Work>& work : c2works) {
+ if (work) {
+ InputBufferManager::
+ registerFrameData(mListener, work->input);
+ }
+ }
+
+ return static_cast<Status>(mComponent->queue_nb(&c2works));
+}
+
+Return<void> Component::flush(flush_cb _hidl_cb) {
+ std::list<std::unique_ptr<C2Work>> c2flushedWorks;
+ c2_status_t c2res = mComponent->flush_sm(
+ C2Component::FLUSH_COMPONENT,
+ &c2flushedWorks);
+
+ // Unregister input buffers.
+ for (const std::unique_ptr<C2Work>& work : c2flushedWorks) {
+ if (work) {
+ if (work->worklets.empty()
+ || !work->worklets.back()
+ || (work->worklets.back()->output.flags &
+ C2FrameData::FLAG_INCOMPLETE) == 0) {
+ InputBufferManager::
+ unregisterFrameData(mListener, work->input);
+ }
+ }
+ }
+
+ WorkBundle flushedWorkBundle;
+ Status res = static_cast<Status>(c2res);
+ beginTransferBufferQueueBlocks(c2flushedWorks, true);
+ if (c2res == C2_OK) {
+ if (!objcpy(&flushedWorkBundle, c2flushedWorks, &mBufferPoolSender)) {
+ res = Status::CORRUPTED;
+ }
+ }
+ _hidl_cb(res, flushedWorkBundle);
+ endTransferBufferQueueBlocks(c2flushedWorks, true, true);
+ return Void();
+}
+
+Return<Status> Component::drain(bool withEos) {
+ return static_cast<Status>(mComponent->drain_nb(withEos ?
+ C2Component::DRAIN_COMPONENT_WITH_EOS :
+ C2Component::DRAIN_COMPONENT_NO_EOS));
+}
+
+Return<Status> Component::setOutputSurface(
+ uint64_t blockPoolId,
+ const sp<HGraphicBufferProducer2>& surface) {
+ std::shared_ptr<C2BlockPool> pool;
+ GetCodec2BlockPool(blockPoolId, mComponent, &pool);
+ if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
+ C2BufferQueueBlockPool::OnRenderCallback cb =
+ [this](uint64_t producer, int32_t slot, int64_t nsecs) {
+ // TODO: batch this
+ hidl_vec<IComponentListener::RenderedFrame> rendered;
+ rendered.resize(1);
+ rendered[0] = { producer, slot, nsecs };
+ (void)mListener->onFramesRendered(rendered).isOk();
+ };
+ if (bqPool) {
+ bqPool->setRenderCallback(cb);
+ bqPool->configureProducer(surface);
+ }
+ }
+ return Status::OK;
+}
+
+Return<void> Component::connectToInputSurface(
+ const sp<IInputSurface>& inputSurface,
+ connectToInputSurface_cb _hidl_cb) {
+ Status status;
+ sp<IInputSurfaceConnection> connection;
+ auto transStatus = inputSurface->connect(
+ asInputSink(),
+ [&status, &connection](
+ Status s, const sp<IInputSurfaceConnection>& c) {
+ status = s;
+ connection = c;
+ }
+ );
+ _hidl_cb(status, connection);
+ return Void();
+}
+
+Return<void> Component::connectToOmxInputSurface(
+ const sp<HGraphicBufferProducer1>& producer,
+ const sp<::android::hardware::media::omx::V1_0::
+ IGraphicBufferSource>& source,
+ connectToOmxInputSurface_cb _hidl_cb) {
+ (void)producer;
+ (void)source;
+ (void)_hidl_cb;
+ return Void();
+}
+
+Return<Status> Component::disconnectFromInputSurface() {
+ // TODO implement
+ return Status::OK;
+}
+
+namespace /* unnamed */ {
+
+struct BlockPoolIntf : public ConfigurableC2Intf {
+ BlockPoolIntf(const std::shared_ptr<C2BlockPool>& pool)
+ : ConfigurableC2Intf{
+ "C2BlockPool:" +
+ (pool ? std::to_string(pool->getLocalId()) : "null"),
+ 0},
+ mPool{pool} {
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*>& params,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ (void)params;
+ (void)mayBlock;
+ (void)failures;
+ return C2_OK;
+ }
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index>& indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params
+ ) const override {
+ (void)indices;
+ (void)mayBlock;
+ (void)params;
+ return C2_OK;
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override {
+ (void)params;
+ return C2_OK;
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override {
+ (void)fields;
+ (void)mayBlock;
+ return C2_OK;
+ }
+
+protected:
+ std::shared_ptr<C2BlockPool> mPool;
+};
+
+} // unnamed namespace
+
+Return<void> Component::createBlockPool(
+ uint32_t allocatorId,
+ createBlockPool_cb _hidl_cb) {
+ std::shared_ptr<C2BlockPool> blockPool;
+#ifdef __ANDROID_APEX__
+ c2_status_t status = CreateCodec2BlockPool(
+ static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
+ mComponent,
+ &blockPool);
+#else
+ c2_status_t status = ComponentStore::GetFilterWrapper()->createBlockPool(
+ static_cast<C2PlatformAllocatorStore::id_t>(allocatorId),
+ mComponent,
+ &blockPool);
+#endif
+ if (status != C2_OK) {
+ blockPool = nullptr;
+ }
+ if (blockPool) {
+ mBlockPoolsMutex.lock();
+ mBlockPools.emplace(blockPool->getLocalId(), blockPool);
+ mBlockPoolsMutex.unlock();
+ } else if (status == C2_OK) {
+ status = C2_CORRUPTED;
+ }
+
+ _hidl_cb(static_cast<Status>(status),
+ blockPool ? blockPool->getLocalId() : 0,
+ new CachedConfigurable(
+ std::make_unique<BlockPoolIntf>(blockPool)));
+ return Void();
+}
+
+Return<Status> Component::destroyBlockPool(uint64_t blockPoolId) {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ return mBlockPools.erase(blockPoolId) == 1 ?
+ Status::OK : Status::CORRUPTED;
+}
+
+Return<Status> Component::start() {
+ return static_cast<Status>(mComponent->start());
+}
+
+Return<Status> Component::stop() {
+ InputBufferManager::unregisterFrameData(mListener);
+ return static_cast<Status>(mComponent->stop());
+}
+
+Return<Status> Component::reset() {
+ Status status = static_cast<Status>(mComponent->reset());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ mBlockPools.clear();
+ }
+ InputBufferManager::unregisterFrameData(mListener);
+ return status;
+}
+
+Return<Status> Component::release() {
+ Status status = static_cast<Status>(mComponent->release());
+ {
+ std::lock_guard<std::mutex> lock(mBlockPoolsMutex);
+ mBlockPools.clear();
+ }
+ InputBufferManager::unregisterFrameData(mListener);
+ return status;
+}
+
+Return<sp<IComponentInterface>> Component::getInterface() {
+ return sp<IComponentInterface>(mInterface);
+}
+
+Return<sp<IInputSink>> Component::asInputSink() {
+ std::lock_guard<std::mutex> lock(mSinkMutex);
+ if (!mSink) {
+ mSink = new Sink(shared_from_this());
+ }
+ return {mSink};
+}
+
+Return<void> Component::configureVideoTunnel(
+ uint32_t avSyncHwId, configureVideoTunnel_cb _hidl_cb) {
+ (void)avSyncHwId;
+ _hidl_cb(Status::OMITTED, hidl_handle{});
+ return Void();
+}
+
+Return<Status> Component::setOutputSurfaceWithSyncObj(
+ uint64_t blockPoolId, const sp<HGraphicBufferProducer2>& surface,
+ const SurfaceSyncObj& syncObject) {
+ std::shared_ptr<C2BlockPool> pool;
+ GetCodec2BlockPool(blockPoolId, mComponent, &pool);
+ if (pool && pool->getAllocatorId() == C2PlatformAllocatorStore::BUFFERQUEUE) {
+ std::shared_ptr<C2BufferQueueBlockPool> bqPool =
+ std::static_pointer_cast<C2BufferQueueBlockPool>(pool);
+ C2BufferQueueBlockPool::OnRenderCallback cb =
+ [this](uint64_t producer, int32_t slot, int64_t nsecs) {
+ // TODO: batch this
+ hidl_vec<IComponentListener::RenderedFrame> rendered;
+ rendered.resize(1);
+ rendered[0] = { producer, slot, nsecs };
+ (void)mListener->onFramesRendered(rendered).isOk();
+ };
+ if (bqPool) {
+ const native_handle_t *h = syncObject.syncMemory;
+ native_handle_t *syncMemory = h ? native_handle_clone(h) : nullptr;
+ uint64_t bqId = syncObject.bqId;
+ uint32_t generationId = syncObject.generationId;
+ uint64_t consumerUsage = syncObject.consumerUsage;
+
+ bqPool->setRenderCallback(cb);
+ bqPool->configureProducer(surface, syncMemory, bqId,
+ generationId, consumerUsage);
+ }
+ }
+ return Status::OK;
+}
+
+std::shared_ptr<C2Component> Component::findLocalComponent(
+ const sp<IInputSink>& sink) {
+ return Component::Sink::findLocalComponent(sink);
+}
+
+void Component::initListener(const sp<Component>& self) {
+ std::shared_ptr<C2Component::Listener> c2listener =
+ std::make_shared<Listener>(self);
+ c2_status_t res = mComponent->setListener_vb(c2listener, C2_DONT_BLOCK);
+ if (res != C2_OK) {
+ mInit = res;
+ }
+
+ struct ListenerDeathRecipient : public HwDeathRecipient {
+ ListenerDeathRecipient(const wp<Component>& comp)
+ : component{comp} {
+ }
+
+ virtual void serviceDied(
+ uint64_t /* cookie */,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */
+ ) override {
+ auto strongComponent = component.promote();
+ if (strongComponent) {
+ LOG(INFO) << "Client died ! release the component !!";
+ strongComponent->release();
+ } else {
+ LOG(ERROR) << "Client died ! no component to release !!";
+ }
+ }
+
+ wp<Component> component;
+ };
+
+ mDeathRecipient = new ListenerDeathRecipient(self);
+ Return<bool> transStatus = mListener->linkToDeath(
+ mDeathRecipient, 0);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Listener linkToDeath() transaction failed.";
+ }
+ if (!static_cast<bool>(transStatus)) {
+ LOG(DEBUG) << "Listener linkToDeath() call failed.";
+ }
+}
+
+Component::~Component() {
+ InputBufferManager::unregisterFrameData(mListener);
+ mStore->reportComponentDeath(this);
+}
+
+} // namespace utils
+} // namespace V1_2
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hal/aidl/ComponentInterface.cpp b/media/codec2/hal/aidl/ComponentInterface.cpp
new file mode 100644
index 0000000..12078e0
--- /dev/null
+++ b/media/codec2/hal/aidl/ComponentInterface.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright 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 "Codec2-ComponentInterface"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+
+#include <hidl/HidlBinderSupport.h>
+#include <utils/Timers.h>
+
+#include <C2BqBufferPriv.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+
+#include <chrono>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+namespace /* unnamed */ {
+
+// Implementation of ConfigurableC2Intf based on C2ComponentInterface
+struct CompIntf : public ConfigurableC2Intf {
+ CompIntf(const std::shared_ptr<C2ComponentInterface>& intf) :
+ ConfigurableC2Intf{intf->getName(), intf->getId()},
+ mIntf{intf} {
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*>& params,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ return mIntf->config_vb(params, mayBlock, failures);
+ }
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index>& indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params
+ ) const override {
+ return mIntf->query_vb({}, indices, mayBlock, params);
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override {
+ return mIntf->querySupportedParams_nb(params);
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override {
+ return mIntf->querySupportedValues_vb(fields, mayBlock);
+ }
+
+protected:
+ std::shared_ptr<C2ComponentInterface> mIntf;
+};
+
+} // unnamed namespace
+
+// ComponentInterface
+ComponentInterface::ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& intf,
+ const std::shared_ptr<ParameterCache>& cache)
+ : mInterface{intf},
+ mConfigurable{new CachedConfigurable(std::make_unique<CompIntf>(intf))} {
+ mInit = mConfigurable->init(cache);
+}
+
+c2_status_t ComponentInterface::status() const {
+ return mInit;
+}
+
+Return<sp<IConfigurable>> ComponentInterface::getConfigurable() {
+ return mConfigurable;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
new file mode 100644
index 0000000..9fac5d5
--- /dev/null
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2021 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 "Codec2-ComponentStore@1.2"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.2/ComponentStore.h>
+#include <codec2/hidl/1.2/InputSurface.h>
+#include <codec2/hidl/1.2/types.h>
+
+#include <android-base/file.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+#include <utils/Errors.h>
+
+#include <C2PlatformSupport.h>
+#include <util/C2InterfaceHelper.h>
+
+#include <chrono>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+#ifndef __ANDROID_APEX__
+#include <codec2/hidl/plugin/FilterPlugin.h>
+#include <dlfcn.h>
+#include <C2Config.h>
+#include <DefaultFilterPlugin.h>
+#include <FilterWrapper.h>
+#endif
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_2 {
+namespace utils {
+
+using namespace ::android;
+using ::android::GraphicBufferSource;
+using namespace ::android::hardware::media::bufferpool::V2_0::implementation;
+
+namespace /* unnamed */ {
+
+struct StoreIntf : public ConfigurableC2Intf {
+ StoreIntf(const std::shared_ptr<C2ComponentStore>& store)
+ : ConfigurableC2Intf{store ? store->getName() : "", 0},
+ mStore{store} {
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures
+ ) override {
+ // Assume all params are blocking
+ // TODO: Filter for supported params
+ if (mayBlock == C2_DONT_BLOCK && params.size() != 0) {
+ return C2_BLOCKING;
+ }
+ return mStore->config_sm(params, failures);
+ }
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>> *const params) const override {
+ // Assume all params are blocking
+ // TODO: Filter for supported params
+ if (mayBlock == C2_DONT_BLOCK && indices.size() != 0) {
+ return C2_BLOCKING;
+ }
+ return mStore->query_sm({}, indices, params);
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+ ) const override {
+ return mStore->querySupportedParams_nb(params);
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const override {
+ // Assume all params are blocking
+ // TODO: Filter for supported params
+ if (mayBlock == C2_DONT_BLOCK && fields.size() != 0) {
+ return C2_BLOCKING;
+ }
+ return mStore->querySupportedValues_sm(fields);
+ }
+
+protected:
+ std::shared_ptr<C2ComponentStore> mStore;
+};
+
+} // unnamed namespace
+
+struct ComponentStore::StoreParameterCache : public ParameterCache {
+ std::mutex mStoreMutex;
+ ComponentStore* mStore;
+
+ StoreParameterCache(ComponentStore* store): mStore{store} {
+ }
+
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params
+ ) override {
+ std::scoped_lock _lock(mStoreMutex);
+ return mStore ? mStore->validateSupportedParams(params) : C2_NO_INIT;
+ }
+
+ void onStoreDestroyed() {
+ std::scoped_lock _lock(mStoreMutex);
+ mStore = nullptr;
+ }
+};
+
+ComponentStore::ComponentStore(const std::shared_ptr<C2ComponentStore>& store)
+ : mConfigurable{new CachedConfigurable(std::make_unique<StoreIntf>(store))},
+ mParameterCache{std::make_shared<StoreParameterCache>(this)},
+ mStore{store} {
+
+ std::shared_ptr<C2ComponentStore> platformStore = android::GetCodec2PlatformComponentStore();
+ SetPreferredCodec2ComponentStore(store);
+
+ // Retrieve struct descriptors
+ mParamReflector = mStore->getParamReflector();
+
+ // Retrieve supported parameters from store
+ using namespace std::placeholders;
+ mInit = mConfigurable->init(mParameterCache);
+}
+
+ComponentStore::~ComponentStore() {
+ mParameterCache->onStoreDestroyed();
+}
+
+c2_status_t ComponentStore::status() const {
+ return mInit;
+}
+
+c2_status_t ComponentStore::validateSupportedParams(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params) {
+ c2_status_t res = C2_OK;
+
+ for (const std::shared_ptr<C2ParamDescriptor> &desc : params) {
+ if (!desc) {
+ // All descriptors should be valid
+ res = res ? res : C2_BAD_VALUE;
+ continue;
+ }
+ C2Param::CoreIndex coreIndex = desc->index().coreIndex();
+ std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+ auto it = mStructDescriptors.find(coreIndex);
+ if (it == mStructDescriptors.end()) {
+ std::shared_ptr<C2StructDescriptor> structDesc =
+ mParamReflector->describe(coreIndex);
+ if (!structDesc) {
+ // All supported params must be described
+ res = C2_BAD_INDEX;
+ }
+ mStructDescriptors.insert({ coreIndex, structDesc });
+ }
+ }
+ return res;
+}
+
+std::shared_ptr<ParameterCache> ComponentStore::getParameterCache() const {
+ return mParameterCache;
+}
+
+#ifndef __ANDROID_APEX__
+// static
+std::shared_ptr<FilterWrapper> ComponentStore::GetFilterWrapper() {
+ constexpr const char kPluginPath[] = "libc2filterplugin.so";
+ static std::shared_ptr<FilterWrapper> wrapper = FilterWrapper::Create(
+ std::make_unique<DefaultFilterPlugin>(kPluginPath));
+ return wrapper;
+}
+#endif
+
+// Methods from ::android::hardware::media::c2::V1_0::IComponentStore
+Return<void> ComponentStore::createComponent(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_cb _hidl_cb) {
+
+ sp<Component> component;
+ std::shared_ptr<C2Component> c2component;
+ Status status = static_cast<Status>(
+ mStore->createComponent(name, &c2component));
+
+ if (status == Status::OK) {
+#ifndef __ANDROID_APEX__
+ c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
+#endif
+ onInterfaceLoaded(c2component->intf());
+ component = new Component(c2component, listener, this, pool);
+ if (!component) {
+ status = Status::CORRUPTED;
+ } else {
+ reportComponentBirth(component.get());
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ } else {
+ component->initListener(component);
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ }
+ }
+ }
+ }
+ _hidl_cb(status, component);
+ return Void();
+}
+
+Return<void> ComponentStore::createInterface(
+ const hidl_string& name,
+ createInterface_cb _hidl_cb) {
+ std::shared_ptr<C2ComponentInterface> c2interface;
+ c2_status_t res = mStore->createInterface(name, &c2interface);
+ sp<IComponentInterface> interface;
+ if (res == C2_OK) {
+#ifndef __ANDROID_APEX__
+ c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
+#endif
+ onInterfaceLoaded(c2interface);
+ interface = new ComponentInterface(c2interface, mParameterCache);
+ }
+ _hidl_cb(static_cast<Status>(res), interface);
+ return Void();
+}
+
+Return<void> ComponentStore::listComponents(listComponents_cb _hidl_cb) {
+ std::vector<std::shared_ptr<const C2Component::Traits>> c2traits =
+ mStore->listComponents();
+ hidl_vec<IComponentStore::ComponentTraits> traits(c2traits.size());
+ size_t ix = 0;
+ for (const std::shared_ptr<const C2Component::Traits> &c2trait : c2traits) {
+ if (c2trait) {
+ if (objcpy(&traits[ix], *c2trait)) {
+ ++ix;
+ } else {
+ break;
+ }
+ }
+ }
+ traits.resize(ix);
+ _hidl_cb(Status::OK, traits);
+ return Void();
+}
+
+Return<void> ComponentStore::createInputSurface(createInputSurface_cb _hidl_cb) {
+ sp<GraphicBufferSource> source = new GraphicBufferSource();
+ if (source->initCheck() != OK) {
+ _hidl_cb(Status::CORRUPTED, nullptr);
+ return Void();
+ }
+ using namespace std::placeholders;
+ sp<InputSurface> inputSurface = new InputSurface(
+ mParameterCache,
+ std::make_shared<C2ReflectorHelper>(),
+ source->getHGraphicBufferProducer(),
+ source);
+ _hidl_cb(inputSurface ? Status::OK : Status::NO_MEMORY,
+ inputSurface);
+ return Void();
+}
+
+void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
+ // invalidate unsupported struct descriptors if a new interface is loaded as it may have
+ // exposed new descriptors
+ std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+ if (!mLoadedInterfaces.count(intf->getName())) {
+ mUnsupportedStructDescriptors.clear();
+ mLoadedInterfaces.emplace(intf->getName());
+ }
+}
+
+Return<void> ComponentStore::getStructDescriptors(
+ const hidl_vec<uint32_t>& indices,
+ getStructDescriptors_cb _hidl_cb) {
+ hidl_vec<StructDescriptor> descriptors(indices.size());
+ size_t dstIx = 0;
+ Status res = Status::OK;
+ for (size_t srcIx = 0; srcIx < indices.size(); ++srcIx) {
+ std::lock_guard<std::mutex> lock(mStructDescriptorsMutex);
+ const C2Param::CoreIndex coreIndex = C2Param::CoreIndex(indices[srcIx]).coreIndex();
+ const auto item = mStructDescriptors.find(coreIndex);
+ if (item == mStructDescriptors.end()) {
+ // not in the cache, and not known to be unsupported, query local reflector
+ if (!mUnsupportedStructDescriptors.count(coreIndex)) {
+ std::shared_ptr<C2StructDescriptor> structDesc =
+ mParamReflector->describe(coreIndex);
+ if (!structDesc) {
+ mUnsupportedStructDescriptors.emplace(coreIndex);
+ } else {
+ mStructDescriptors.insert({ coreIndex, structDesc });
+ if (objcpy(&descriptors[dstIx], *structDesc)) {
+ ++dstIx;
+ continue;
+ }
+ res = Status::CORRUPTED;
+ break;
+ }
+ }
+ res = Status::NOT_FOUND;
+ } else if (item->second) {
+ if (objcpy(&descriptors[dstIx], *item->second)) {
+ ++dstIx;
+ continue;
+ }
+ res = Status::CORRUPTED;
+ break;
+ } else {
+ res = Status::NO_MEMORY;
+ break;
+ }
+ }
+ descriptors.resize(dstIx);
+ _hidl_cb(res, descriptors);
+ return Void();
+}
+
+Return<sp<IClientManager>> ComponentStore::getPoolClientManager() {
+ return ClientManager::getInstance();
+}
+
+Return<Status> ComponentStore::copyBuffer(const Buffer& src, const Buffer& dst) {
+ // TODO implement
+ (void)src;
+ (void)dst;
+ return Status::OMITTED;
+}
+
+Return<sp<IConfigurable>> ComponentStore::getConfigurable() {
+ return mConfigurable;
+}
+
+// Methods from ::android::hardware::media::c2::V1_1::IComponentStore
+Return<void> ComponentStore::createComponent_1_1(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_1_1_cb _hidl_cb) {
+
+ sp<Component> component;
+ std::shared_ptr<C2Component> c2component;
+ Status status = static_cast<Status>(
+ mStore->createComponent(name, &c2component));
+
+ if (status == Status::OK) {
+#ifndef __ANDROID_APEX__
+ c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
+#endif
+ onInterfaceLoaded(c2component->intf());
+ component = new Component(c2component, listener, this, pool);
+ if (!component) {
+ status = Status::CORRUPTED;
+ } else {
+ reportComponentBirth(component.get());
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ } else {
+ component->initListener(component);
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ }
+ }
+ }
+ }
+ _hidl_cb(status, component);
+ return Void();
+}
+
+// Methods from ::android::hardware::media::c2::V1_2::IComponentStore
+Return<void> ComponentStore::createComponent_1_2(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_1_2_cb _hidl_cb) {
+
+ sp<Component> component;
+ std::shared_ptr<C2Component> c2component;
+ Status status = static_cast<Status>(
+ mStore->createComponent(name, &c2component));
+
+ if (status == Status::OK) {
+#ifndef __ANDROID_APEX__
+ c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
+#endif
+ onInterfaceLoaded(c2component->intf());
+ component = new Component(c2component, listener, this, pool);
+ if (!component) {
+ status = Status::CORRUPTED;
+ } else {
+ reportComponentBirth(component.get());
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ } else {
+ component->initListener(component);
+ if (component->status() != C2_OK) {
+ status = static_cast<Status>(component->status());
+ }
+ }
+ }
+ }
+ _hidl_cb(status, component);
+ return Void();
+}
+
+// Called from createComponent() after a successful creation of `component`.
+void ComponentStore::reportComponentBirth(Component* component) {
+ ComponentStatus componentStatus;
+ componentStatus.c2Component = component->mComponent;
+ componentStatus.birthTime = std::chrono::system_clock::now();
+
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ mComponentRoster.emplace(component, componentStatus);
+}
+
+// Called from within the destructor of `component`. No virtual function calls
+// are made on `component` here.
+void ComponentStore::reportComponentDeath(Component* component) {
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ mComponentRoster.erase(component);
+}
+
+// Dumps component traits.
+std::ostream& ComponentStore::dump(
+ std::ostream& out,
+ const std::shared_ptr<const C2Component::Traits>& comp) {
+
+ constexpr const char indent[] = " ";
+
+ out << indent << "name: " << comp->name << std::endl;
+ out << indent << "domain: " << comp->domain << std::endl;
+ out << indent << "kind: " << comp->kind << std::endl;
+ out << indent << "rank: " << comp->rank << std::endl;
+ out << indent << "mediaType: " << comp->mediaType << std::endl;
+ out << indent << "aliases:";
+ for (const auto& alias : comp->aliases) {
+ out << ' ' << alias;
+ }
+ out << std::endl;
+
+ return out;
+}
+
+// Dumps component status.
+std::ostream& ComponentStore::dump(
+ std::ostream& out,
+ ComponentStatus& compStatus) {
+
+ constexpr const char indent[] = " ";
+
+ // Print birth time.
+ std::chrono::milliseconds ms =
+ std::chrono::duration_cast<std::chrono::milliseconds>(
+ compStatus.birthTime.time_since_epoch());
+ std::time_t birthTime = std::chrono::system_clock::to_time_t(
+ compStatus.birthTime);
+ std::tm tm = *std::localtime(&birthTime);
+ out << indent << "Creation time: "
+ << std::put_time(&tm, "%Y-%m-%d %H:%M:%S")
+ << '.' << std::setfill('0') << std::setw(3) << ms.count() % 1000
+ << std::endl;
+
+ // Print name and id.
+ std::shared_ptr<C2ComponentInterface> intf = compStatus.c2Component->intf();
+ if (!intf) {
+ out << indent << "Unknown component -- null interface" << std::endl;
+ return out;
+ }
+ out << indent << "Name: " << intf->getName() << std::endl;
+ out << indent << "Id: " << intf->getId() << std::endl;
+
+ return out;
+}
+
+// Dumps information when lshal is called.
+Return<void> ComponentStore::debug(
+ const hidl_handle& handle,
+ const hidl_vec<hidl_string>& /* args */) {
+ LOG(INFO) << "debug -- dumping...";
+ const native_handle_t *h = handle.getNativeHandle();
+ if (!h || h->numFds != 1) {
+ LOG(ERROR) << "debug -- dumping failed -- "
+ "invalid file descriptor to dump to";
+ return Void();
+ }
+ std::ostringstream out;
+
+ { // Populate "out".
+
+ constexpr const char indent[] = " ";
+
+ // Show name.
+ out << "Beginning of dump -- C2ComponentStore: "
+ << mStore->getName() << std::endl << std::endl;
+
+ // Retrieve the list of supported components.
+ std::vector<std::shared_ptr<const C2Component::Traits>> traitsList =
+ mStore->listComponents();
+
+ // Dump the traits of supported components.
+ out << indent << "Supported components:" << std::endl << std::endl;
+ if (traitsList.size() == 0) {
+ out << indent << indent << "NONE" << std::endl << std::endl;
+ } else {
+ for (const auto& traits : traitsList) {
+ dump(out, traits) << std::endl;
+ }
+ }
+
+ // Dump active components.
+ {
+ out << indent << "Active components:" << std::endl << std::endl;
+ std::lock_guard<std::mutex> lock(mComponentRosterMutex);
+ if (mComponentRoster.size() == 0) {
+ out << indent << indent << "NONE" << std::endl << std::endl;
+ } else {
+ for (auto& pair : mComponentRoster) {
+ dump(out, pair.second) << std::endl;
+ }
+ }
+ }
+
+ out << "End of dump -- C2ComponentStore: "
+ << mStore->getName() << std::endl;
+ }
+
+ if (!android::base::WriteStringToFd(out.str(), h->data[0])) {
+ PLOG(WARNING) << "debug -- dumping failed -- write()";
+ } else {
+ LOG(INFO) << "debug -- dumping succeeded";
+ }
+ return Void();
+}
+
+} // namespace utils
+} // namespace V1_2
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
diff --git a/media/codec2/hal/aidl/Configurable.cpp b/media/codec2/hal/aidl/Configurable.cpp
new file mode 100644
index 0000000..530576d
--- /dev/null
+++ b/media/codec2/hal/aidl/Configurable.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 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 "Codec2-Configurable"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/ComponentStore.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <C2ParamInternal.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+CachedConfigurable::CachedConfigurable(
+ std::unique_ptr<ConfigurableC2Intf>&& intf)
+ : mIntf{std::move(intf)} {
+}
+
+c2_status_t CachedConfigurable::init(
+ const std::shared_ptr<ParameterCache>& cache) {
+ // Retrieve supported parameters from store
+ c2_status_t init = mIntf->querySupportedParams(&mSupportedParams);
+ c2_status_t validate = cache->validate(mSupportedParams);
+ return init == C2_OK ? C2_OK : validate;
+}
+
+// Methods from ::android::hardware::media::c2::V1_0::IConfigurable follow.
+Return<uint32_t> CachedConfigurable::getId() {
+ return mIntf->getId();
+}
+
+Return<void> CachedConfigurable::getName(getName_cb _hidl_cb) {
+ _hidl_cb(mIntf->getName());
+ return Void();
+}
+
+Return<void> CachedConfigurable::query(
+ const hidl_vec<uint32_t>& indices,
+ bool mayBlock,
+ query_cb _hidl_cb) {
+ typedef C2Param::Index Index;
+ std::vector<Index> c2heapParamIndices(
+ (Index*)indices.data(),
+ (Index*)indices.data() + indices.size());
+ std::vector<std::unique_ptr<C2Param>> c2heapParams;
+ c2_status_t c2res = mIntf->query(
+ c2heapParamIndices,
+ mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
+ &c2heapParams);
+
+ hidl_vec<uint8_t> params;
+ if (!createParamsBlob(¶ms, c2heapParams)) {
+ LOG(WARNING) << "query -- invalid output params.";
+ }
+ _hidl_cb(static_cast<Status>(c2res), params);
+ return Void();
+}
+
+Return<void> CachedConfigurable::config(
+ const hidl_vec<uint8_t>& inParams,
+ bool mayBlock,
+ config_cb _hidl_cb) {
+ // inParams is not writable, so create a copy as config modifies the parameters
+ hidl_vec<uint8_t> inParamsCopy = inParams;
+ std::vector<C2Param*> c2params;
+ if (!parseParamsBlob(&c2params, inParamsCopy)) {
+ LOG(WARNING) << "config -- invalid input params.";
+ _hidl_cb(Status::CORRUPTED,
+ hidl_vec<SettingResult>(),
+ hidl_vec<uint8_t>());
+ return Void();
+ }
+ // TODO: check if blob was invalid
+ std::vector<std::unique_ptr<C2SettingResult>> c2failures;
+ c2_status_t c2res = mIntf->config(
+ c2params,
+ mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
+ &c2failures);
+ hidl_vec<SettingResult> failures(c2failures.size());
+ {
+ size_t ix = 0;
+ for (const std::unique_ptr<C2SettingResult>& c2result : c2failures) {
+ if (c2result) {
+ if (objcpy(&failures[ix], *c2result)) {
+ ++ix;
+ } else {
+ LOG(DEBUG) << "config -- invalid setting results.";
+ break;
+ }
+ }
+ }
+ failures.resize(ix);
+ }
+ hidl_vec<uint8_t> outParams;
+ if (!createParamsBlob(&outParams, c2params)) {
+ LOG(DEBUG) << "config -- invalid output params.";
+ }
+ _hidl_cb((Status)c2res, failures, outParams);
+ return Void();
+}
+
+Return<void> CachedConfigurable::querySupportedParams(
+ uint32_t start,
+ uint32_t count,
+ querySupportedParams_cb _hidl_cb) {
+ C2LinearRange request = C2LinearCapacity(mSupportedParams.size()).range(
+ start, count);
+ hidl_vec<ParamDescriptor> params(request.size());
+ Status res = Status::OK;
+ size_t dstIx = 0;
+ for (size_t srcIx = request.offset(); srcIx < request.endOffset(); ++srcIx) {
+ if (mSupportedParams[srcIx]) {
+ if (objcpy(¶ms[dstIx], *mSupportedParams[srcIx])) {
+ ++dstIx;
+ } else {
+ res = Status::CORRUPTED;
+ LOG(WARNING) << "querySupportedParams -- invalid output params.";
+ break;
+ }
+ } else {
+ res = Status::BAD_INDEX;
+ }
+ }
+ params.resize(dstIx);
+ _hidl_cb(res, params);
+ return Void();
+}
+
+Return<void> CachedConfigurable::querySupportedValues(
+ const hidl_vec<FieldSupportedValuesQuery>& inFields,
+ bool mayBlock,
+ querySupportedValues_cb _hidl_cb) {
+ std::vector<C2FieldSupportedValuesQuery> c2fields;
+ {
+ // C2FieldSupportedValuesQuery objects are restricted in that some
+ // members are const.
+ // C2ParamField - required for its constructor - has no constructors
+ // from fields. Use C2ParamInspector.
+ for (const FieldSupportedValuesQuery &query : inFields) {
+ c2fields.emplace_back(_C2ParamInspector::CreateParamField(
+ query.field.index,
+ query.field.fieldId.offset,
+ query.field.fieldId.size),
+ query.type == FieldSupportedValuesQuery::Type::POSSIBLE ?
+ C2FieldSupportedValuesQuery::POSSIBLE :
+ C2FieldSupportedValuesQuery::CURRENT);
+ }
+ }
+ c2_status_t c2res = mIntf->querySupportedValues(
+ c2fields,
+ mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
+ hidl_vec<FieldSupportedValuesQueryResult> outFields(inFields.size());
+ size_t dstIx = 0;
+ for (const C2FieldSupportedValuesQuery &result : c2fields) {
+ if (objcpy(&outFields[dstIx], result)) {
+ ++dstIx;
+ } else {
+ outFields.resize(dstIx);
+ c2res = C2_CORRUPTED;
+ LOG(WARNING) << "querySupportedValues -- invalid output params.";
+ break;
+ }
+ }
+ _hidl_cb((Status)c2res, outFields);
+ return Void();
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/aidl/InputBufferManager.cpp b/media/codec2/hal/aidl/InputBufferManager.cpp
new file mode 100644
index 0000000..8c0d0a4
--- /dev/null
+++ b/media/codec2/hal/aidl/InputBufferManager.cpp
@@ -0,0 +1,476 @@
+/*
+ * Copyright 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 "Codec2-InputBufferManager"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputBufferManager.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android-base/logging.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <chrono>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+void InputBufferManager::registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ getInstance()._registerFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ getInstance()._unregisterFrameData(listener, input);
+}
+
+void InputBufferManager::unregisterFrameData(
+ const wp<IComponentListener>& listener) {
+ getInstance()._unregisterFrameData(listener);
+}
+
+void InputBufferManager::setNotificationInterval(
+ nsecs_t notificationIntervalNs) {
+ getInstance()._setNotificationInterval(notificationIntervalNs);
+}
+
+void InputBufferManager::_registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+ LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- called with "
+ << "listener @ 0x" << std::hex << listener.get()
+ << ", frameIndex = " << std::dec << frameIndex
+ << ".";
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ std::set<TrackedBuffer*> &bufferIds =
+ mTrackedBuffersMap[listener][frameIndex];
+
+ for (size_t i = 0; i < input.buffers.size(); ++i) {
+ if (!input.buffers[i]) {
+ LOG(VERBOSE) << "InputBufferManager::_registerFrameData -- "
+ << "Input buffer at index " << i << " is null.";
+ continue;
+ }
+ TrackedBuffer *bufferId =
+ new TrackedBuffer(listener, frameIndex, i, input.buffers[i]);
+ mTrackedBufferCache.emplace(bufferId);
+ bufferIds.emplace(bufferId);
+
+ c2_status_t status = input.buffers[i]->registerOnDestroyNotify(
+ onBufferDestroyed,
+ reinterpret_cast<void*>(bufferId));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "InputBufferManager::_registerFrameData -- "
+ << "registerOnDestroyNotify() failed "
+ << "(listener @ 0x" << std::hex << listener.get()
+ << ", frameIndex = " << std::dec << frameIndex
+ << ", bufferIndex = " << i
+ << ") => status = " << status
+ << ".";
+ }
+ }
+
+ mDeathNotifications.emplace(
+ listener,
+ DeathNotifications(
+ mNotificationIntervalNs.load(std::memory_order_relaxed)));
+}
+
+// Remove a pair (listener, frameIndex) from mTrackedBuffersMap and
+// mDeathNotifications. This implies all bufferIndices are removed.
+//
+// This is called from onWorkDone() and flush().
+void InputBufferManager::_unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input) {
+ uint64_t frameIndex = input.ordinal.frameIndex.peeku();
+ LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+ << "listener @ 0x" << std::hex << listener.unsafe_get()
+ << ", frameIndex = " << std::dec << frameIndex
+ << ".";
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto findListener = mTrackedBuffersMap.find(listener);
+ if (findListener != mTrackedBuffersMap.end()) {
+ std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds
+ = findListener->second;
+ auto findFrameIndex = frameIndex2BufferIds.find(frameIndex);
+ if (findFrameIndex != frameIndex2BufferIds.end()) {
+ std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+ for (TrackedBuffer* bufferId : bufferIds) {
+ std::shared_ptr<C2Buffer> buffer = bufferId->buffer.lock();
+ if (buffer) {
+ c2_status_t status = buffer->unregisterOnDestroyNotify(
+ onBufferDestroyed,
+ reinterpret_cast<void*>(bufferId));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+ << "-- unregisterOnDestroyNotify() failed "
+ << "(listener @ 0x"
+ << std::hex
+ << bufferId->listener.unsafe_get()
+ << ", frameIndex = "
+ << std::dec << bufferId->frameIndex
+ << ", bufferIndex = " << bufferId->bufferIndex
+ << ") => status = " << status
+ << ".";
+ }
+ }
+ mTrackedBufferCache.erase(bufferId);
+ delete bufferId;
+ }
+
+ frameIndex2BufferIds.erase(findFrameIndex);
+ if (frameIndex2BufferIds.empty()) {
+ mTrackedBuffersMap.erase(findListener);
+ }
+ }
+ }
+
+ auto findListenerD = mDeathNotifications.find(listener);
+ if (findListenerD != mDeathNotifications.end()) {
+ DeathNotifications &deathNotifications = findListenerD->second;
+ auto findFrameIndex = deathNotifications.indices.find(frameIndex);
+ if (findFrameIndex != deathNotifications.indices.end()) {
+ std::vector<size_t> &bufferIndices = findFrameIndex->second;
+ deathNotifications.count -= bufferIndices.size();
+ deathNotifications.indices.erase(findFrameIndex);
+ }
+ }
+}
+
+// Remove listener from mTrackedBuffersMap and mDeathNotifications. This implies
+// all frameIndices and bufferIndices are removed.
+//
+// This is called when the component cleans up all input buffers, i.e., when
+// reset(), release(), stop() or ~Component() is called.
+void InputBufferManager::_unregisterFrameData(
+ const wp<IComponentListener>& listener) {
+ LOG(VERBOSE) << "InputBufferManager::_unregisterFrameData -- called with "
+ << "listener @ 0x" << std::hex << listener.unsafe_get()
+ << std::dec << ".";
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ auto findListener = mTrackedBuffersMap.find(listener);
+ if (findListener != mTrackedBuffersMap.end()) {
+ std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds =
+ findListener->second;
+ for (auto findFrameIndex = frameIndex2BufferIds.begin();
+ findFrameIndex != frameIndex2BufferIds.end();
+ ++findFrameIndex) {
+ std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+ for (TrackedBuffer* bufferId : bufferIds) {
+ std::shared_ptr<C2Buffer> buffer = bufferId->buffer.lock();
+ if (buffer) {
+ c2_status_t status = buffer->unregisterOnDestroyNotify(
+ onBufferDestroyed,
+ reinterpret_cast<void*>(bufferId));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "InputBufferManager::_unregisterFrameData "
+ << "-- unregisterOnDestroyNotify() failed "
+ << "(listener @ 0x"
+ << std::hex
+ << bufferId->listener.unsafe_get()
+ << ", frameIndex = "
+ << std::dec << bufferId->frameIndex
+ << ", bufferIndex = " << bufferId->bufferIndex
+ << ") => status = " << status
+ << ".";
+ }
+ mTrackedBufferCache.erase(bufferId);
+ delete bufferId;
+ }
+ }
+ }
+ mTrackedBuffersMap.erase(findListener);
+ }
+
+ mDeathNotifications.erase(listener);
+}
+
+// Set mNotificationIntervalNs.
+void InputBufferManager::_setNotificationInterval(
+ nsecs_t notificationIntervalNs) {
+ mNotificationIntervalNs.store(
+ notificationIntervalNs,
+ std::memory_order_relaxed);
+}
+
+// Move a buffer from mTrackedBuffersMap to mDeathNotifications.
+// This is called when a registered C2Buffer object is destroyed.
+void InputBufferManager::onBufferDestroyed(const C2Buffer* buf, void* arg) {
+ getInstance()._onBufferDestroyed(buf, arg);
+}
+
+void InputBufferManager::_onBufferDestroyed(const C2Buffer* buf, void* arg) {
+ if (!buf || !arg) {
+ LOG(WARNING) << "InputBufferManager::_onBufferDestroyed -- called with "
+ << "null argument (s): "
+ << "buf @ 0x" << std::hex << buf
+ << ", arg @ 0x" << std::hex << arg
+ << std::dec << ".";
+ return;
+ }
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ TrackedBuffer *bufferId = reinterpret_cast<TrackedBuffer*>(arg);
+
+ if (mTrackedBufferCache.find(bufferId) == mTrackedBufferCache.end()) {
+ LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+ << "unregistered buffer: "
+ << "buf @ 0x" << std::hex << buf
+ << ", arg @ 0x" << std::hex << arg
+ << std::dec << ".";
+ return;
+ }
+
+ LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- called with "
+ << "buf @ 0x" << std::hex << buf
+ << ", arg @ 0x" << std::hex << arg
+ << std::dec << " -- "
+ << "listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+ << ", frameIndex = " << std::dec << bufferId->frameIndex
+ << ", bufferIndex = " << bufferId->bufferIndex
+ << ".";
+ auto findListener = mTrackedBuffersMap.find(bufferId->listener);
+ if (findListener == mTrackedBuffersMap.end()) {
+ LOG(VERBOSE) << "InputBufferManager::_onBufferDestroyed -- "
+ << "received invalid listener: "
+ << "listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+ << " (frameIndex = " << std::dec << bufferId->frameIndex
+ << ", bufferIndex = " << bufferId->bufferIndex
+ << ").";
+ return;
+ }
+
+ std::map<uint64_t, std::set<TrackedBuffer*>> &frameIndex2BufferIds
+ = findListener->second;
+ auto findFrameIndex = frameIndex2BufferIds.find(bufferId->frameIndex);
+ if (findFrameIndex == frameIndex2BufferIds.end()) {
+ LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+ << "received invalid frame index: "
+ << "frameIndex = " << bufferId->frameIndex
+ << " (listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+ << ", bufferIndex = " << std::dec << bufferId->bufferIndex
+ << ").";
+ return;
+ }
+
+ std::set<TrackedBuffer*> &bufferIds = findFrameIndex->second;
+ auto findBufferId = bufferIds.find(bufferId);
+ if (findBufferId == bufferIds.end()) {
+ LOG(DEBUG) << "InputBufferManager::_onBufferDestroyed -- "
+ << "received invalid buffer index: "
+ << "bufferIndex = " << bufferId->bufferIndex
+ << " (frameIndex = " << bufferId->frameIndex
+ << ", listener @ 0x" << std::hex << bufferId->listener.unsafe_get()
+ << std::dec << ").";
+ return;
+ }
+
+ bufferIds.erase(findBufferId);
+ if (bufferIds.empty()) {
+ frameIndex2BufferIds.erase(findFrameIndex);
+ if (frameIndex2BufferIds.empty()) {
+ mTrackedBuffersMap.erase(findListener);
+ }
+ }
+
+ DeathNotifications &deathNotifications = mDeathNotifications[bufferId->listener];
+ deathNotifications.indices[bufferId->frameIndex].emplace_back(bufferId->bufferIndex);
+ ++deathNotifications.count;
+ mOnBufferDestroyed.notify_one();
+
+ mTrackedBufferCache.erase(bufferId);
+ delete bufferId;
+}
+
+// Notify the clients about buffer destructions.
+// Return false if all destructions have been notified.
+// Return true and set timeToRetry to the time point to wait for before
+// retrying if some destructions have not been notified.
+bool InputBufferManager::processNotifications(nsecs_t* timeToRetryNs) {
+
+ struct Notification {
+ sp<IComponentListener> listener;
+ hidl_vec<IComponentListener::InputBuffer> inputBuffers;
+ Notification(const sp<IComponentListener>& l, size_t s)
+ : listener(l), inputBuffers(s) {}
+ };
+ std::list<Notification> notifications;
+ nsecs_t notificationIntervalNs =
+ mNotificationIntervalNs.load(std::memory_order_relaxed);
+
+ bool retry = false;
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ *timeToRetryNs = notificationIntervalNs;
+ nsecs_t timeNowNs = systemTime();
+ for (auto it = mDeathNotifications.begin();
+ it != mDeathNotifications.end(); ) {
+ sp<IComponentListener> listener = it->first.promote();
+ if (!listener) {
+ ++it;
+ continue;
+ }
+ DeathNotifications &deathNotifications = it->second;
+
+ nsecs_t timeSinceLastNotifiedNs =
+ timeNowNs - deathNotifications.lastSentNs;
+ // If not enough time has passed since the last callback, leave the
+ // notifications for this listener untouched for now and retry
+ // later.
+ if (timeSinceLastNotifiedNs < notificationIntervalNs) {
+ retry = true;
+ *timeToRetryNs = std::min(*timeToRetryNs,
+ notificationIntervalNs - timeSinceLastNotifiedNs);
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "Notifications for listener @ "
+ << std::hex << listener.get()
+ << " will be postponed.";
+ ++it;
+ continue;
+ }
+
+ // If enough time has passed since the last notification to this
+ // listener but there are currently no pending notifications, the
+ // listener can be removed from mDeathNotifications---there is no
+ // need to keep track of the last notification time anymore.
+ if (deathNotifications.count == 0) {
+ it = mDeathNotifications.erase(it);
+ continue;
+ }
+
+ // Create the argument for the callback.
+ notifications.emplace_back(listener, deathNotifications.count);
+ hidl_vec<IComponentListener::InputBuffer> &inputBuffers =
+ notifications.back().inputBuffers;
+ size_t i = 0;
+ for (std::pair<const uint64_t, std::vector<size_t>>& p :
+ deathNotifications.indices) {
+ uint64_t frameIndex = p.first;
+ const std::vector<size_t> &bufferIndices = p.second;
+ for (const size_t& bufferIndex : bufferIndices) {
+ IComponentListener::InputBuffer &inputBuffer
+ = inputBuffers[i++];
+ inputBuffer.arrayIndex = bufferIndex;
+ inputBuffer.frameIndex = frameIndex;
+ }
+ }
+
+ // Clear deathNotifications for this listener and set retry to true
+ // so processNotifications will be called again. This will
+ // guarantee that a listener with no pending notifications will
+ // eventually be removed from mDeathNotifications after
+ // mNotificationIntervalNs nanoseconds has passed.
+ retry = true;
+ deathNotifications.indices.clear();
+ deathNotifications.count = 0;
+ deathNotifications.lastSentNs = timeNowNs;
+ ++it;
+ }
+ }
+
+ // Call onInputBuffersReleased() outside the lock to avoid deadlock.
+ for (const Notification& notification : notifications) {
+ if (!notification.listener->onInputBuffersReleased(
+ notification.inputBuffers).isOk()) {
+ // This may trigger if the client has died.
+ LOG(DEBUG) << "InputBufferManager::processNotifications -- "
+ << "failed to send death notifications to "
+ << "listener @ 0x" << std::hex
+ << notification.listener.get()
+ << std::dec << ".";
+ } else {
+#if LOG_NDEBUG == 0
+ std::stringstream inputBufferLog;
+ for (const IComponentListener::InputBuffer& inputBuffer :
+ notification.inputBuffers) {
+ inputBufferLog << " (" << inputBuffer.frameIndex
+ << ", " << inputBuffer.arrayIndex
+ << ")";
+ }
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "death notifications sent to "
+ << "listener @ 0x" << std::hex
+ << notification.listener.get()
+ << std::dec
+ << " with these (frameIndex, bufferIndex) pairs:"
+ << inputBufferLog.str();
+#endif
+ }
+ }
+#if LOG_NDEBUG == 0
+ if (retry) {
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "will retry again in " << *timeToRetryNs << "ns.";
+ } else {
+ LOG(VERBOSE) << "InputBufferManager::processNotifications -- "
+ << "no pending death notifications.";
+ }
+#endif
+ return retry;
+}
+
+void InputBufferManager::main() {
+ LOG(VERBOSE) << "InputBufferManager main -- started.";
+ nsecs_t timeToRetryNs;
+ while (true) {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mDeathNotifications.empty()) {
+ mOnBufferDestroyed.wait(lock);
+ }
+ lock.unlock();
+ while (processNotifications(&timeToRetryNs)) {
+ std::this_thread::sleep_for(
+ std::chrono::nanoseconds(timeToRetryNs));
+ }
+ }
+}
+
+InputBufferManager::InputBufferManager()
+ : mMainThread{&InputBufferManager::main, this} {
+}
+
+InputBufferManager& InputBufferManager::getInstance() {
+ static InputBufferManager instance{};
+ return instance;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+
+
diff --git a/media/codec2/hal/aidl/InputSurface.cpp b/media/codec2/hal/aidl/InputSurface.cpp
new file mode 100644
index 0000000..c3c32e9
--- /dev/null
+++ b/media/codec2/hal/aidl/InputSurface.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright 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 "Codec2-InputSurface"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputSurface.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+
+#include <C2Component.h>
+#include <C2Config.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+// Derived class of C2InterfaceHelper
+class InputSurface::Interface : public C2InterfaceHelper {
+public:
+ explicit Interface(
+ const std::shared_ptr<C2ReflectorHelper> &helper)
+ : C2InterfaceHelper(helper) {
+
+ setDerivedInstance(this);
+
+ addParameter(
+ DefineParam(mEos, C2_PARAMKEY_INPUT_SURFACE_EOS)
+ .withDefault(new C2InputSurfaceEosTuning(false))
+ .withFields({C2F(mEos, value).oneOf({true, false})})
+ .withSetter(EosSetter)
+ .build());
+ }
+
+ static C2R EosSetter(bool mayBlock, C2P<C2InputSurfaceEosTuning> &me) {
+ (void)mayBlock;
+ return me.F(me.v.value).validatePossible(me.v.value);
+ }
+
+ bool eos() const { return mEos->value; }
+
+private:
+ std::shared_ptr<C2InputSurfaceEosTuning> mEos;
+};
+
+// Derived class of ConfigurableC2Intf
+class InputSurface::ConfigurableIntf : public ConfigurableC2Intf {
+public:
+ ConfigurableIntf(
+ const std::shared_ptr<InputSurface::Interface> &intf,
+ const sp<GraphicBufferSource> &source)
+ : ConfigurableC2Intf("input-surface", 0),
+ mIntf(intf),
+ mSource(source) {
+ }
+
+ virtual ~ConfigurableIntf() override = default;
+
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params
+ ) const override {
+ return mIntf->query({}, indices, mayBlock, params);
+ }
+
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures
+ ) override {
+ c2_status_t err = mIntf->config(params, mayBlock, failures);
+ if (mIntf->eos()) {
+ sp<GraphicBufferSource> source = mSource.promote();
+ if (source == nullptr || source->signalEndOfInputStream() != OK) {
+ // TODO: put something in |failures|
+ err = C2_BAD_VALUE;
+ }
+ // TODO: reset eos?
+ }
+ return err;
+ }
+
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params
+ ) const override {
+ return mIntf->querySupportedParams(params);
+ }
+
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields,
+ c2_blocking_t mayBlock) const override {
+ return mIntf->querySupportedValues(fields, mayBlock);
+ }
+
+private:
+ const std::shared_ptr<InputSurface::Interface> mIntf;
+ wp<GraphicBufferSource> mSource;
+};
+
+Return<sp<InputSurface::HGraphicBufferProducer>> InputSurface::getGraphicBufferProducer() {
+ return mProducer;
+}
+
+Return<sp<IConfigurable>> InputSurface::getConfigurable() {
+ return mConfigurable;
+}
+
+Return<void> InputSurface::connect(
+ const sp<IInputSink>& sink,
+ connect_cb _hidl_cb) {
+ Status status;
+ sp<InputSurfaceConnection> connection;
+ if (!sink) {
+ _hidl_cb(Status::BAD_VALUE, nullptr);
+ return Void();
+ }
+ std::shared_ptr<C2Component> comp = Component::findLocalComponent(sink);
+ if (comp) {
+ connection = new InputSurfaceConnection(mSource, comp, mParameterCache);
+ } else {
+ connection = new InputSurfaceConnection(mSource, sink, mParameterCache);
+ }
+ if (!connection->init()) {
+ connection = nullptr;
+ status = Status::BAD_VALUE;
+ } else {
+ status = Status::OK;
+ }
+ _hidl_cb(status, connection);
+ return Void();
+}
+
+// Constructor is exclusive to ComponentStore.
+InputSurface::InputSurface(
+ const std::shared_ptr<ParameterCache>& cache,
+ const std::shared_ptr<C2ReflectorHelper>& reflector,
+ const sp<HGraphicBufferProducer>& producer,
+ const sp<GraphicBufferSource>& source)
+ : mParameterCache{cache},
+ mProducer{producer},
+ mSource{source},
+ mIntf{std::make_shared<Interface>(reflector)},
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<ConfigurableIntf>(
+ mIntf, source))} {
+
+ mConfigurable->init(mParameterCache);
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/aidl/InputSurfaceConnection.cpp b/media/codec2/hal/aidl/InputSurfaceConnection.cpp
new file mode 100644
index 0000000..7c2e014
--- /dev/null
+++ b/media/codec2/hal/aidl/InputSurfaceConnection.cpp
@@ -0,0 +1,531 @@
+/*
+ * Copyright 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 "Codec2-InputSurfaceConnection"
+#include <android-base/logging.h>
+
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+#include <codec2/hidl/1.0/InputSurfaceConnection.h>
+
+#include <memory>
+#include <list>
+#include <mutex>
+#include <atomic>
+
+#include <hidl/HidlSupport.h>
+#include <media/stagefright/bqhelper/ComponentWrapper.h>
+#include <system/graphics.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Errors.h>
+
+#include <C2.h>
+#include <C2AllocatorGralloc.h>
+#include <C2BlockInternal.h>
+#include <C2Buffer.h>
+#include <C2Component.h>
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <C2Work.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+constexpr int32_t kBufferCount = 16;
+
+using namespace ::android;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+
+namespace /* unnamed */ {
+
+class Buffer2D : public C2Buffer {
+public:
+ explicit Buffer2D(C2ConstGraphicBlock block) : C2Buffer({ block }) {
+ }
+};
+
+} // unnamed namespace
+
+// Derived class of ComponentWrapper for use with
+// GraphicBufferSource::configure().
+//
+struct InputSurfaceConnection::Impl : public ComponentWrapper {
+
+ Impl(const sp<GraphicBufferSource>& source,
+ const std::shared_ptr<C2Component>& localComp)
+ : mSource{source}, mLocalComp{localComp}, mSink{}, mFrameIndex{0} {
+ std::shared_ptr<C2ComponentInterface> intf = localComp->intf();
+ mSinkName = intf ? intf->getName() : "";
+ }
+
+ Impl(const sp<GraphicBufferSource>& source,
+ const sp<IInputSink>& sink)
+ : mSource{source}, mLocalComp{}, mSink{sink}, mFrameIndex{0} {
+ Return<sp<IConfigurable>> transResult = sink->getConfigurable();
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "Remote sink is dead.";
+ return;
+ }
+ mSinkConfigurable =
+ static_cast<sp<IConfigurable>>(transResult);
+ if (!mSinkConfigurable) {
+ LOG(ERROR) << "Remote sink is not configurable.";
+ mSinkName = "";
+ return;
+ }
+
+ hidl_string name;
+ Return<void> transStatus = mSinkConfigurable->getName(
+ [&name](const hidl_string& n) {
+ name = n;
+ });
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "Remote sink's configurable is dead.";
+ mSinkName = "";
+ return;
+ }
+ mSinkName = name.c_str();
+ }
+
+ virtual ~Impl() {
+ mSource->stop();
+ mSource->release();
+ }
+
+ bool init() {
+ if (mSource == nullptr) {
+ return false;
+ }
+ status_t err = mSource->initCheck();
+ if (err != OK) {
+ LOG(WARNING) << "Impl::init -- GraphicBufferSource init failed: "
+ << "status = " << err << ".";
+ return false;
+ }
+
+ // TODO: read settings properly from the interface
+ C2StreamPictureSizeInfo::input inputSize;
+ C2StreamUsageTuning::input usage;
+ c2_status_t c2Status = queryFromSink({ &inputSize, &usage },
+ {},
+ C2_MAY_BLOCK,
+ nullptr);
+ if (c2Status != C2_OK) {
+ LOG(WARNING) << "Impl::init -- cannot query information from "
+ "the component interface: "
+ << "status = " << asString(c2Status) << ".";
+ return false;
+ }
+
+ // TODO: proper color aspect & dataspace
+ android_dataspace dataSpace = HAL_DATASPACE_BT709;
+
+ // TODO: use the usage read from intf
+ // uint32_t grallocUsage =
+ // C2AndroidMemoryUsage(C2MemoryUsage(usage.value)).
+ // asGrallocUsage();
+
+ uint32_t grallocUsage =
+ mSinkName.compare(0, 11, "c2.android.") == 0 ?
+ GRALLOC_USAGE_SW_READ_OFTEN :
+ GRALLOC_USAGE_HW_VIDEO_ENCODER;
+
+ err = mSource->configure(
+ this, dataSpace, kBufferCount,
+ inputSize.width, inputSize.height,
+ grallocUsage);
+ if (err != OK) {
+ LOG(WARNING) << "Impl::init -- GBS configure failed: "
+ << "status = " << err << ".";
+ return false;
+ }
+ for (int32_t i = 0; i < kBufferCount; ++i) {
+ if (mSource->onInputBufferAdded(i) != OK) {
+ LOG(WARNING) << "Impl::init: failed to populate GBS slots.";
+ return false;
+ }
+ }
+ if (mSource->start() != OK) {
+ LOG(WARNING) << "Impl::init -- GBS failed to start.";
+ return false;
+ }
+ mAllocatorMutex.lock();
+ c2_status_t c2err = GetCodec2PlatformAllocatorStore()->fetchAllocator(
+ C2AllocatorStore::PLATFORM_START + 1, // GRALLOC
+ &mAllocator);
+ mAllocatorMutex.unlock();
+ if (c2err != OK) {
+ LOG(WARNING) << "Impl::init -- failed to fetch gralloc allocator: "
+ << "status = " << asString(c2err) << ".";
+ return false;
+ }
+ return true;
+ }
+
+ // From ComponentWrapper
+ virtual status_t submitBuffer(
+ int32_t bufferId,
+ const sp<GraphicBuffer>& buffer,
+ int64_t timestamp,
+ int fenceFd) override {
+ LOG(VERBOSE) << "Impl::submitBuffer -- bufferId = " << bufferId << ".";
+ // TODO: Use fd to construct fence
+ (void)fenceFd;
+
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ C2Handle* handle = WrapNativeCodec2GrallocHandle(
+ buffer->handle,
+ buffer->width, buffer->height,
+ buffer->format, buffer->usage, buffer->stride);
+ mAllocatorMutex.lock();
+ c2_status_t err = mAllocator->priorGraphicAllocation(handle, &alloc);
+ mAllocatorMutex.unlock();
+ if (err != OK) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ return UNKNOWN_ERROR;
+ }
+ std::shared_ptr<C2GraphicBlock> block =
+ _C2BlockFactory::CreateGraphicBlock(alloc);
+
+ std::unique_ptr<C2Work> work(new C2Work);
+ work->input.flags = (C2FrameData::flags_t)0;
+ work->input.ordinal.timestamp = timestamp;
+ work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
+ 1, std::memory_order_relaxed);
+ work->input.buffers.clear();
+ std::shared_ptr<C2Buffer> c2Buffer(
+ // TODO: fence
+ new Buffer2D(block->share(
+ C2Rect(block->width(), block->height()), ::C2Fence())),
+ [bufferId, source = mSource](C2Buffer* ptr) {
+ delete ptr;
+ if (source != nullptr) {
+ // TODO: fence
+ (void)source->onInputBufferEmptied(bufferId, -1);
+ }
+ });
+ work->input.buffers.push_back(c2Buffer);
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+
+ err = queueToSink(&items);
+ return (err == C2_OK) ? OK : UNKNOWN_ERROR;
+ }
+
+ virtual status_t submitEos(int32_t bufferId) override {
+ LOG(VERBOSE) << "Impl::submitEos -- bufferId = " << bufferId << ".";
+ (void)bufferId;
+
+ std::unique_ptr<C2Work> work(new C2Work);
+ work->input.flags = (C2FrameData::flags_t)0;
+ work->input.ordinal.frameIndex = mFrameIndex.fetch_add(
+ 1, std::memory_order_relaxed);
+ work->input.buffers.clear();
+ work->worklets.clear();
+ work->worklets.emplace_back(new C2Worklet);
+ std::list<std::unique_ptr<C2Work>> items;
+ items.push_back(std::move(work));
+
+ c2_status_t err = queueToSink(&items);
+ return (err == C2_OK) ? OK : UNKNOWN_ERROR;
+ }
+
+ virtual void dispatchDataSpaceChanged(
+ int32_t dataSpace, int32_t aspects, int32_t pixelFormat) override {
+ // TODO
+ (void)dataSpace;
+ (void)aspects;
+ (void)pixelFormat;
+ }
+
+ // Configurable interface for InputSurfaceConnection::Impl.
+ //
+ // This class is declared as an inner class so that it will have access to
+ // all Impl's members.
+ struct ConfigurableIntf : public ConfigurableC2Intf {
+ sp<Impl> mConnection;
+ ConfigurableIntf(const sp<Impl>& connection)
+ : ConfigurableC2Intf{"input-surface-connection", 0},
+ mConnection{connection} {}
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures
+ ) override;
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>> *const params) const override;
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params
+ ) const override;
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const override;
+ };
+
+private:
+ c2_status_t queryFromSink(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) {
+ if (mLocalComp) {
+ std::shared_ptr<C2ComponentInterface> intf = mLocalComp->intf();
+ if (intf) {
+ return intf->query_vb(stackParams,
+ heapParamIndices,
+ mayBlock,
+ heapParams);
+ } else {
+ LOG(ERROR) << "queryFromSink -- "
+ << "component does not have an interface.";
+ return C2_BAD_STATE;
+ }
+ }
+
+ CHECK(mSink) << "-- queryFromSink "
+ << "-- connection has no sink.";
+ CHECK(mSinkConfigurable) << "-- queryFromSink "
+ << "-- sink has no configurable.";
+
+ hidl_vec<ParamIndex> indices(
+ stackParams.size() + heapParamIndices.size());
+ size_t numIndices = 0;
+ for (C2Param* const& stackParam : stackParams) {
+ if (!stackParam) {
+ LOG(DEBUG) << "queryFromSink -- null stack param encountered.";
+ continue;
+ }
+ indices[numIndices++] = static_cast<ParamIndex>(stackParam->index());
+ }
+ size_t numStackIndices = numIndices;
+ for (const C2Param::Index& index : heapParamIndices) {
+ indices[numIndices++] =
+ static_cast<ParamIndex>(static_cast<uint32_t>(index));
+ }
+ indices.resize(numIndices);
+ if (heapParams) {
+ heapParams->reserve(heapParams->size() + numIndices);
+ }
+ c2_status_t status;
+ Return<void> transStatus = mSinkConfigurable->query(
+ indices,
+ mayBlock == C2_MAY_BLOCK,
+ [&status, &numStackIndices, &stackParams, heapParams](
+ Status s, const Params& p) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK && status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "queryFromSink -- call failed: "
+ << "status = " << asString(status) << ".";
+ return;
+ }
+ std::vector<C2Param*> paramPointers;
+ if (!parseParamsBlob(¶mPointers, p)) {
+ LOG(DEBUG) << "queryFromSink -- error while "
+ << "parsing params.";
+ status = C2_CORRUPTED;
+ return;
+ }
+ size_t i = 0;
+ for (auto it = paramPointers.begin();
+ it != paramPointers.end(); ) {
+ C2Param* paramPointer = *it;
+ if (numStackIndices > 0) {
+ --numStackIndices;
+ if (!paramPointer) {
+ LOG(DEBUG) << "queryFromSink -- "
+ "null stack param.";
+ ++it;
+ continue;
+ }
+ for (; i < stackParams.size() &&
+ !stackParams[i]; ) {
+ ++i;
+ }
+ CHECK(i < stackParams.size());
+ if (stackParams[i]->index() !=
+ paramPointer->index()) {
+ LOG(DEBUG) << "queryFromSink -- "
+ "param skipped (index = "
+ << stackParams[i]->index() << ").";
+ stackParams[i++]->invalidate();
+ continue;
+ }
+ if (!stackParams[i++]->updateFrom(*paramPointer)) {
+ LOG(DEBUG) << "queryFromSink -- "
+ "param update failed (index = "
+ << paramPointer->index() << ").";
+ }
+ } else {
+ if (!paramPointer) {
+ LOG(DEBUG) << "queryFromSink -- "
+ "null heap param.";
+ ++it;
+ continue;
+ }
+ if (!heapParams) {
+ LOG(WARNING) << "queryFromSink -- "
+ "too many stack params.";
+ break;
+ }
+ heapParams->emplace_back(C2Param::Copy(*paramPointer));
+ }
+ ++it;
+ }
+ });
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "queryFromSink -- transaction failed.";
+ return C2_CORRUPTED;
+ }
+ return status;
+ }
+
+ c2_status_t queueToSink(std::list<std::unique_ptr<C2Work>>* const items) {
+ if (mLocalComp) {
+ return mLocalComp->queue_nb(items);
+ }
+
+ CHECK(mSink) << "-- queueToSink "
+ << "-- connection has no sink.";
+
+ WorkBundle workBundle;
+ if (!objcpy(&workBundle, *items, nullptr)) {
+ LOG(ERROR) << "queueToSink -- bad input.";
+ return C2_CORRUPTED;
+ }
+ Return<Status> transStatus = mSink->queue(workBundle);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "queueToSink -- transaction failed.";
+ return C2_CORRUPTED;
+ }
+ c2_status_t status =
+ static_cast<c2_status_t>(static_cast<Status>(transStatus));
+ if (status != C2_OK) {
+ LOG(DEBUG) << "queueToSink -- call failed: "
+ << asString(status);
+ }
+ return status;
+ }
+
+ sp<GraphicBufferSource> mSource;
+ std::shared_ptr<C2Component> mLocalComp;
+ sp<IInputSink> mSink;
+ sp<IConfigurable> mSinkConfigurable;
+ std::string mSinkName;
+
+ // Needed for ComponentWrapper implementation
+ std::mutex mAllocatorMutex;
+ std::shared_ptr<C2Allocator> mAllocator;
+ std::atomic_uint64_t mFrameIndex;
+
+};
+
+InputSurfaceConnection::InputSurfaceConnection(
+ const sp<GraphicBufferSource>& source,
+ const std::shared_ptr<C2Component>& comp,
+ const std::shared_ptr<ParameterCache>& cache)
+ : mImpl{new Impl(source, comp)},
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+ mConfigurable->init(cache);
+}
+
+InputSurfaceConnection::InputSurfaceConnection(
+ const sp<GraphicBufferSource>& source,
+ const sp<IInputSink>& sink,
+ const std::shared_ptr<ParameterCache>& cache)
+ : mImpl{new Impl(source, sink)},
+ mConfigurable{new CachedConfigurable(
+ std::make_unique<Impl::ConfigurableIntf>(mImpl))} {
+ mConfigurable->init(cache);
+}
+
+Return<Status> InputSurfaceConnection::disconnect() {
+ std::lock_guard<std::mutex> lock(mImplMutex);
+ mImpl = nullptr;
+ return Status::OK;
+}
+
+InputSurfaceConnection::~InputSurfaceConnection() {
+ mImpl = nullptr;
+}
+
+bool InputSurfaceConnection::init() {
+ std::lock_guard<std::mutex> lock(mImplMutex);
+ return mImpl->init();
+}
+
+Return<sp<IConfigurable>> InputSurfaceConnection::getConfigurable() {
+ return mConfigurable;
+}
+
+// Configurable interface for InputSurfaceConnection::Impl
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
+ // TODO: implement
+ (void)params;
+ (void)mayBlock;
+ (void)failures;
+ return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>> *const params) const {
+ // TODO: implement
+ (void)indices;
+ (void)mayBlock;
+ (void)params;
+ return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
+ // TODO: implement
+ (void)params;
+ return C2_OK;
+}
+
+c2_status_t InputSurfaceConnection::Impl::ConfigurableIntf::querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const {
+ // TODO: implement
+ (void)fields;
+ (void)mayBlock;
+ return C2_OK;
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
diff --git a/media/codec2/hal/aidl/ParamTypes.cpp b/media/codec2/hal/aidl/ParamTypes.cpp
index 0a430f9..7026f4c 100644
--- a/media/codec2/hal/aidl/ParamTypes.cpp
+++ b/media/codec2/hal/aidl/ParamTypes.cpp
@@ -157,14 +157,13 @@
namespace c2 {
namespace utils {
+// TODO: read it from aconfig flags
+bool IsEnabled() { return false; }
+
const char* asString(Status status, const char* def) {
return asString(static_cast<c2_status_t>(status.status), def);
}
-namespace /* unnamed */ {
-
-} // unnamed namespace
-
// C2FieldSupportedValuesQuery -> FieldSupportedValuesQuery
bool ToAidl(
FieldSupportedValuesQuery* d,
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Component.h b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
new file mode 100644
index 0000000..e343655
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
+
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <hidl/Status.h>
+#include <hwbinder/IBinder.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::IBinder;
+using ::android::sp;
+using ::android::wp;
+
+struct ComponentStore;
+
+struct Component : public IComponent,
+ public std::enable_shared_from_this<Component> {
+ Component(
+ const std::shared_ptr<C2Component>&,
+ const sp<IComponentListener>& listener,
+ const sp<ComponentStore>& store,
+ const sp<::android::hardware::media::bufferpool::V2_0::
+ IClientManager>& clientPoolManager);
+ c2_status_t status() const;
+
+ typedef ::android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer HGraphicBufferProducer1;
+ typedef ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer HGraphicBufferProducer2;
+
+ // Methods from IComponent follow.
+ virtual Return<Status> queue(const WorkBundle& workBundle) override;
+ virtual Return<void> flush(flush_cb _hidl_cb) override;
+ virtual Return<Status> drain(bool withEos) override;
+ virtual Return<Status> setOutputSurface(
+ uint64_t blockPoolId,
+ const sp<HGraphicBufferProducer2>& surface) override;
+ virtual Return<void> connectToInputSurface(
+ const sp<IInputSurface>& inputSurface,
+ connectToInputSurface_cb _hidl_cb) override;
+ virtual Return<void> connectToOmxInputSurface(
+ const sp<HGraphicBufferProducer1>& producer,
+ const sp<::android::hardware::media::omx::V1_0::
+ IGraphicBufferSource>& source,
+ connectToOmxInputSurface_cb _hidl_cb) override;
+ virtual Return<Status> disconnectFromInputSurface() override;
+ virtual Return<void> createBlockPool(
+ uint32_t allocatorId,
+ createBlockPool_cb _hidl_cb) override;
+ virtual Return<Status> destroyBlockPool(uint64_t blockPoolId) override;
+ virtual Return<Status> start() override;
+ virtual Return<Status> stop() override;
+ virtual Return<Status> reset() override;
+ virtual Return<Status> release() override;
+ virtual Return<sp<IComponentInterface>> getInterface() override;
+ virtual Return<sp<IInputSink>> asInputSink() override;
+
+ // Returns a C2Component associated to the given sink if the sink is indeed
+ // a local component. Returns nullptr otherwise.
+ //
+ // This function is used by InputSurface::connect().
+ static std::shared_ptr<C2Component> findLocalComponent(
+ const sp<IInputSink>& sink);
+
+protected:
+ c2_status_t mInit;
+ std::shared_ptr<C2Component> mComponent;
+ sp<ComponentInterface> mInterface;
+ sp<IComponentListener> mListener;
+ sp<ComponentStore> mStore;
+ ::android::hardware::media::c2::V1_0::utils::DefaultBufferPoolSender
+ mBufferPoolSender;
+
+ struct Sink;
+ std::mutex mSinkMutex;
+ sp<Sink> mSink;
+
+ std::mutex mBlockPoolsMutex;
+ // This map keeps C2BlockPool objects that are created by createBlockPool()
+ // alive. These C2BlockPool objects can be deleted by calling
+ // destroyBlockPool(), reset() or release(), or by destroying the component.
+ std::map<uint64_t, std::shared_ptr<C2BlockPool>> mBlockPools;
+
+ void initListener(const sp<Component>& self);
+
+ virtual ~Component() override;
+
+ friend struct ComponentStore;
+
+ struct Listener;
+
+ using HwDeathRecipient = ::android::hardware::hidl_death_recipient;
+ sp<HwDeathRecipient> mDeathRecipient;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_COMPONENT_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
new file mode 100644
index 0000000..9102f92
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentInterface.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
+
+#include <codec2/hidl/1.0/Configurable.h>
+#include <codec2/hidl/1.0/types.h>
+
+#include <android/hardware/media/c2/1.0/IComponentInterface.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Buffer.h>
+#include <C2.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+struct ComponentInterface : public IComponentInterface {
+ ComponentInterface(
+ const std::shared_ptr<C2ComponentInterface>& interface,
+ const std::shared_ptr<ParameterCache>& cache);
+ c2_status_t status() const;
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+protected:
+ std::shared_ptr<C2ComponentInterface> mInterface;
+ sp<CachedConfigurable> mConfigurable;
+ c2_status_t mInit;
+};
+
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_COMPONENT_INTERFACE_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
new file mode 100644
index 0000000..27e2a05
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
+#define CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/ComponentInterface.h>
+#include <codec2/hidl/1.0/Configurable.h>
+
+#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
+#include <android/hardware/media/c2/1.0/IComponentStore.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <chrono>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <vector>
+
+namespace android {
+class FilterWrapper;
+
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::media::bufferpool::V2_0::IClientManager;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore : public IComponentStore {
+ ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
+ virtual ~ComponentStore();
+
+ /**
+ * Returns the status of the construction of this object.
+ */
+ c2_status_t status() const;
+
+ /**
+ * This function is called by CachedConfigurable::init() to validate
+ * supported parameters.
+ */
+ c2_status_t validateSupportedParams(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>& params);
+
+ /**
+ * Returns the store's ParameterCache. This is used for validation by
+ * Configurable::init().
+ */
+ std::shared_ptr<ParameterCache> getParameterCache() const;
+
+ static std::shared_ptr<FilterWrapper> GetFilterWrapper();
+
+ // Methods from ::android::hardware::media::c2::V1_0::IComponentStore.
+ virtual Return<void> createComponent(
+ const hidl_string& name,
+ const sp<IComponentListener>& listener,
+ const sp<IClientManager>& pool,
+ createComponent_cb _hidl_cb) override;
+ virtual Return<void> createInterface(
+ const hidl_string& name,
+ createInterface_cb _hidl_cb) override;
+ virtual Return<void> listComponents(listComponents_cb _hidl_cb) override;
+ virtual Return<void> createInputSurface(
+ createInputSurface_cb _hidl_cb) override;
+ virtual Return<void> getStructDescriptors(
+ const hidl_vec<uint32_t>& indices,
+ getStructDescriptors_cb _hidl_cb) override;
+ virtual Return<sp<IClientManager>> getPoolClientManager() override;
+ virtual Return<Status> copyBuffer(
+ const Buffer& src,
+ const Buffer& dst) override;
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+ /**
+ * Dumps information when lshal is called.
+ */
+ virtual Return<void> debug(
+ const hidl_handle& handle,
+ const hidl_vec<hidl_string>& args) override;
+
+protected:
+ sp<CachedConfigurable> mConfigurable;
+ struct StoreParameterCache;
+ std::shared_ptr<StoreParameterCache> mParameterCache;
+
+ // Does bookkeeping for an interface that has been loaded.
+ void onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf);
+
+ c2_status_t mInit;
+ std::shared_ptr<C2ComponentStore> mStore;
+ std::shared_ptr<C2ParamReflector> mParamReflector;
+
+ std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
+ std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
+ std::set<C2String> mLoadedInterfaces;
+ mutable std::mutex mStructDescriptorsMutex;
+
+ // ComponentStore keeps track of live Components.
+
+ struct ComponentStatus {
+ std::shared_ptr<C2Component> c2Component;
+ std::chrono::system_clock::time_point birthTime;
+ };
+
+ mutable std::mutex mComponentRosterMutex;
+ std::map<Component*, ComponentStatus> mComponentRoster;
+
+ // Called whenever Component is created.
+ void reportComponentBirth(Component* component);
+ // Called only from the destructor of Component.
+ void reportComponentDeath(Component* component);
+
+ friend Component;
+
+ // Helper functions for dumping.
+
+ std::ostream& dump(
+ std::ostream& out,
+ const std::shared_ptr<const C2Component::Traits>& comp);
+
+ std::ostream& dump(
+ std::ostream& out,
+ ComponentStatus& compStatus);
+
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_COMPONENTSTORE_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
new file mode 100644
index 0000000..8f49a97
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+#define CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+#include <C2Param.h>
+#include <C2.h>
+
+#include <memory>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct ComponentStore;
+
+/**
+ * Codec2 objects of different types may have different querying and configuring
+ * functions, but across the Treble boundary, they share the same HIDL
+ * interface, IConfigurable.
+ *
+ * ConfigurableC2Intf is an abstract class that a Codec2 object can implement to
+ * easily expose an IConfigurable instance. See CachedConfigurable below.
+ */
+struct ConfigurableC2Intf {
+ C2String getName() const { return mName; }
+ uint32_t getId() const { return mId; }
+ /** C2ComponentInterface::query_vb sans stack params */
+ virtual c2_status_t query(
+ const std::vector<C2Param::Index> &indices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const params) const = 0;
+ /** C2ComponentInterface::config_vb */
+ virtual c2_status_t config(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) = 0;
+ /** C2ComponentInterface::querySupportedParams_nb */
+ virtual c2_status_t querySupportedParams(
+ std::vector<std::shared_ptr<C2ParamDescriptor>>* const params) const = 0;
+ /** C2ComponentInterface::querySupportedParams_nb */
+ virtual c2_status_t querySupportedValues(
+ std::vector<C2FieldSupportedValuesQuery>& fields, c2_blocking_t mayBlock) const = 0;
+
+ virtual ~ConfigurableC2Intf() = default;
+
+ ConfigurableC2Intf(const C2String& name, uint32_t id)
+ : mName{name}, mId{id} {}
+
+protected:
+ C2String mName; /* cached component name */
+ uint32_t mId;
+};
+
+/**
+ * Type for validating and caching parameters when CachedConfigurable is
+ * initialized.
+ *
+ * This is meant to be created by the ComponentStore. The purpose of abstracting
+ * this is to allow different versions of ComponentStore to work with this
+ * CachedConfigurable.
+ */
+struct ParameterCache {
+ virtual c2_status_t validate(
+ const std::vector<std::shared_ptr<C2ParamDescriptor>>&) = 0;
+ virtual ~ParameterCache() = default;
+};
+
+/**
+ * Implementation of the IConfigurable interface that supports caching of
+ * supported parameters from a supplied ComponentStore.
+ *
+ * CachedConfigurable essentially converts a ConfigurableC2Intf into HIDL's
+ * IConfigurable. A Codec2 object generally implements ConfigurableC2Intf and
+ * passes the implementation to the constructor of CachedConfigurable.
+ *
+ * Note that caching happens
+ */
+struct CachedConfigurable : public IConfigurable {
+ CachedConfigurable(std::unique_ptr<ConfigurableC2Intf>&& intf);
+
+ // Populates mSupportedParams.
+ c2_status_t init(const std::shared_ptr<ParameterCache> &cache);
+
+ // Methods from ::android::hardware::media::c2::V1_0::IConfigurable
+
+ virtual Return<uint32_t> getId() override;
+
+ virtual Return<void> getName(getName_cb _hidl_cb) override;
+
+ virtual Return<void> query(
+ const hidl_vec<uint32_t>& indices,
+ bool mayBlock,
+ query_cb _hidl_cb) override;
+
+ virtual Return<void> config(
+ const hidl_vec<uint8_t>& inParams,
+ bool mayBlock,
+ config_cb _hidl_cb) override;
+
+ virtual Return<void> querySupportedParams(
+ uint32_t start,
+ uint32_t count,
+ querySupportedParams_cb _hidl_cb) override;
+
+ virtual Return<void> querySupportedValues(
+ const hidl_vec<FieldSupportedValuesQuery>& inFields,
+ bool mayBlock,
+ querySupportedValues_cb _hidl_cb) override;
+
+protected:
+ // Common Codec2.0 interface wrapper
+ std::unique_ptr<ConfigurableC2Intf> mIntf;
+
+ // Cached supported params
+ std::vector<std::shared_ptr<C2ParamDescriptor>> mSupportedParams;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_CONFIGURABLE_H
+
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h b/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h
new file mode 100644
index 0000000..42fa557
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/InputBufferManager.h
@@ -0,0 +1,300 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
+#include <android/hardware/media/c2/1.0/IComponentListener.h>
+#include <utils/Timers.h>
+
+#include <C2Buffer.h>
+#include <C2Work.h>
+
+#include <set>
+#include <map>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using namespace ::android;
+
+/**
+ * InputBufferManager
+ * ==================
+ *
+ * InputBufferManager presents a way to track and untrack input buffers in this
+ * (codec) process and send a notification to a listener, possibly in a
+ * different process, when a tracked buffer no longer has any references in this
+ * process.
+ *
+ * InputBufferManager holds a collection of records representing tracked buffers
+ * and their callback listeners. Conceptually, one record is a triple (listener,
+ * frameIndex, bufferIndex) where
+ *
+ * - (frameIndex, bufferIndex) is a pair of indices used to identify the buffer.
+ * - listener is of type IComponentListener. Its onInputBuffersReleased()
+ * function will be called after the associated buffer dies. The argument of
+ * onInputBuffersReleased() is a list of InputBuffer objects, each of which
+ * has the following members:
+ *
+ * uint64_t frameIndex
+ * uint32_t arrayIndex
+ *
+ * When a tracked buffer associated to the triple (listener, frameIndex,
+ * bufferIndex) goes out of scope, listener->onInputBuffersReleased() will be
+ * called with an InputBuffer object whose members are set as follows:
+ *
+ * inputBuffer.frameIndex = frameIndex
+ * inputBuffer.arrayIndex = bufferIndex
+ *
+ * IPC Optimization
+ * ----------------
+ *
+ * Since onInputBuffersReleased() is an IPC call, InputBufferManager tries not
+ * to call it too often. Any two calls to the same listener are at least
+ * mNotificationIntervalNs nanoseconds apart, where mNotificationIntervalNs is
+ * configurable via calling setNotificationInterval(). The default value of
+ * mNotificationIntervalNs is kDefaultNotificationInternalNs.
+ *
+ * Public Member Functions
+ * -----------------------
+ *
+ * InputBufferManager is a singleton class. Its only instance is accessible via
+ * the following public functions:
+ *
+ * - registerFrameData(const sp<IComponentListener>& listener,
+ * const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener,
+ * const C2FrameData& input)
+ *
+ * - unregisterFrameData(const sp<IComponentListener>& listener)
+ *
+ * - setNotificationInterval(nsecs_t notificationIntervalNs)
+ *
+ */
+
+struct InputBufferManager {
+
+ /**
+ * The default value for the time interval between 2 subsequent IPCs.
+ */
+ static constexpr nsecs_t kDefaultNotificationIntervalNs = 1000000; /* 1ms */
+
+ /**
+ * Track all buffers in a C2FrameData object.
+ *
+ * input (C2FrameData) has the following two members that are of interest:
+ *
+ * C2WorkOrdinal ordinal
+ * vector<shared_ptr<C2Buffer>> buffers
+ *
+ * Calling registerFrameData(listener, input) will register multiple
+ * triples (listener, frameIndex, bufferIndex) where frameIndex is equal to
+ * input.ordinal.frameIndex and bufferIndex runs through the indices of
+ * input.buffers such that input.buffers[bufferIndex] is not null.
+ *
+ * This should be called from queue().
+ *
+ * \param listener Listener of death notifications.
+ * \param input Input frame data whose input buffers are to be tracked.
+ */
+ static void registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input);
+
+ /**
+ * Untrack all buffers in a C2FrameData object.
+ *
+ * Calling unregisterFrameData(listener, input) will unregister and remove
+ * pending notifications for all triples (l, fi, bufferIndex) such that
+ * l = listener and fi = input.ordinal.frameIndex.
+ *
+ * This should be called from onWorkDone() and flush().
+ *
+ * \param listener Previously registered listener.
+ * \param input Previously registered frame data.
+ */
+ static void unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input);
+
+ /**
+ * Untrack all buffers associated to a given listener.
+ *
+ * Calling unregisterFrameData(listener) will unregister and remove
+ * pending notifications for all triples (l, frameIndex, bufferIndex) such
+ * that l = listener.
+ *
+ * This should be called when the component cleans up all input buffers,
+ * i.e., when reset(), release(), stop() or ~Component() is called.
+ *
+ * \param listener Previously registered listener.
+ */
+ static void unregisterFrameData(
+ const wp<IComponentListener>& listener);
+
+ /**
+ * Set the notification interval.
+ *
+ * \param notificationIntervalNs New notification interval, in nanoseconds.
+ */
+ static void setNotificationInterval(nsecs_t notificationIntervalNs);
+
+private:
+ void _registerFrameData(
+ const sp<IComponentListener>& listener,
+ const C2FrameData& input);
+ void _unregisterFrameData(
+ const wp<IComponentListener>& listener,
+ const C2FrameData& input);
+ void _unregisterFrameData(
+ const wp<IComponentListener>& listener);
+ void _setNotificationInterval(nsecs_t notificationIntervalNs);
+
+ // The callback function tied to C2Buffer objects.
+ //
+ // Note: This function assumes that sInstance is the only instance of this
+ // class.
+ static void onBufferDestroyed(const C2Buffer* buf, void* arg);
+ void _onBufferDestroyed(const C2Buffer* buf, void* arg);
+
+ // Persistent data to be passed as "arg" in onBufferDestroyed().
+ // This is essentially the triple (listener, frameIndex, bufferIndex) plus a
+ // weak pointer to the C2Buffer object.
+ //
+ // Note that the "key" is bufferIndex according to operator<(). This is
+ // designed to work with TrackedBuffersMap defined below.
+ struct TrackedBuffer {
+ wp<IComponentListener> listener;
+ uint64_t frameIndex;
+ size_t bufferIndex;
+ std::weak_ptr<C2Buffer> buffer;
+ TrackedBuffer(const wp<IComponentListener>& listener,
+ uint64_t frameIndex,
+ size_t bufferIndex,
+ const std::shared_ptr<C2Buffer>& buffer)
+ : listener(listener),
+ frameIndex(frameIndex),
+ bufferIndex(bufferIndex),
+ buffer(buffer) {}
+ };
+
+ // Map: listener -> frameIndex -> set<TrackedBuffer*>.
+ // Essentially, this is used to store triples (listener, frameIndex,
+ // bufferIndex) that's searchable by listener and (listener, frameIndex).
+ // However, the value of the innermost map is TrackedBuffer, which also
+ // contains an extra copy of listener and frameIndex. This is needed
+ // because onBufferDestroyed() needs to know listener and frameIndex too.
+ typedef std::map<wp<IComponentListener>,
+ std::map<uint64_t,
+ std::set<TrackedBuffer*>>> TrackedBuffersMap;
+
+ // Storage for pending (unsent) death notifications for one listener.
+ // Each pair in member named "indices" are (frameIndex, bufferIndex) from
+ // the (listener, frameIndex, bufferIndex) triple.
+ struct DeathNotifications {
+
+ // The number of pending notifications for this listener.
+ // count may be 0, in which case the DeathNotifications object will
+ // remain valid for only a small period (specified
+ // nanoseconds).
+ size_t count;
+
+ // The timestamp of the most recent callback on this listener. This is
+ // used to guarantee that callbacks do not occur too frequently, and
+ // also to trigger expiration of a DeathNotifications object that has
+ // count = 0.
+ nsecs_t lastSentNs;
+
+ // Map: frameIndex -> vector of bufferIndices
+ // This is essentially a collection of (framdeIndex, bufferIndex).
+ std::map<uint64_t, std::vector<size_t>> indices;
+
+ DeathNotifications(
+ nsecs_t notificationIntervalNs = kDefaultNotificationIntervalNs)
+ : count(0),
+ lastSentNs(systemTime() - notificationIntervalNs),
+ indices() {}
+ };
+
+ // The minimum time period between IPC calls to notify the client about the
+ // destruction of input buffers.
+ std::atomic<nsecs_t> mNotificationIntervalNs{kDefaultNotificationIntervalNs};
+
+ // Mutex for the management of all input buffers.
+ std::mutex mMutex;
+
+ // Cache for all TrackedBuffers.
+ //
+ // Whenever registerOnDestroyNotify() is called, an argument of type
+ // TrackedBuffer is created and stored into this cache.
+ // Whenever unregisterOnDestroyNotify() or onBufferDestroyed() is called,
+ // the TrackedBuffer is removed from this cache.
+ //
+ // mTrackedBuffersMap stores references to TrackedBuffers inside this cache.
+ std::set<TrackedBuffer*> mTrackedBufferCache;
+
+ // Tracked input buffers.
+ TrackedBuffersMap mTrackedBuffersMap;
+
+ // Death notifications to be sent.
+ //
+ // A DeathNotifications object is associated to each listener. An entry in
+ // this map will be removed if its associated DeathNotifications has count =
+ // 0 and lastSentNs < systemTime() - mNotificationIntervalNs.
+ std::map<wp<IComponentListener>, DeathNotifications> mDeathNotifications;
+
+ // Condition variable signaled when an entry is added to mDeathNotifications.
+ std::condition_variable mOnBufferDestroyed;
+
+ // Notify the clients about buffer destructions.
+ // Return false if all destructions have been notified.
+ // Return true and set timeToRetry to the duration to wait for before
+ // retrying if some destructions have not been notified.
+ bool processNotifications(nsecs_t* timeToRetryNs);
+
+ // Main function for the input buffer manager thread.
+ void main();
+
+ // The thread that manages notifications.
+ //
+ // Note: This variable is declared last so its initialization will happen
+ // after all other member variables have been initialized.
+ std::thread mMainThread;
+
+ // Private constructor.
+ InputBufferManager();
+
+ // The only instance of this class.
+ static InputBufferManager& getInstance();
+
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_INPUT_BUFFER_MANAGER_H
+
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/InputSurface.h b/media/codec2/hal/aidl/include/codec2/aidl/InputSurface.h
new file mode 100644
index 0000000..062dcd9
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/InputSurface.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUTSURFACE_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUTSURFACE_H
+
+#include <codec2/hidl/1.0/ComponentStore.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <android/hardware/media/c2/1.0/IInputSink.h>
+#include <android/hardware/media/c2/1.0/IInputSurface.h>
+#include <hidl/Status.h>
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+
+#include <util/C2InterfaceHelper.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct InputSurface : public IInputSurface {
+
+ typedef ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer HGraphicBufferProducer;
+
+ typedef ::android::
+ GraphicBufferSource GraphicBufferSource;
+
+ virtual Return<sp<HGraphicBufferProducer>> getGraphicBufferProducer() override;
+
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+ virtual Return<void> connect(
+ const sp<IInputSink>& sink,
+ connect_cb _hidl_cb) override;
+
+ InputSurface(
+ const std::shared_ptr<ParameterCache>& cache,
+ const std::shared_ptr<C2ReflectorHelper>& reflector,
+ const sp<HGraphicBufferProducer>& base,
+ const sp<GraphicBufferSource>& source);
+
+protected:
+
+ class Interface;
+ class ConfigurableIntf;
+
+ std::shared_ptr<ParameterCache> mParameterCache;
+ sp<HGraphicBufferProducer> mProducer;
+ sp<GraphicBufferSource> mSource;
+ std::shared_ptr<Interface> mIntf;
+ sp<CachedConfigurable> mConfigurable;
+
+ virtual ~InputSurface() override = default;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_INPUTSURFACE_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/InputSurfaceConnection.h b/media/codec2/hal/aidl/include/codec2/aidl/InputSurfaceConnection.h
new file mode 100644
index 0000000..475ce8b
--- /dev/null
+++ b/media/codec2/hal/aidl/include/codec2/aidl/InputSurfaceConnection.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
+#define CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
+
+#include <codec2/hidl/1.0/Component.h>
+#include <codec2/hidl/1.0/Configurable.h>
+
+#include <android/hardware/media/c2/1.0/IComponent.h>
+#include <android/hardware/media/c2/1.0/IConfigurable.h>
+#include <android/hardware/media/c2/1.0/IInputSurfaceConnection.h>
+
+#include <media/stagefright/bqhelper/GraphicBufferSource.h>
+
+#include <hidl/HidlSupport.h>
+#include <hidl/Status.h>
+
+#include <C2Component.h>
+
+#include <memory>
+#include <mutex>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace c2 {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::GraphicBufferSource;
+
+// An InputSurfaceConnection connects an InputSurface to a sink, which may be an
+// IInputSink or a local C2Component. This can be specified by choosing the
+// corresponding constructor. The reason for distinguishing these two cases is
+// that when an InputSurfaceConnection lives in the same process as the
+// component that processes the buffers, data parceling is not needed.
+struct InputSurfaceConnection : public IInputSurfaceConnection {
+
+ virtual Return<Status> disconnect() override;
+
+ virtual Return<sp<IConfigurable>> getConfigurable() override;
+
+protected:
+
+ InputSurfaceConnection(
+ const sp<GraphicBufferSource>& source,
+ const std::shared_ptr<C2Component>& comp,
+ const std::shared_ptr<ParameterCache>& cache);
+
+ InputSurfaceConnection(
+ const sp<GraphicBufferSource>& source,
+ const sp<IInputSink>& sink,
+ const std::shared_ptr<ParameterCache>& cache);
+
+ bool init();
+
+ friend struct InputSurface;
+
+ InputSurfaceConnection() = delete;
+ InputSurfaceConnection(const InputSurfaceConnection&) = delete;
+ void operator=(const InputSurfaceConnection&) = delete;
+
+ struct Impl;
+
+ std::mutex mImplMutex;
+ sp<Impl> mImpl;
+ sp<CachedConfigurable> mConfigurable;
+
+ virtual ~InputSurfaceConnection() override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace c2
+} // namespace media
+} // namespace hardware
+} // namespace android
+
+#endif // CODEC2_HIDL_V1_0_UTILS_INPUTSURFACECONNECTION_H
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
index ff69039..3f82ee3 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ParamTypes.h
@@ -37,11 +37,14 @@
namespace c2 {
namespace utils {
+// Returns true iff AIDL c2 HAL is enabled
+bool IsEnabled();
+
// Make asString() and operator<< work with Status as well as c2_status_t.
C2_DECLARE_AS_STRING_AND_DEFINE_STREAM_OUT(Status);
/**
- * All objcpy() functions will return a boolean value indicating whether the
+ * All To/FromAidl() functions will return a boolean value indicating whether the
* conversion succeeds or not.
*/
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 61ec10e..22aa35e 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -42,6 +42,7 @@
"android.hardware.media.c2@1.0",
"android.hardware.media.c2@1.1",
"android.hardware.media.c2@1.2",
+ "android.hardware.media.bufferpool2-V1-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder",
@@ -56,11 +57,16 @@
"libhidlbase",
"liblog",
"libnativewindow",
+ "libstagefright_aidl_bufferpool2",
"libstagefright_bufferpool@2.0.1",
"libui",
"libutils",
],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+
export_include_dirs: [
"include",
],
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index b5cb546..b680931 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -25,7 +25,6 @@
#include <C2Config.h> // for C2StreamUsageTuning
#include <C2PlatformSupport.h>
-#include <android/binder_auto_utils.h>
#include <android/hardware/media/bufferpool/2.0/IClientManager.h>
#include <android/hardware/media/c2/1.0/IComponent.h>
#include <android/hardware/media/c2/1.0/IComponentInterface.h>
@@ -34,6 +33,8 @@
#include <android/hardware/media/c2/1.0/IConfigurable.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
+#include <aidl/android/hardware/media/c2/BnComponentListener.h>
#include <aidl/android/hardware/media/c2/FieldSupportedValues.h>
#include <aidl/android/hardware/media/c2/FieldSupportedValuesQuery.h>
#include <aidl/android/hardware/media/c2/FieldSupportedValuesQueryResult.h>
@@ -42,9 +43,17 @@
#include <aidl/android/hardware/media/c2/IComponentStore.h>
#include <aidl/android/hardware/media/c2/IConfigurable.h>
#include <aidl/android/hardware/media/c2/ParamDescriptor.h>
+#include <aidl/android/hardware/media/c2/StructDescriptor.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <bufferpool/ClientManager.h>
+#include <bufferpool2/ClientManager.h>
+#include <codec2/aidl/BufferTypes.h>
#include <codec2/aidl/ParamTypes.h>
#include <codec2/hidl/1.0/types.h>
#include <codec2/hidl/1.1/types.h>
@@ -86,6 +95,7 @@
V2_0::utils::H2BGraphicBufferProducer;
using ::android::hardware::media::c2::V1_2::SurfaceSyncObj;
+namespace bufferpool2_aidl = ::aidl::android::hardware::media::bufferpool2;
namespace bufferpool_hidl = ::android::hardware::media::bufferpool::V2_0;
namespace c2_aidl = ::aidl::android::hardware::media::c2;
namespace c2_hidl_base = ::android::hardware::media::c2;
@@ -179,6 +189,20 @@
}
};
+c2_status_t GetC2Status(const ::ndk::ScopedAStatus &transStatus, const char *method) {
+ if (!transStatus.isOk()) {
+ if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
+ LOG(DEBUG) << method << " -- call failed: " << status << ".";
+ return status;
+ } else {
+ LOG(ERROR) << method << " -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
+ }
+ return C2_OK;
+}
+
} // unnamed namespace
// This class caches a Codec2Client object and its component traits. The client
@@ -606,18 +630,11 @@
}
c2_aidl::Params result;
ndk::ScopedAStatus transStatus = mBase->query(indices, (mayBlock == C2_MAY_BLOCK), &result);
- if (!transStatus.isOk()) {
- if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
- c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
- LOG(DEBUG) << "query -- call failed: " << status << ".";
- return status;
- } else {
- LOG(ERROR) << "query -- transaction failed.";
- return C2_TRANSACTION_FAILED;
- }
+ c2_status_t status = GetC2Status(transStatus, "query");
+ if (status != C2_OK) {
+ return status;
}
- c2_status_t status = C2_OK;
std::vector<C2Param*> paramPointers;
if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, result)) {
LOG(ERROR) << "query -- error while parsing params.";
@@ -686,17 +703,10 @@
}
c2_aidl::IConfigurable::ConfigResult result;
ndk::ScopedAStatus transStatus = mBase->config(aidlParams, (mayBlock == C2_MAY_BLOCK), &result);
- if (!transStatus.isOk()) {
- if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
- c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
- LOG(DEBUG) << "config -- call failed: " << status << ".";
- return status;
- } else {
- LOG(ERROR) << "config -- transaction failed.";
- return C2_TRANSACTION_FAILED;
- }
+ c2_status_t status = GetC2Status(transStatus, "config");
+ if (status != C2_OK) {
+ return status;
}
- c2_status_t status = C2_OK;
size_t i = failures->size();
failures->resize(i + result.failures.size());
for (const c2_aidl::SettingResult& sf : result.failures) {
@@ -721,17 +731,10 @@
std::numeric_limits<uint32_t>::min(),
std::numeric_limits<uint32_t>::max(),
&result);
- if (!transStatus.isOk()) {
- if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
- c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
- LOG(DEBUG) << "querySupportedParams -- call failed: " << status << ".";
- return status;
- } else {
- LOG(ERROR) << "querySupportedParams -- transaction failed.";
- return C2_TRANSACTION_FAILED;
- }
+ c2_status_t status = GetC2Status(transStatus, "querySupportedParams");
+ if (status != C2_OK) {
+ return status;
}
- c2_status_t status = C2_OK;
size_t i = params->size();
params->resize(i + result.size());
for (const c2_aidl::ParamDescriptor& sp : result) {
@@ -757,17 +760,10 @@
std::vector<c2_aidl::FieldSupportedValuesQueryResult> result;
ndk::ScopedAStatus transStatus = mBase->querySupportedValues(
inFields, (mayBlock == C2_MAY_BLOCK), &result);
- if (!transStatus.isOk()) {
- if (transStatus.getExceptionCode() == EX_SERVICE_SPECIFIC) {
- c2_status_t status = static_cast<c2_status_t>(transStatus.getServiceSpecificError());
- LOG(DEBUG) << "querySupportedValues -- call failed: " << status << ".";
- return status;
- } else {
- LOG(ERROR) << "querySupportedValues -- transaction failed.";
- return C2_TRANSACTION_FAILED;
- }
+ c2_status_t status = GetC2Status(transStatus, "querySupportedValues");
+ if (status != C2_OK) {
+ return status;
}
- c2_status_t status = C2_OK;
if (result.size() != fields.size()) {
LOG(ERROR) << "querySupportedValues -- "
"input and output lists "
@@ -923,14 +919,119 @@
};
-// Codec2Client::Component::BufferPoolSender
-struct Codec2Client::Component::BufferPoolSender :
+// Codec2Client::Component::AidlListener
+struct Codec2Client::Component::AidlListener : public c2_aidl::BnComponentListener {
+ std::weak_ptr<Component> component;
+ std::weak_ptr<Listener> base;
+
+ virtual ::ndk::ScopedAStatus onWorkDone(const c2_aidl::WorkBundle& workBundle) override {
+ std::list<std::unique_ptr<C2Work>> workItems;
+ if (!c2_aidl::utils::FromAidl(&workItems, workBundle)) {
+ LOG(DEBUG) << "onWorkDone -- received corrupted WorkBundle.";
+ return ::ndk::ScopedAStatus::ok();
+ }
+ // release input buffers potentially held by the component from queue
+ std::shared_ptr<Codec2Client::Component> strongComponent =
+ component.lock();
+ if (strongComponent) {
+ strongComponent->handleOnWorkDone(workItems);
+ }
+ if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
+ listener->onWorkDone(component, workItems);
+ } else {
+ LOG(DEBUG) << "onWorkDone -- listener died.";
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ virtual ::ndk::ScopedAStatus onTripped(
+ const std::vector<c2_aidl::SettingResult>& settingResults) override {
+ std::vector<std::shared_ptr<C2SettingResult>> c2SettingResults(
+ settingResults.size());
+ for (size_t i = 0; i < settingResults.size(); ++i) {
+ std::unique_ptr<C2SettingResult> c2SettingResult;
+ if (!c2_aidl::utils::FromAidl(&c2SettingResult, settingResults[i])) {
+ LOG(DEBUG) << "onTripped -- received corrupted SettingResult.";
+ return ::ndk::ScopedAStatus::ok();
+ }
+ c2SettingResults[i] = std::move(c2SettingResult);
+ }
+ if (std::shared_ptr<Codec2Client::Listener> listener = base.lock()) {
+ listener->onTripped(component, c2SettingResults);
+ } else {
+ LOG(DEBUG) << "onTripped -- listener died.";
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ virtual ::ndk::ScopedAStatus onError(const c2_aidl::Status &s, int32_t errorCode) override {
+ LOG(DEBUG) << "onError --"
+ << " status = " << s.status
+ << ", errorCode = " << errorCode
+ << ".";
+ if (std::shared_ptr<Listener> listener = base.lock()) {
+ listener->onError(component, s.status == c2_aidl::Status::OK ?
+ errorCode : static_cast<c2_status_t>(s.status));
+ } else {
+ LOG(DEBUG) << "onError -- listener died.";
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ virtual ::ndk::ScopedAStatus onFramesRendered(
+ const std::vector<RenderedFrame>& renderedFrames) override {
+ std::shared_ptr<Listener> listener = base.lock();
+ if (!listener) {
+ LOG(DEBUG) << "onFramesRendered -- listener died.";
+ return ::ndk::ScopedAStatus::ok();
+ }
+ for (const RenderedFrame& renderedFrame : renderedFrames) {
+ listener->onFrameRendered(
+ renderedFrame.bufferQueueId,
+ renderedFrame.slotId,
+ renderedFrame.timestampNs);
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+ virtual ::ndk::ScopedAStatus onInputBuffersReleased(
+ const std::vector<InputBuffer>& inputBuffers) override {
+ std::shared_ptr<Listener> listener = base.lock();
+ if (!listener) {
+ LOG(DEBUG) << "onInputBuffersReleased -- listener died.";
+ return ::ndk::ScopedAStatus::ok();
+ }
+ for (const InputBuffer& inputBuffer : inputBuffers) {
+ LOG(VERBOSE) << "onInputBuffersReleased --"
+ " received death notification of"
+ " input buffer:"
+ " frameIndex = " << inputBuffer.frameIndex
+ << ", bufferIndex = " << inputBuffer.arrayIndex
+ << ".";
+ listener->onInputBufferDone(
+ inputBuffer.frameIndex, inputBuffer.arrayIndex);
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+
+};
+
+// Codec2Client::Component::HidlBufferPoolSender
+struct Codec2Client::Component::HidlBufferPoolSender :
hardware::media::c2::V1_1::utils::DefaultBufferPoolSender {
- BufferPoolSender()
+ HidlBufferPoolSender()
: hardware::media::c2::V1_1::utils::DefaultBufferPoolSender() {
}
};
+// Codec2Client::Component::AidlBufferPoolSender
+struct Codec2Client::Component::AidlBufferPoolSender :
+ c2_aidl::utils::DefaultBufferPoolSender {
+ AidlBufferPoolSender()
+ : c2_aidl::utils::DefaultBufferPoolSender() {
+ }
+};
+
// Codec2Client::Component::OutputBufferQueue
struct Codec2Client::Component::OutputBufferQueue :
hardware::media::c2::OutputBufferQueue {
@@ -940,36 +1041,53 @@
};
// Codec2Client
-Codec2Client::Codec2Client(sp<Base> const& base,
+Codec2Client::Codec2Client(sp<HidlBase> const& base,
sp<c2_hidl::IConfigurable> const& configurable,
size_t serviceIndex)
: Configurable{configurable},
- mBase1_0{base},
- mBase1_1{Base1_1::castFrom(base)},
- mBase1_2{Base1_2::castFrom(base)},
+ mHidlBase1_0{base},
+ mHidlBase1_1{HidlBase1_1::castFrom(base)},
+ mHidlBase1_2{HidlBase1_2::castFrom(base)},
mServiceIndex{serviceIndex} {
Return<sp<bufferpool_hidl::IClientManager>> transResult = base->getPoolClientManager();
if (!transResult.isOk()) {
LOG(ERROR) << "getPoolClientManager -- transaction failed.";
} else {
- mHostPoolManager = static_cast<sp<bufferpool_hidl::IClientManager>>(transResult);
+ mHidlHostPoolManager = static_cast<sp<bufferpool_hidl::IClientManager>>(transResult);
}
}
-sp<Codec2Client::Base> const& Codec2Client::getBase() const {
- return mBase1_0;
+Codec2Client::Codec2Client(std::shared_ptr<AidlBase> const& base,
+ std::shared_ptr<c2_aidl::IConfigurable> const& configurable,
+ size_t serviceIndex)
+ : Configurable{configurable},
+ mAidlBase{base},
+ mServiceIndex{serviceIndex} {
+ ::ndk::ScopedAStatus transStatus = base->getPoolClientManager(&mAidlHostPoolManager);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "getPoolClientManager -- transaction failed.";
+ mAidlHostPoolManager.reset();
+ }
}
-sp<Codec2Client::Base1_0> const& Codec2Client::getBase1_0() const {
- return mBase1_0;
+sp<Codec2Client::HidlBase> const& Codec2Client::getHidlBase() const {
+ return mHidlBase1_0;
}
-sp<Codec2Client::Base1_1> const& Codec2Client::getBase1_1() const {
- return mBase1_1;
+sp<Codec2Client::HidlBase1_0> const& Codec2Client::getHidlBase1_0() const {
+ return mHidlBase1_0;
}
-sp<Codec2Client::Base1_2> const& Codec2Client::getBase1_2() const {
- return mBase1_2;
+sp<Codec2Client::HidlBase1_1> const& Codec2Client::getHidlBase1_1() const {
+ return mHidlBase1_1;
+}
+
+sp<Codec2Client::HidlBase1_2> const& Codec2Client::getHidlBase1_2() const {
+ return mHidlBase1_2;
+}
+
+::ndk::SpAIBinder Codec2Client::getAidlBase() const {
+ return mAidlBase ? mAidlBase->asBinder() : nullptr;
}
std::string const& Codec2Client::getServiceName() const {
@@ -980,13 +1098,41 @@
const C2String& name,
const std::shared_ptr<Codec2Client::Listener>& listener,
std::shared_ptr<Codec2Client::Component>* const component) {
+ if (mAidlBase) {
+ std::shared_ptr<Component::AidlListener> aidlListener =
+ Component::AidlListener::make<Component::AidlListener>();
+ aidlListener->base = listener;
+ std::shared_ptr<c2_aidl::IComponent> aidlComponent;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->createComponent(
+ name,
+ aidlListener,
+ bufferpool2_aidl::implementation::ClientManager::getInstance(),
+ &aidlComponent);
+ c2_status_t status = GetC2Status(transStatus, "createComponent");
+ if (status != C2_OK) {
+ return status;
+ } else if (!aidlComponent) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- null component.";
+ return C2_CORRUPTED;
+ }
+ *component = std::make_shared<Codec2Client::Component>(aidlComponent);
+ status = (*component)->setDeathListener((*component), listener);
+ if (status != C2_OK) {
+ LOG(ERROR) << "createComponent(" << name.c_str()
+ << ") -- failed to set up death listener: "
+ << status << ".";
+ }
+ (*component)->mAidlBufferPoolSender->setReceiver(mAidlHostPoolManager);
+ return status;
+ }
c2_status_t status;
sp<Component::HidlListener> hidlListener = new Component::HidlListener{};
hidlListener->base = listener;
Return<void> transStatus;
- if (mBase1_2) {
- transStatus = mBase1_2->createComponent_1_2(
+ if (mHidlBase1_2) {
+ transStatus = mHidlBase1_2->createComponent_1_2(
name,
hidlListener,
bufferpool_hidl::implementation::ClientManager::getInstance(),
@@ -1001,8 +1147,8 @@
hidlListener->component = *component;
});
}
- else if (mBase1_1) {
- transStatus = mBase1_1->createComponent_1_1(
+ else if (mHidlBase1_1) {
+ transStatus = mHidlBase1_1->createComponent_1_1(
name,
hidlListener,
bufferpool_hidl::implementation::ClientManager::getInstance(),
@@ -1016,8 +1162,8 @@
*component = std::make_shared<Codec2Client::Component>(c);
hidlListener->component = *component;
});
- } else if (mBase1_0) { // ver1_0
- transStatus = mBase1_0->createComponent(
+ } else if (mHidlBase1_0) { // ver1_0
+ transStatus = mHidlBase1_0->createComponent(
name,
hidlListener,
bufferpool_hidl::implementation::ClientManager::getInstance(),
@@ -1060,15 +1206,32 @@
<< status << ".";
}
- (*component)->mBufferPoolSender->setReceiver(mHostPoolManager);
+ (*component)->mHidlBufferPoolSender->setReceiver(mHidlHostPoolManager);
return status;
}
c2_status_t Codec2Client::createInterface(
const C2String& name,
std::shared_ptr<Codec2Client::Interface>* const interface) {
+ if (mAidlBase) {
+ std::shared_ptr<c2_aidl::IComponentInterface> aidlInterface;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->createInterface(
+ name,
+ &aidlInterface);
+ c2_status_t status = GetC2Status(transStatus, "createInterface");
+ if (status != C2_OK) {
+ return status;
+ } else if (!aidlInterface) {
+ LOG(ERROR) << "createInterface(" << name.c_str()
+ << ") -- null interface.";
+ return C2_CORRUPTED;
+ }
+ interface->reset(new Codec2Client::Interface(aidlInterface));
+ return C2_OK;
+ }
+
c2_status_t status;
- Return<void> transStatus = mBase1_0->createInterface(
+ Return<void> transStatus = mHidlBase1_0->createInterface(
name,
[&status, interface](
c2_hidl::Status s,
@@ -1099,8 +1262,13 @@
c2_status_t Codec2Client::createInputSurface(
std::shared_ptr<InputSurface>* const inputSurface) {
+ if (mAidlBase) {
+ // FIXME
+ return C2_OMITTED;
+ }
+
c2_status_t status;
- Return<void> transStatus = mBase1_0->createInputSurface(
+ Return<void> transStatus = mHidlBase1_0->createInputSurface(
[&status, inputSurface](
c2_hidl::Status s,
const sp<c2_hidl::IInputSurface>& i) {
@@ -1128,7 +1296,29 @@
bool* success) const {
std::vector<C2Component::Traits> traits;
std::string const& serviceName = getServiceName();
- Return<void> transStatus = mBase1_0->listComponents(
+
+ if (mAidlBase) {
+ std::vector<c2_aidl::IComponentStore::ComponentTraits> aidlTraits;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->listComponents(&aidlTraits);
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "_listComponents -- transaction failed.";
+ *success = false;
+ } else {
+ traits.resize(aidlTraits.size());
+ *success = true;
+ for (size_t i = 0; i < aidlTraits.size(); ++i) {
+ if (!c2_aidl::utils::FromAidl(&traits[i], aidlTraits[i])) {
+ LOG(ERROR) << "_listComponents -- corrupted output.";
+ *success = false;
+ traits.clear();
+ break;
+ }
+ traits[i].owner = serviceName;
+ }
+ }
+ return traits;
+ }
+ Return<void> transStatus = mHidlBase1_0->listComponents(
[&traits, &serviceName](c2_hidl::Status s,
const hidl_vec<c2_hidl::IComponentStore::ComponentTraits>& t) {
if (s != c2_hidl::Status::OK) {
@@ -1164,12 +1354,12 @@
return C2_OMITTED;
}
-std::shared_ptr<C2ParamReflector>
- Codec2Client::getParamReflector() {
+std::shared_ptr<C2ParamReflector> 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<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) const {
+ struct HidlSimpleParamReflector : public C2ParamReflector {
+ std::unique_ptr<C2StructDescriptor> describe(
+ C2Param::CoreIndex coreIndex) const override {
hidl_vec<c2_hidl::ParamIndex> indices(1);
indices[0] = static_cast<c2_hidl::ParamIndex>(coreIndex.coreIndex());
std::unique_ptr<C2StructDescriptor> descriptor;
@@ -1211,80 +1401,112 @@
return descriptor;
}
- SimpleParamReflector(sp<Base> base)
+ HidlSimpleParamReflector(sp<HidlBase> base)
: mBase(base) { }
- sp<Base> mBase;
+ sp<HidlBase> mBase;
+ };
+ struct AidlSimpleParamReflector : public C2ParamReflector {
+ std::unique_ptr<C2StructDescriptor> describe(
+ C2Param::CoreIndex coreIndex) const override {
+ std::vector<c2_aidl::StructDescriptor> aidlDesc;
+ std::unique_ptr<C2StructDescriptor> descriptor;
+ ::ndk::ScopedAStatus transStatus = mBase->getStructDescriptors(
+ {int32_t(coreIndex.coreIndex())},
+ &aidlDesc);
+ c2_status_t status = GetC2Status(transStatus, "describe");
+ if (status != C2_OK) {
+ descriptor.reset();
+ } else if (!c2_aidl::utils::FromAidl(&descriptor, aidlDesc[0])) {
+ LOG(ERROR) << "describe -- conversion failed.";
+ descriptor.reset();
+ }
+ return descriptor;
+ }
+
+ AidlSimpleParamReflector(const std::shared_ptr<AidlBase> &base)
+ : mBase(base) { }
+
+ std::shared_ptr<AidlBase> mBase;
};
- return std::make_shared<SimpleParamReflector>(mBase1_0);
+ if (mAidlBase) {
+ return std::make_shared<AidlSimpleParamReflector>(mAidlBase);
+ }
+ return std::make_shared<HidlSimpleParamReflector>(mHidlBase1_0);
};
-std::vector<std::string> const& Codec2Client::GetServiceNames() {
- static std::vector<std::string> sServiceNames{[]() {
- using ::android::hardware::media::c2::V1_0::IComponentStore;
- using ::android::hidl::manager::V1_2::IServiceManager;
+std::vector<std::string> Codec2Client::CacheServiceNames() {
+ std::vector<std::string> names;
- while (true) {
- sp<IServiceManager> serviceManager = IServiceManager::getService();
- CHECK(serviceManager) << "Hardware service manager is not running.";
+ if (c2_aidl::utils::IsEnabled()) {
+ // Get AIDL service names
+ AServiceManager_forEachDeclaredInstance(
+ AidlBase::descriptor, &names, [](const char *name, void *context) {
+ std::vector<std::string> *names = (std::vector<std::string> *)context;
+ names->emplace_back(name);
+ });
+ }
- // There are three categories of services based on names.
- std::vector<std::string> defaultNames; // Prefixed with "default"
- std::vector<std::string> vendorNames; // Prefixed with "vendor"
- std::vector<std::string> otherNames; // Others
- Return<void> transResult;
- transResult = serviceManager->listManifestByInterface(
- IComponentStore::descriptor,
- [&defaultNames, &vendorNames, &otherNames](
- hidl_vec<hidl_string> const& instanceNames) {
- for (hidl_string const& instanceName : instanceNames) {
- char const* name = instanceName.c_str();
- if (strncmp(name, "default", 7) == 0) {
- defaultNames.emplace_back(name);
- } else if (strncmp(name, "vendor", 6) == 0) {
- vendorNames.emplace_back(name);
- } else {
- otherNames.emplace_back(name);
- }
- }
- });
- if (transResult.isOk()) {
- // Sort service names in each category.
- std::sort(defaultNames.begin(), defaultNames.end());
- std::sort(vendorNames.begin(), vendorNames.end());
- std::sort(otherNames.begin(), otherNames.end());
+ // Get HIDL service names
+ using ::android::hardware::media::c2::V1_0::IComponentStore;
+ using ::android::hidl::manager::V1_2::IServiceManager;
+ while (true) {
+ sp<IServiceManager> serviceManager = IServiceManager::getService();
+ CHECK(serviceManager) << "Hardware service manager is not running.";
- // Concatenate the three lists in this order: default, vendor,
- // other.
- std::vector<std::string>& names = defaultNames;
- names.reserve(names.size() + vendorNames.size() + otherNames.size());
- names.insert(names.end(),
- std::make_move_iterator(vendorNames.begin()),
- std::make_move_iterator(vendorNames.end()));
- names.insert(names.end(),
- std::make_move_iterator(otherNames.begin()),
- std::make_move_iterator(otherNames.end()));
-
- // Summarize to logcat.
- if (names.empty()) {
- LOG(INFO) << "No Codec2 services declared in the manifest.";
- } else {
- std::stringstream stringOutput;
- stringOutput << "Available Codec2 services:";
- for (std::string const& name : names) {
- stringOutput << " \"" << name << "\"";
- }
- LOG(INFO) << stringOutput.str();
- }
-
- return names;
- }
- LOG(ERROR) << "Could not retrieve the list of service instances of "
- << IComponentStore::descriptor
- << ". Retrying...";
+ Return<void> transResult;
+ transResult = serviceManager->listManifestByInterface(
+ IComponentStore::descriptor,
+ [&names](
+ hidl_vec<hidl_string> const& instanceNames) {
+ names.insert(names.end(), instanceNames.begin(), instanceNames.end());
+ });
+ if (transResult.isOk()) {
+ break;
}
- }()};
+ LOG(ERROR) << "Could not retrieve the list of service instances of "
+ << IComponentStore::descriptor
+ << ". Retrying...";
+ }
+ // Sort service names in each category.
+ std::stable_sort(
+ names.begin(), names.end(),
+ [](const std::string &a, const std::string &b) {
+ // First compare by prefix: default -> vendor -> {everything else}
+ constexpr int DEFAULT = 1;
+ constexpr int VENDOR = 2;
+ constexpr int OTHER = 3;
+ int aPrefix = ((a.compare(0, 7, "default") == 0) ? DEFAULT :
+ (a.compare(0, 6, "vendor") == 0) ? VENDOR :
+ OTHER);
+ int bPrefix = ((b.compare(0, 7, "default") == 0) ? DEFAULT :
+ (b.compare(0, 6, "vendor") == 0) ? VENDOR :
+ OTHER);
+ if (aPrefix != bPrefix) {
+ return aPrefix < bPrefix;
+ }
+ // If the prefix is the same, compare alphabetically
+ return a < b;
+ });
+
+ // Summarize to logcat.
+ if (names.empty()) {
+ LOG(INFO) << "No Codec2 services declared in the manifest.";
+ } else {
+ std::stringstream stringOutput;
+ stringOutput << "Available Codec2 services:";
+ for (std::string const& name : names) {
+ stringOutput << " \"" << name << "\"";
+ }
+ LOG(INFO) << stringOutput.str();
+ }
+
+ return names;
+}
+
+std::vector<std::string> const& Codec2Client::GetServiceNames() {
+ static std::vector<std::string> sServiceNames = CacheServiceNames();
return sServiceNames;
}
@@ -1323,14 +1545,34 @@
std::shared_ptr<Codec2Client> Codec2Client::_CreateFromIndex(size_t index) {
std::string const& name = GetServiceNames()[index];
LOG(VERBOSE) << "Creating a Codec2 client to service \"" << name << "\"";
- sp<Base> baseStore = Base::getService(name);
+
+ if (c2_aidl::utils::IsEnabled()) {
+ std::string instanceName =
+ ::android::base::StringPrintf("%s/%s", AidlBase::descriptor, name.c_str());
+ if (AServiceManager_isDeclared(instanceName.c_str())) {
+ std::shared_ptr<AidlBase> baseStore = AidlBase::fromBinder(
+ ::ndk::SpAIBinder(AServiceManager_waitForService(instanceName.c_str())));
+ CHECK(baseStore) << "Codec2 AIDL service \"" << name << "\""
+ " inaccessible for unknown reasons.";
+ LOG(VERBOSE) << "Client to Codec2 AIDL service \"" << name << "\" created";
+ std::shared_ptr<c2_aidl::IConfigurable> configurable;
+ ::ndk::ScopedAStatus transStatus = baseStore->getConfigurable(&configurable);
+ CHECK(transStatus.isOk()) << "Codec2 AIDL service \"" << name << "\""
+ "does not have IConfigurable.";
+ return std::make_shared<Codec2Client>(baseStore, configurable, index);
+ }
+ }
+
+ std::string instanceName = "android.hardware.media.c2/" + name;
+ sp<HidlBase> baseStore = HidlBase::getService(name);
CHECK(baseStore) << "Codec2 service \"" << name << "\""
" inaccessible for unknown reasons.";
LOG(VERBOSE) << "Client to Codec2 service \"" << name << "\" created";
- Return<sp<IConfigurable>> transResult = baseStore->getConfigurable();
+ Return<sp<c2_hidl::IConfigurable>> transResult = baseStore->getConfigurable();
CHECK(transResult.isOk()) << "Codec2 service \"" << name << "\""
"does not have IConfigurable.";
- sp<IConfigurable> configurable = static_cast<sp<IConfigurable>>(transResult);
+ sp<c2_hidl::IConfigurable> configurable =
+ static_cast<sp<c2_hidl::IConfigurable>>(transResult);
return std::make_shared<Codec2Client>(baseStore, configurable, index);
}
@@ -1432,8 +1674,7 @@
return status;
}
-std::shared_ptr<Codec2Client::Interface>
- Codec2Client::CreateInterfaceByName(
+std::shared_ptr<Codec2Client::Interface> Codec2Client::CreateInterfaceByName(
const char* interfaceName,
std::shared_ptr<Codec2Client>* owner,
size_t numberOfAttempts) {
@@ -1519,13 +1760,8 @@
return nullptr;
}
-// Codec2Client::Listener
-
-Codec2Client::Listener::~Listener() {
-}
-
// Codec2Client::Interface
-Codec2Client::Interface::Interface(const sp<Base>& base)
+Codec2Client::Interface::Interface(const sp<HidlBase>& base)
: Configurable{
[base]() -> sp<c2_hidl::IConfigurable> {
Return<sp<c2_hidl::IConfigurable>> transResult =
@@ -1535,11 +1771,91 @@
nullptr;
}()
},
- mBase{base} {
+ mHidlBase{base} {
+}
+
+Codec2Client::Interface::Interface(const std::shared_ptr<AidlBase>& base)
+ : Configurable{
+ [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
+ std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
+ ::ndk::ScopedAStatus transStatus =
+ base->getConfigurable(&aidlConfigurable);
+ return transStatus.isOk() ? aidlConfigurable : nullptr;
+ }()
+ },
+ mAidlBase{base} {
}
// Codec2Client::Component
-Codec2Client::Component::Component(const sp<Base>& base)
+
+class Codec2Client::Component::AidlDeathManager {
+public:
+ AidlDeathManager()
+ : mSeq(0),
+ mDeathRecipient(AIBinder_DeathRecipient_new(OnBinderDied)) {
+ }
+
+ ~AidlDeathManager() = default;
+
+ bool linkToDeath(
+ const std::shared_ptr<Component> &comp,
+ const std::shared_ptr<Listener> &listener,
+ size_t *seqPtr) {
+ std::unique_lock lock(mMutex);
+ size_t seq = mSeq++;
+ if (!mMap.try_emplace(seq, comp, listener).second) {
+ return false;
+ }
+ if (STATUS_OK != AIBinder_linkToDeath(
+ comp->mAidlBase->asBinder().get(), mDeathRecipient.get(), (void *)seq)) {
+ mMap.erase(seq);
+ return false;
+ }
+ *seqPtr = seq;
+ return true;
+ }
+
+ void unlinkToDeath(size_t seq, const std::shared_ptr<AidlBase> &base) {
+ std::unique_lock lock(mMutex);
+ AIBinder_unlinkToDeath(base->asBinder().get(), mDeathRecipient.get(), (void *)seq);
+ mMap.erase(seq);
+ }
+
+private:
+ std::mutex mMutex;
+ size_t mSeq;
+ typedef std::tuple<std::weak_ptr<Component>, std::weak_ptr<Listener>> Context;
+ std::map<size_t, Context> mMap;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ bool extractContext(size_t seq, Context *context) {
+ std::unique_lock lock(mMutex);
+ auto node = mMap.extract(seq);
+ if (!node) {
+ return false;
+ }
+ *context = node.mapped();
+ return true;
+ }
+
+ static void OnBinderDied(void *cookie) {
+ size_t seq = size_t(cookie);
+ Context context;
+ if (!Component::GetAidlDeathManager()->extractContext(seq, &context)) {
+ return;
+ }
+ std::weak_ptr<Component> weakComponent;
+ std::weak_ptr<Listener> weakListener;
+ std::tie(weakComponent, weakListener) = context;
+ if (std::shared_ptr<Listener> listener = weakListener.lock()) {
+ listener->onDeath(weakComponent);
+ } else {
+ LOG(DEBUG) << "onDeath -- listener died.";
+ }
+ }
+};
+
+Codec2Client::Component::Component(const sp<HidlBase>& base)
: Configurable{
[base]() -> sp<c2_hidl::IConfigurable> {
Return<sp<c2_hidl::IComponentInterface>> transResult1 =
@@ -1555,14 +1871,14 @@
nullptr;
}()
},
- mBase1_0{base},
- mBase1_1{Base1_1::castFrom(base)},
- mBase1_2{Base1_2::castFrom(base)},
- mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+ mHidlBase1_0{base},
+ mHidlBase1_1{HidlBase1_1::castFrom(base)},
+ mHidlBase1_2{HidlBase1_2::castFrom(base)},
+ mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
}
-Codec2Client::Component::Component(const sp<Base1_1>& base)
+Codec2Client::Component::Component(const sp<HidlBase1_1>& base)
: Configurable{
[base]() -> sp<c2_hidl::IConfigurable> {
Return<sp<c2_hidl::IComponentInterface>> transResult1 =
@@ -1578,14 +1894,14 @@
nullptr;
}()
},
- mBase1_0{base},
- mBase1_1{base},
- mBase1_2{Base1_2::castFrom(base)},
- mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+ mHidlBase1_0{base},
+ mHidlBase1_1{base},
+ mHidlBase1_2{HidlBase1_2::castFrom(base)},
+ mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
}
-Codec2Client::Component::Component(const sp<Base1_2>& base)
+Codec2Client::Component::Component(const sp<HidlBase1_2>& base)
: Configurable{
[base]() -> sp<c2_hidl::IConfigurable> {
Return<sp<c2_hidl::IComponentInterface>> transResult1 =
@@ -1601,22 +1917,54 @@
nullptr;
}()
},
- mBase1_0{base},
- mBase1_1{base},
- mBase1_2{base},
- mBufferPoolSender{std::make_unique<BufferPoolSender>()},
+ mHidlBase1_0{base},
+ mHidlBase1_1{base},
+ mHidlBase1_2{base},
+ mHidlBufferPoolSender{std::make_unique<HidlBufferPoolSender>()},
+ mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
+}
+
+Codec2Client::Component::Component(const std::shared_ptr<AidlBase> &base)
+ : Configurable{
+ [base]() -> std::shared_ptr<c2_aidl::IConfigurable> {
+ std::shared_ptr<c2_aidl::IComponentInterface> aidlIntf;
+ ::ndk::ScopedAStatus transStatus = base->getInterface(&aidlIntf);
+ if (!transStatus.isOk()) {
+ return nullptr;
+ }
+ std::shared_ptr<c2_aidl::IConfigurable> aidlConfigurable;
+ transStatus = aidlIntf->getConfigurable(&aidlConfigurable);
+ return transStatus.isOk() ? aidlConfigurable : nullptr;
+ }()
+ },
+ mAidlBase{base},
+ mAidlBufferPoolSender{std::make_unique<AidlBufferPoolSender>()},
mOutputBufferQueue{std::make_unique<OutputBufferQueue>()} {
}
Codec2Client::Component::~Component() {
+ if (mAidlDeathSeq) {
+ GetAidlDeathManager()->unlinkToDeath(*mAidlDeathSeq, mAidlBase);
+ }
}
c2_status_t Codec2Client::Component::createBlockPool(
C2Allocator::id_t id,
C2BlockPool::local_id_t* blockPoolId,
std::shared_ptr<Codec2Client::Configurable>* configurable) {
+ if (mAidlBase) {
+ c2_aidl::IComponent::BlockPool aidlBlockPool;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(id, &aidlBlockPool);
+ c2_status_t status = GetC2Status(transStatus, "createBlockPool");
+ if (status != C2_OK) {
+ return status;
+ }
+ *blockPoolId = aidlBlockPool.blockPoolId;
+ *configurable = std::make_shared<Configurable>(aidlBlockPool.configurable);
+ return C2_OK;
+ }
c2_status_t status;
- Return<void> transStatus = mBase1_0->createBlockPool(
+ Return<void> transStatus = mHidlBase1_0->createBlockPool(
static_cast<uint32_t>(id),
[&status, blockPoolId, configurable](
c2_hidl::Status s,
@@ -1641,7 +1989,11 @@
c2_status_t Codec2Client::Component::destroyBlockPool(
C2BlockPool::local_id_t localId) {
- Return<c2_hidl::Status> transResult = mBase1_0->destroyBlockPool(
+ if (mAidlBase) {
+ ::ndk::ScopedAStatus transStatus = mAidlBase->destroyBlockPool(localId);
+ return GetC2Status(transStatus, "destroyBlockPool");
+ }
+ Return<c2_hidl::Status> transResult = mHidlBase1_0->destroyBlockPool(
static_cast<uint64_t>(localId));
if (!transResult.isOk()) {
LOG(ERROR) << "destroyBlockPool -- transaction failed.";
@@ -1658,12 +2010,21 @@
c2_status_t Codec2Client::Component::queue(
std::list<std::unique_ptr<C2Work>>* const items) {
+ if (mAidlBase) {
+ c2_aidl::WorkBundle workBundle;
+ if (!c2_aidl::utils::ToAidl(&workBundle, *items, mAidlBufferPoolSender.get())) {
+ LOG(ERROR) << "queue -- bad input.";
+ return C2_TRANSACTION_FAILED;
+ }
+ ::ndk::ScopedAStatus transStatus = mAidlBase->queue(workBundle);
+ return GetC2Status(transStatus, "queue");
+ }
c2_hidl::WorkBundle workBundle;
- if (!objcpy(&workBundle, *items, mBufferPoolSender.get())) {
+ if (!c2_hidl::utils::objcpy(&workBundle, *items, mHidlBufferPoolSender.get())) {
LOG(ERROR) << "queue -- bad input.";
return C2_TRANSACTION_FAILED;
}
- Return<c2_hidl::Status> transStatus = mBase1_0->queue(workBundle);
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->queue(workBundle);
if (!transStatus.isOk()) {
LOG(ERROR) << "queue -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1679,25 +2040,38 @@
c2_status_t Codec2Client::Component::flush(
C2Component::flush_mode_t mode,
std::list<std::unique_ptr<C2Work>>* const flushedWork) {
- (void)mode; // Flush mode isn't supported in HIDL yet.
- c2_status_t status;
- Return<void> transStatus = mBase1_0->flush(
- [&status, flushedWork](
- c2_hidl::Status s, const c2_hidl::WorkBundle& wb) {
- status = static_cast<c2_status_t>(s);
- if (status != C2_OK) {
- LOG(DEBUG) << "flush -- call failed: " << status << ".";
- return;
- }
- if (!c2_hidl::utils::objcpy(flushedWork, wb)) {
- status = C2_CORRUPTED;
- } else {
- status = C2_OK;
- }
- });
- if (!transStatus.isOk()) {
- LOG(ERROR) << "flush -- transaction failed.";
- return C2_TRANSACTION_FAILED;
+ (void)mode; // Flush mode isn't supported in HIDL/AIDL yet.
+ c2_status_t status = C2_OK;
+ if (mAidlBase) {
+ c2_aidl::WorkBundle workBundle;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->flush(&workBundle);
+ c2_status_t status = GetC2Status(transStatus, "flush");
+ if (status != C2_OK) {
+ return status;
+ }
+ if (!c2_aidl::utils::FromAidl(flushedWork, workBundle)) {
+ LOG(DEBUG) << "flush -- flushedWork corrupted.";
+ return C2_CORRUPTED;
+ }
+ } else {
+ Return<void> transStatus = mHidlBase1_0->flush(
+ [&status, flushedWork](
+ c2_hidl::Status s, const c2_hidl::WorkBundle& wb) {
+ status = static_cast<c2_status_t>(s);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "flush -- call failed: " << status << ".";
+ return;
+ }
+ if (!c2_hidl::utils::objcpy(flushedWork, wb)) {
+ status = C2_CORRUPTED;
+ } else {
+ status = C2_OK;
+ }
+ });
+ if (!transStatus.isOk()) {
+ LOG(ERROR) << "flush -- transaction failed.";
+ return C2_TRANSACTION_FAILED;
+ }
}
// Indices of flushed work items.
@@ -1722,7 +2096,12 @@
}
c2_status_t Codec2Client::Component::drain(C2Component::drain_mode_t mode) {
- Return<c2_hidl::Status> transStatus = mBase1_0->drain(
+ if (mAidlBase) {
+ ::ndk::ScopedAStatus transStatus = mAidlBase->drain(
+ mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
+ return GetC2Status(transStatus, "drain");
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->drain(
mode == C2Component::DRAIN_COMPONENT_WITH_EOS);
if (!transStatus.isOk()) {
LOG(ERROR) << "drain -- transaction failed.";
@@ -1737,7 +2116,11 @@
}
c2_status_t Codec2Client::Component::start() {
- Return<c2_hidl::Status> transStatus = mBase1_0->start();
+ if (mAidlBase) {
+ ::ndk::ScopedAStatus transStatus = mAidlBase->start();
+ return GetC2Status(transStatus, "start");
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->start();
if (!transStatus.isOk()) {
LOG(ERROR) << "start -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1751,7 +2134,11 @@
}
c2_status_t Codec2Client::Component::stop() {
- Return<c2_hidl::Status> transStatus = mBase1_0->stop();
+ if (mAidlBase) {
+ ::ndk::ScopedAStatus transStatus = mAidlBase->stop();
+ return GetC2Status(transStatus, "stop");
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->stop();
if (!transStatus.isOk()) {
LOG(ERROR) << "stop -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1765,7 +2152,11 @@
}
c2_status_t Codec2Client::Component::reset() {
- Return<c2_hidl::Status> transStatus = mBase1_0->reset();
+ if (mAidlBase) {
+ ::ndk::ScopedAStatus transStatus = mAidlBase->reset();
+ return GetC2Status(transStatus, "reset");
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->reset();
if (!transStatus.isOk()) {
LOG(ERROR) << "reset -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1779,7 +2170,11 @@
}
c2_status_t Codec2Client::Component::release() {
- Return<c2_hidl::Status> transStatus = mBase1_0->release();
+ if (mAidlBase) {
+ ::ndk::ScopedAStatus transStatus = mAidlBase->release();
+ return GetC2Status(transStatus, "release");
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->release();
if (!transStatus.isOk()) {
LOG(ERROR) << "release -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1796,11 +2191,25 @@
uint32_t avSyncHwId,
native_handle_t** sidebandHandle) {
*sidebandHandle = nullptr;
- if (!mBase1_1) {
+ if (mAidlBase) {
+ ::aidl::android::hardware::common::NativeHandle handle;
+ ::ndk::ScopedAStatus transStatus = mAidlBase->configureVideoTunnel(avSyncHwId, &handle);
+ c2_status_t status = GetC2Status(transStatus, "configureVideoTunnel");
+ if (status != C2_OK) {
+ return status;
+ }
+ if (isAidlNativeHandleEmpty(handle)) {
+ LOG(DEBUG) << "configureVideoTunnel -- empty handle returned";
+ } else {
+ *sidebandHandle = dupFromAidl(handle);
+ }
+ return C2_OK;
+ }
+ if (!mHidlBase1_1) {
return C2_OMITTED;
}
c2_status_t status{};
- Return<void> transStatus = mBase1_1->configureVideoTunnel(avSyncHwId,
+ Return<void> transStatus = mHidlBase1_1->configureVideoTunnel(avSyncHwId,
[&status, sidebandHandle](
c2_hidl::Status s, hardware::hidl_handle const& h) {
status = static_cast<c2_status_t>(s);
@@ -1841,8 +2250,8 @@
bqId = 0;
mOutputBufferQueue->configure(nullIgbp, generation, 0, maxDequeueCount, nullptr);
} else {
- mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount, mBase1_2 ?
- &syncObj : nullptr);
+ mOutputBufferQueue->configure(surface, generation, bqId, maxDequeueCount,
+ mHidlBase1_2 ? &syncObj : nullptr);
}
// set consumer bits
@@ -1881,11 +2290,15 @@
ALOGD("setOutputSurface -- generation=%u consumer usage=%#llx%s",
generation, (long long)consumerUsage, syncObj ? " sync" : "");
+ if (mAidlBase) {
+ // FIXME
+ return C2_OMITTED;
+ }
Return<c2_hidl::Status> transStatus = syncObj ?
- mBase1_2->setOutputSurfaceWithSyncObj(
+ mHidlBase1_2->setOutputSurfaceWithSyncObj(
static_cast<uint64_t>(blockPoolId),
bqId == 0 ? nullHgbp : igbp, *syncObj) :
- mBase1_0->setOutputSurface(
+ mHidlBase1_0->setOutputSurface(
static_cast<uint64_t>(blockPoolId),
bqId == 0 ? nullHgbp : igbp);
@@ -1925,7 +2338,11 @@
C2BlockPool::local_id_t blockPoolId) {
std::scoped_lock lock(mOutputMutex);
mOutputBufferQueue->stop();
- Return<c2_hidl::Status> transStatus = mBase1_0->setOutputSurface(
+ if (mAidlBase) {
+ // FIXME
+ return;
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->setOutputSurface(
static_cast<uint64_t>(blockPoolId), nullptr);
if (!transStatus.isOk()) {
LOG(ERROR) << "setOutputSurface(stopUsingOutputSurface) -- transaction failed.";
@@ -1943,8 +2360,12 @@
c2_status_t Codec2Client::Component::connectToInputSurface(
const std::shared_ptr<InputSurface>& inputSurface,
std::shared_ptr<InputSurfaceConnection>* connection) {
+ if (mAidlBase) {
+ // FIXME
+ return C2_OMITTED;
+ }
c2_status_t status;
- Return<void> transStatus = mBase1_0->connectToInputSurface(
+ Return<void> transStatus = mHidlBase1_0->connectToInputSurface(
inputSurface->mBase,
[&status, connection](
c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
@@ -1967,8 +2388,12 @@
const sp<HGraphicBufferProducer1>& producer,
const sp<HGraphicBufferSource>& source,
std::shared_ptr<InputSurfaceConnection>* connection) {
+ if (mAidlBase) {
+ LOG(WARNING) << "Connecting to OMX input surface is not supported for AIDL C2 HAL";
+ return C2_OMITTED;
+ }
c2_status_t status;
- Return<void> transStatus = mBase1_0->connectToOmxInputSurface(
+ Return<void> transStatus = mHidlBase1_0->connectToOmxInputSurface(
producer, source,
[&status, connection](
c2_hidl::Status s, const sp<c2_hidl::IInputSurfaceConnection>& c) {
@@ -1988,7 +2413,11 @@
}
c2_status_t Codec2Client::Component::disconnectFromInputSurface() {
- Return<c2_hidl::Status> transStatus = mBase1_0->disconnectFromInputSurface();
+ if (mAidlBase) {
+ // FIXME
+ return C2_OMITTED;
+ }
+ Return<c2_hidl::Status> transStatus = mHidlBase1_0->disconnectFromInputSurface();
if (!transStatus.isOk()) {
LOG(ERROR) << "disconnectToInputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -2002,6 +2431,12 @@
return status;
}
+Codec2Client::Component::AidlDeathManager *Codec2Client::Component::GetAidlDeathManager() {
+ // This object never gets destructed
+ static AidlDeathManager *sManager = new AidlDeathManager();
+ return sManager;
+}
+
c2_status_t Codec2Client::Component::setDeathListener(
const std::shared_ptr<Component>& component,
const std::shared_ptr<Listener>& listener) {
@@ -2022,12 +2457,20 @@
}
};
+ if (component->mAidlBase) {
+ size_t seq;
+ if (GetAidlDeathManager()->linkToDeath(component, listener, &seq)) {
+ component->mAidlDeathSeq = seq;
+ }
+ return C2_OK;
+ }
+
sp<HidlDeathRecipient> deathRecipient = new HidlDeathRecipient();
deathRecipient->base = listener;
deathRecipient->component = component;
component->mDeathRecipient = deathRecipient;
- Return<bool> transResult = component->mBase1_0->linkToDeath(
+ Return<bool> transResult = component->mHidlBase1_0->linkToDeath(
component->mDeathRecipient, 0);
if (!transResult.isOk()) {
LOG(ERROR) << "setDeathListener -- linkToDeath() transaction failed.";
diff --git a/media/codec2/hal/client/include/codec2/hidl/client.h b/media/codec2/hal/client/include/codec2/hidl/client.h
index 6fa19b0..0c7dd77 100644
--- a/media/codec2/hal/client/include/codec2/hidl/client.h
+++ b/media/codec2/hal/client/include/codec2/hidl/client.h
@@ -95,6 +95,11 @@
struct IClientManager;
} // namespace android::hardware::media::bufferpool::V2_0
+namespace aidl::android::hardware::media::bufferpool2 {
+class IClientManager;
+} // namespace aidl::android::hardware::media::c2
+
+
namespace android::hardware::graphics::bufferqueue::V1_0 {
struct IGraphicBufferProducer;
} // android::hardware::graphics::bufferqueue::V1_0
@@ -173,12 +178,12 @@
struct Codec2Client : public Codec2ConfigurableClient {
- typedef ::android::hardware::media::c2::V1_0::IComponentStore Base1_0;
- typedef ::android::hardware::media::c2::V1_1::IComponentStore Base1_1;
- typedef ::android::hardware::media::c2::V1_2::IComponentStore Base1_2;
- typedef Base1_0 Base;
+ typedef ::android::hardware::media::c2::V1_0::IComponentStore HidlBase1_0;
+ typedef ::android::hardware::media::c2::V1_1::IComponentStore HidlBase1_1;
+ typedef ::android::hardware::media::c2::V1_2::IComponentStore HidlBase1_2;
+ typedef HidlBase1_0 HidlBase;
- typedef ::android::hardware::media::c2::V1_0::IConfigurable IConfigurable;
+ typedef ::aidl::android::hardware::media::c2::IComponentStore AidlBase;
struct Listener;
@@ -194,10 +199,11 @@
typedef Codec2Client Store;
- sp<Base> const& getBase() const;
- sp<Base1_0> const& getBase1_0() const;
- sp<Base1_1> const& getBase1_1() const;
- sp<Base1_2> const& getBase1_2() const;
+ sp<HidlBase> const& getHidlBase() const;
+ sp<HidlBase1_0> const& getHidlBase1_0() const;
+ sp<HidlBase1_1> const& getHidlBase1_1() const;
+ sp<HidlBase1_2> const& getHidlBase1_2() const;
+ ::ndk::SpAIBinder getAidlBase() const;
std::string const& getServiceName() const;
@@ -266,14 +272,19 @@
// base and/or configurable cannot be null.
Codec2Client(
- sp<Base> const& base,
- sp<IConfigurable> const& configurable,
+ sp<HidlBase> const& base,
+ sp<Codec2ConfigurableClient::HidlBase> const& configurable,
+ size_t serviceIndex);
+ Codec2Client(
+ std::shared_ptr<AidlBase> const& base,
+ std::shared_ptr<Codec2ConfigurableClient::AidlBase> const& configurable,
size_t serviceIndex);
protected:
- sp<Base1_0> mBase1_0;
- sp<Base1_1> mBase1_1;
- sp<Base1_2> mBase1_2;
+ sp<HidlBase1_0> mHidlBase1_0;
+ sp<HidlBase1_1> mHidlBase1_1;
+ sp<HidlBase1_2> mHidlBase1_2;
+ std::shared_ptr<AidlBase> mAidlBase;
// Finds the first store where the predicate returns C2_OK and returns the
// last predicate result. The predicate will be tried on all stores. The
@@ -301,8 +312,11 @@
mutable std::vector<C2Component::Traits> mTraitsList;
sp<::android::hardware::media::bufferpool::V2_0::IClientManager>
- mHostPoolManager;
+ mHidlHostPoolManager;
+ std::shared_ptr<::aidl::android::hardware::media::bufferpool2::IClientManager>
+ mAidlHostPoolManager;
+ static std::vector<std::string> CacheServiceNames();
static std::shared_ptr<Codec2Client> _CreateFromIndex(size_t index);
std::vector<C2Component::Traits> _listComponents(bool* success) const;
@@ -312,12 +326,15 @@
struct Codec2Client::Interface : public Codec2Client::Configurable {
- typedef ::android::hardware::media::c2::V1_0::IComponentInterface Base;
+ typedef ::android::hardware::media::c2::V1_0::IComponentInterface HidlBase;
+ typedef ::aidl::android::hardware::media::c2::IComponentInterface AidlBase;
- Interface(const sp<Base>& base);
+ Interface(const sp<HidlBase>& base);
+ Interface(const std::shared_ptr<AidlBase>& base);
protected:
- sp<Base> mBase;
+ sp<HidlBase> mHidlBase;
+ std::shared_ptr<AidlBase> mAidlBase;
};
struct Codec2Client::Listener {
@@ -356,16 +373,17 @@
int32_t slotId,
int64_t timestampNs) = 0;
- virtual ~Listener();
-
+ virtual ~Listener() = default;
};
struct Codec2Client::Component : public Codec2Client::Configurable {
- typedef ::android::hardware::media::c2::V1_0::IComponent Base1_0;
- typedef ::android::hardware::media::c2::V1_1::IComponent Base1_1;
- typedef ::android::hardware::media::c2::V1_2::IComponent Base1_2;
- typedef Base1_0 Base;
+ typedef ::android::hardware::media::c2::V1_0::IComponent HidlBase1_0;
+ typedef ::android::hardware::media::c2::V1_1::IComponent HidlBase1_1;
+ typedef ::android::hardware::media::c2::V1_2::IComponent HidlBase1_2;
+ typedef HidlBase1_0 HidlBase;
+
+ typedef ::aidl::android::hardware::media::c2::IComponent AidlBase;
c2_status_t createBlockPool(
C2Allocator::id_t id,
@@ -469,19 +487,23 @@
c2_status_t disconnectFromInputSurface();
// base cannot be null.
- Component(const sp<Base>& base);
- Component(const sp<Base1_1>& base);
- Component(const sp<Base1_2>& base);
+ Component(const sp<HidlBase>& base);
+ Component(const sp<HidlBase1_1>& base);
+ Component(const sp<HidlBase1_2>& base);
+ Component(const std::shared_ptr<AidlBase>& base);
~Component();
protected:
- sp<Base1_0> mBase1_0;
- sp<Base1_1> mBase1_1;
- sp<Base1_2> mBase1_2;
+ sp<HidlBase1_0> mHidlBase1_0;
+ sp<HidlBase1_1> mHidlBase1_1;
+ sp<HidlBase1_2> mHidlBase1_2;
+ std::shared_ptr<AidlBase> mAidlBase;
- struct BufferPoolSender;
- std::unique_ptr<BufferPoolSender> mBufferPoolSender;
+ struct HidlBufferPoolSender;
+ struct AidlBufferPoolSender;
+ std::unique_ptr<HidlBufferPoolSender> mHidlBufferPoolSender;
+ std::unique_ptr<AidlBufferPoolSender> mAidlBufferPoolSender;
struct OutputBufferQueue;
std::unique_ptr<OutputBufferQueue> mOutputBufferQueue;
@@ -491,6 +513,10 @@
// In order to prevent the race condition mutex is added.
std::mutex mOutputMutex;
+ class AidlDeathManager;
+ static AidlDeathManager *GetAidlDeathManager();
+ std::optional<size_t> mAidlDeathSeq;
+
static c2_status_t setDeathListener(
const std::shared_ptr<Component>& component,
const std::shared_ptr<Listener>& listener);
@@ -499,16 +525,15 @@
friend struct Codec2Client;
struct HidlListener;
+ struct AidlListener;
void handleOnWorkDone(const std::list<std::unique_ptr<C2Work>> &workItems);
-
};
struct Codec2Client::InputSurface : public Codec2Client::Configurable {
public:
typedef ::android::hardware::media::c2::V1_0::IInputSurface Base;
- typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection
- ConnectionBase;
+ typedef ::android::hardware::media::c2::V1_0::IInputSurfaceConnection ConnectionBase;
typedef Codec2Client::InputSurfaceConnection Connection;
diff --git a/media/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
index 1eefd87..81cdb43 100644
--- a/media/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -17,10 +17,14 @@
#ifndef ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
#define ANDROID_STAGEFRIGHT_C2BLOCK_INTERNAL_H_
-#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
-
#include <C2Buffer.h>
+#include <utils/RefBase.h>
+
+namespace android::hardware::graphics::bufferqueue::V2_0 {
+struct IGraphicBufferProducer;
+}
+
// Note: HIDL-BufferPool and AIDL-BufferPool are not compatible
namespace android::hardware::media::bufferpool {
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 44e78d6..718f782 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -47,6 +47,7 @@
"framework-permission-aidl-cpp",
"libaudioclient_aidl_conversion",
"libbase",
+ "libbinder_ndk",
"libactivitymanager_aidl",
"libandroid_net",
"libaudioclient",
diff --git a/media/libmediaplayerservice/DeathNotifier.cpp b/media/libmediaplayerservice/DeathNotifier.cpp
index d13bdf5..ab22f67 100644
--- a/media/libmediaplayerservice/DeathNotifier.cpp
+++ b/media/libmediaplayerservice/DeathNotifier.cpp
@@ -31,6 +31,10 @@
DeathRecipient(Notify const& notify): mNotify{notify} {
}
+ void initNdk() {
+ mNdkRecipient.set(AIBinder_DeathRecipient_new(OnBinderDied));
+ }
+
virtual void binderDied(wp<IBinder> const&) override {
mNotify();
}
@@ -39,8 +43,18 @@
mNotify();
}
+ static void OnBinderDied(void *cookie) {
+ DeathRecipient *thiz = (DeathRecipient *)cookie;
+ thiz->mNotify();
+ }
+
+ AIBinder_DeathRecipient *getNdkRecipient() {
+ return mNdkRecipient.get();;
+ }
+
private:
Notify mNotify;
+ ::ndk::ScopedAIBinder_DeathRecipient mNdkRecipient;
};
DeathNotifier::DeathNotifier(sp<IBinder> const& service, Notify const& notify)
@@ -55,6 +69,14 @@
service->linkToDeath(mDeathRecipient, 0);
}
+DeathNotifier::DeathNotifier(::ndk::SpAIBinder const& service, Notify const& notify)
+ : mService{std::in_place_index<3>, service},
+ mDeathRecipient{new DeathRecipient(notify)} {
+ mDeathRecipient->initNdk();
+ AIBinder_linkToDeath(
+ service.get(), mDeathRecipient->getNdkRecipient(), mDeathRecipient.get());
+}
+
DeathNotifier::DeathNotifier(DeathNotifier&& other)
: mService{other.mService}, mDeathRecipient{other.mDeathRecipient} {
other.mService.emplace<0>();
@@ -71,6 +93,12 @@
case 2:
std::get<2>(mService)->unlinkToDeath(mDeathRecipient);
break;
+ case 3:
+ AIBinder_unlinkToDeath(
+ std::get<3>(mService).get(),
+ mDeathRecipient->getNdkRecipient(),
+ mDeathRecipient.get());
+ break;
default:
CHECK(false) << "Corrupted service type during destruction.";
}
diff --git a/media/libmediaplayerservice/DeathNotifier.h b/media/libmediaplayerservice/DeathNotifier.h
index 7bc2611..24e45a3 100644
--- a/media/libmediaplayerservice/DeathNotifier.h
+++ b/media/libmediaplayerservice/DeathNotifier.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
#define ANDROID_MEDIASERVICE_DEATHNOTIFIER_H
+#include <android/binder_auto_utils.h>
#include <android/hidl/base/1.0/IBase.h>
#include <binder/Binder.h>
#include <hidl/HidlSupport.h>
@@ -32,11 +33,12 @@
DeathNotifier(sp<IBinder> const& service, Notify const& notify);
DeathNotifier(sp<HBase> const& service, Notify const& notify);
+ DeathNotifier(::ndk::SpAIBinder const& service, Notify const& notify);
DeathNotifier(DeathNotifier&& other);
~DeathNotifier();
private:
- std::variant<std::monostate, sp<IBinder>, sp<HBase>> mService;
+ std::variant<std::monostate, sp<IBinder>, sp<HBase>, ::ndk::SpAIBinder> mService;
class DeathRecipient;
sp<DeathRecipient> mDeathRecipient;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 91599e7..10a1da7 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -927,10 +927,10 @@
{
for (std::shared_ptr<Codec2Client> const& client :
Codec2Client::CreateFromAllServices()) {
- sp<IBase> base = client->getBase();
- deathNotifiers.emplace_back(
- base, [l = wp<MediaPlayerBase>(p),
- name = std::string(client->getServiceName())]() {
+ sp<IBase> hidlBase = client->getHidlBase();
+ ::ndk::SpAIBinder aidlBase = client->getAidlBase();
+ auto onBinderDied = [l = wp<MediaPlayerBase>(p),
+ name = std::string(client->getServiceName())]() {
sp<MediaPlayerBase> listener = l.promote();
if (listener) {
ALOGI("Codec2 service \"%s\" died. "
@@ -944,7 +944,12 @@
"without a death handler.",
name.c_str());
}
- });
+ };
+ if (hidlBase) {
+ deathNotifiers.emplace_back(hidlBase, onBinderDied);
+ } else if (aidlBase.get() != nullptr) {
+ deathNotifiers.emplace_back(aidlBase, onBinderDied);
+ }
}
}
}
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index d6b1c90..ed3ec89 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -22,6 +22,7 @@
#include "MediaPlayerService.h"
#include "StagefrightRecorder.h"
+#include <android/binder_auto_utils.h>
#include <android/hardware/media/omx/1.0/IOmx.h>
#include <android/hardware/media/c2/1.0/IComponentStore.h>
#include <binder/IPCThreadState.h>
@@ -490,9 +491,9 @@
{
for (std::shared_ptr<Codec2Client> const& client :
Codec2Client::CreateFromAllServices()) {
- sp<IBase> base = client->getBase();
- mDeathNotifiers.emplace_back(
- base, [l = wp<IMediaRecorderClient>(listener),
+ sp<IBase> hidlBase = client->getHidlBase();
+ ::ndk::SpAIBinder aidlBase = client->getAidlBase();
+ auto onBinderDied = [l = wp<IMediaRecorderClient>(listener),
name = std::string(client->getServiceName())]() {
sp<IMediaRecorderClient> listener = l.promote();
if (listener) {
@@ -507,7 +508,12 @@
"without a death handler",
name.c_str());
}
- });
+ };
+ if (hidlBase) {
+ mDeathNotifiers.emplace_back(hidlBase, onBinderDied);
+ } else if (aidlBase.get() != nullptr) {
+ mDeathNotifiers.emplace_back(aidlBase, onBinderDied);
+ }
}
}
}
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index 41a322a..b511372 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -35,6 +35,7 @@
shared_libs: [
"framework-permission-aidl-cpp",
"libbinder",
+ "libbinder_ndk",
"libcutils",
"libmedia",
"libstagefright",
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 3d5c1d2..6f19a7a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -618,13 +618,15 @@
}
// Convert Sink name to port pointer
sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
- if (sink == NULL && !mIgnoreVendorExtensions) {
- ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
- return BAD_VALUE;
- } else if (sink == NULL) {
- ALOGW("Skipping route to sink \"%s\" as it likely has vendor extension type",
- sinkAttr.c_str());
- return NO_INIT;
+ if (sink == NULL) {
+ if (!mIgnoreVendorExtensions) {
+ ALOGE("%s: no sink found with name \"%s\"", __func__, sinkAttr.c_str());
+ return BAD_VALUE;
+ } else {
+ ALOGW("%s: skipping route to sink \"%s\" as it likely has vendor extension type",
+ __func__, sinkAttr.c_str());
+ return NO_INIT;
+ }
}
route->setSink(sink);
@@ -641,12 +643,14 @@
while (devTag != NULL) {
if (strlen(devTag) != 0) {
sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
- if (source == NULL && !mIgnoreVendorExtensions) {
- ALOGE("%s: no source found with name=%s", __func__, devTag);
- return BAD_VALUE;
- } else if (source == NULL) {
- ALOGW("Skipping route source \"%s\" as it likely has vendor extension type",
- devTag);
+ if (source == NULL) {
+ if (!mIgnoreVendorExtensions) {
+ ALOGE("%s: no source found with name \"%s\"", __func__, devTag);
+ return BAD_VALUE;
+ } else {
+ ALOGW("%s: skipping route source \"%s\" as it likely has vendor extension type",
+ __func__, devTag);
+ }
} else {
sources.add(source);
}
@@ -728,10 +732,16 @@
sp<DeviceDescriptor> device = module->getDeclaredDevices().
getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
attachedDevice.get())));
- if (device == nullptr && mIgnoreVendorExtensions) {
- ALOGW("Skipped attached device \"%s\" because it likely uses a vendor"
- "extension type",
- reinterpret_cast<const char*>(attachedDevice.get()));
+ if (device == NULL) {
+ if (mIgnoreVendorExtensions) {
+ ALOGW("%s: skipped attached device \"%s\" because it likely uses a "
+ "vendor extension type",
+ __func__,
+ reinterpret_cast<const char*>(attachedDevice.get()));
+ } else {
+ ALOGE("%s: got null device in %s, \"%s\"", __func__, child->name,
+ reinterpret_cast<const char*>(attachedDevice.get()));
+ }
continue;
}
ctx->addDevice(device);