Move Codec2-related code from hardware/google/av
Test: None
Bug: 112362730
Change-Id: Ie2f8ff431d65c40333f267ab9877d47089adeea4
diff --git a/media/codec2/components/base/Android.bp b/media/codec2/components/base/Android.bp
new file mode 100644
index 0000000..ad456e2
--- /dev/null
+++ b/media/codec2/components/base/Android.bp
@@ -0,0 +1,141 @@
+// DO NOT DEPEND ON THIS DIRECTLY
+// use libstagefright_soft_c2-defaults instead
+cc_library_shared {
+ name: "libstagefright_soft_c2common",
+ defaults: ["libstagefright_codec2-impl-defaults"],
+ vendor_available: true,
+
+ srcs: [
+ "SimpleC2Component.cpp",
+ "SimpleC2Interface.cpp",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ export_shared_lib_headers: [
+ "libstagefright_ccodec_utils",
+ ],
+
+ shared_libs: [
+ "libcutils", // for properties
+ "liblog", // for ALOG
+ "libstagefright_ccodec_utils", // for ImageCopy
+ "libstagefright_foundation", // for Mutexed
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
+// public dependency for software codec implementation
+// to be used by code under media/codecs/* only as its stability is not guaranteed
+cc_defaults {
+ name: "libstagefright_soft_c2-defaults",
+ defaults: ["libstagefright_codec2-impl-defaults"],
+ vendor_available: true,
+
+ export_shared_lib_headers: [
+ "libstagefright_ccodec_utils",
+ ],
+
+ shared_libs: [
+ "libcutils", // for properties
+ "liblog", // for ALOG
+ "libstagefright_foundation", // for ColorUtils and MIME
+ "libstagefright_ccodec_utils", // for ImageCopy
+ "libstagefright_soft_c2common",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
+// public dependency for software codec implementation
+// to be used by code under media/codecs/* only
+cc_defaults {
+ name: "libstagefright_soft_c2_sanitize_all-defaults",
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+}
+
+// public dependency for software codec implementation
+// to be used by code under media/codecs/* only
+cc_defaults {
+ name: "libstagefright_soft_c2_sanitize_signed-defaults",
+
+ sanitize: {
+ misc_undefined: [
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+}
+
+// TEMP: used by cheets2 project - remove when no longer used
+cc_library_shared {
+ name: "libstagefright_simple_c2component",
+ vendor_available: true,
+
+ srcs: [
+ "SimpleC2Interface.cpp",
+ ],
+
+ local_include_dirs: [
+ "include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libstagefright_codec2",
+ "libstagefright_codec2_vndk",
+ "libstagefright_foundation",
+ "libutils",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+
+ ldflags: ["-Wl,-Bsymbolic"],
+}
+
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
new file mode 100644
index 0000000..7990ee5
--- /dev/null
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2017 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 "SimpleC2Component"
+#include <log/log.h>
+
+#include <cutils/properties.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+#include <inttypes.h>
+
+#include <C2Config.h>
+#include <C2Debug.h>
+#include <C2PlatformSupport.h>
+#include <SimpleC2Component.h>
+
+namespace android {
+
+std::unique_ptr<C2Work> SimpleC2Component::WorkQueue::pop_front() {
+ std::unique_ptr<C2Work> work = std::move(mQueue.front().work);
+ mQueue.pop_front();
+ return work;
+}
+
+void SimpleC2Component::WorkQueue::push_back(std::unique_ptr<C2Work> work) {
+ mQueue.push_back({ std::move(work), NO_DRAIN });
+}
+
+bool SimpleC2Component::WorkQueue::empty() const {
+ return mQueue.empty();
+}
+
+void SimpleC2Component::WorkQueue::clear() {
+ mQueue.clear();
+}
+
+uint32_t SimpleC2Component::WorkQueue::drainMode() const {
+ return mQueue.front().drainMode;
+}
+
+void SimpleC2Component::WorkQueue::markDrain(uint32_t drainMode) {
+ mQueue.push_back({ nullptr, drainMode });
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+SimpleC2Component::WorkHandler::WorkHandler() : mRunning(false) {}
+
+void SimpleC2Component::WorkHandler::setComponent(
+ const std::shared_ptr<SimpleC2Component> &thiz) {
+ mThiz = thiz;
+}
+
+static void Reply(const sp<AMessage> &msg, int32_t *err = nullptr) {
+ sp<AReplyToken> replyId;
+ CHECK(msg->senderAwaitsResponse(&replyId));
+ sp<AMessage> reply = new AMessage;
+ if (err) {
+ reply->setInt32("err", *err);
+ }
+ reply->postReply(replyId);
+}
+
+void SimpleC2Component::WorkHandler::onMessageReceived(const sp<AMessage> &msg) {
+ std::shared_ptr<SimpleC2Component> thiz = mThiz.lock();
+ if (!thiz) {
+ ALOGD("component not yet set; msg = %s", msg->debugString().c_str());
+ sp<AReplyToken> replyId;
+ if (msg->senderAwaitsResponse(&replyId)) {
+ sp<AMessage> reply = new AMessage;
+ reply->setInt32("err", C2_CORRUPTED);
+ reply->postReply(replyId);
+ }
+ return;
+ }
+
+ switch (msg->what()) {
+ case kWhatProcess: {
+ if (mRunning) {
+ if (thiz->processQueue()) {
+ (new AMessage(kWhatProcess, this))->post();
+ }
+ } else {
+ ALOGV("Ignore process message as we're not running");
+ }
+ break;
+ }
+ case kWhatInit: {
+ int32_t err = thiz->onInit();
+ Reply(msg, &err);
+ [[fallthrough]];
+ }
+ case kWhatStart: {
+ mRunning = true;
+ break;
+ }
+ case kWhatStop: {
+ int32_t err = thiz->onStop();
+ Reply(msg, &err);
+ break;
+ }
+ case kWhatReset: {
+ thiz->onReset();
+ mRunning = false;
+ Reply(msg);
+ break;
+ }
+ case kWhatRelease: {
+ thiz->onRelease();
+ mRunning = false;
+ Reply(msg);
+ break;
+ }
+ default: {
+ ALOGD("Unrecognized msg: %d", msg->what());
+ break;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+struct DummyReadView : public C2ReadView {
+ DummyReadView() : C2ReadView(C2_NO_INIT) {}
+};
+
+} // namespace
+
+SimpleC2Component::SimpleC2Component(
+ const std::shared_ptr<C2ComponentInterface> &intf)
+ : mDummyReadView(DummyReadView()),
+ mIntf(intf),
+ mLooper(new ALooper),
+ mHandler(new WorkHandler) {
+ mLooper->setName(intf->getName().c_str());
+ (void)mLooper->registerHandler(mHandler);
+ mLooper->start(false, false, ANDROID_PRIORITY_VIDEO);
+}
+
+SimpleC2Component::~SimpleC2Component() {
+ mLooper->unregisterHandler(mHandler->id());
+ (void)mLooper->stop();
+}
+
+c2_status_t SimpleC2Component::setListener_vb(
+ const std::shared_ptr<C2Component::Listener> &listener, c2_blocking_t mayBlock) {
+ mHandler->setComponent(shared_from_this());
+
+ Mutexed<ExecState>::Locked state(mExecState);
+ if (state->mState == RUNNING) {
+ if (listener) {
+ return C2_BAD_STATE;
+ } else if (!mayBlock) {
+ return C2_BLOCKING;
+ }
+ }
+ state->mListener = listener;
+ // TODO: wait for listener change to have taken place before returning
+ // (e.g. if there is an ongoing listener callback)
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::queue_nb(std::list<std::unique_ptr<C2Work>> * const items) {
+ {
+ Mutexed<ExecState>::Locked state(mExecState);
+ if (state->mState != RUNNING) {
+ return C2_BAD_STATE;
+ }
+ }
+ bool queueWasEmpty = false;
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ queueWasEmpty = queue->empty();
+ while (!items->empty()) {
+ queue->push_back(std::move(items->front()));
+ items->pop_front();
+ }
+ }
+ if (queueWasEmpty) {
+ (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
+ }
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::announce_nb(const std::vector<C2WorkOutline> &items) {
+ (void)items;
+ return C2_OMITTED;
+}
+
+c2_status_t SimpleC2Component::flush_sm(
+ flush_mode_t flushMode, std::list<std::unique_ptr<C2Work>>* const flushedWork) {
+ (void)flushMode;
+ {
+ Mutexed<ExecState>::Locked state(mExecState);
+ if (state->mState != RUNNING) {
+ return C2_BAD_STATE;
+ }
+ }
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ queue->incGeneration();
+ // TODO: queue->splicedBy(flushedWork, flushedWork->end());
+ while (!queue->empty()) {
+ std::unique_ptr<C2Work> work = queue->pop_front();
+ if (work) {
+ flushedWork->push_back(std::move(work));
+ }
+ }
+ }
+ {
+ Mutexed<PendingWork>::Locked pending(mPendingWork);
+ while (!pending->empty()) {
+ flushedWork->push_back(std::move(pending->begin()->second));
+ pending->erase(pending->begin());
+ }
+ }
+
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::drain_nb(drain_mode_t drainMode) {
+ if (drainMode == DRAIN_CHAIN) {
+ return C2_OMITTED;
+ }
+ {
+ Mutexed<ExecState>::Locked state(mExecState);
+ if (state->mState != RUNNING) {
+ return C2_BAD_STATE;
+ }
+ }
+ bool queueWasEmpty = false;
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ queueWasEmpty = queue->empty();
+ queue->markDrain(drainMode);
+ }
+ if (queueWasEmpty) {
+ (new AMessage(WorkHandler::kWhatProcess, mHandler))->post();
+ }
+
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::start() {
+ Mutexed<ExecState>::Locked state(mExecState);
+ if (state->mState == RUNNING) {
+ return C2_BAD_STATE;
+ }
+ bool needsInit = (state->mState == UNINITIALIZED);
+ state.unlock();
+ if (needsInit) {
+ sp<AMessage> reply;
+ (new AMessage(WorkHandler::kWhatInit, mHandler))->postAndAwaitResponse(&reply);
+ int32_t err;
+ CHECK(reply->findInt32("err", &err));
+ if (err != C2_OK) {
+ return (c2_status_t)err;
+ }
+ } else {
+ (new AMessage(WorkHandler::kWhatStart, mHandler))->post();
+ }
+ state.lock();
+ state->mState = RUNNING;
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::stop() {
+ ALOGV("stop");
+ {
+ Mutexed<ExecState>::Locked state(mExecState);
+ if (state->mState != RUNNING) {
+ return C2_BAD_STATE;
+ }
+ state->mState = STOPPED;
+ }
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ queue->clear();
+ }
+ {
+ Mutexed<PendingWork>::Locked pending(mPendingWork);
+ pending->clear();
+ }
+ sp<AMessage> reply;
+ (new AMessage(WorkHandler::kWhatStop, mHandler))->postAndAwaitResponse(&reply);
+ int32_t err;
+ CHECK(reply->findInt32("err", &err));
+ if (err != C2_OK) {
+ return (c2_status_t)err;
+ }
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::reset() {
+ ALOGV("reset");
+ {
+ Mutexed<ExecState>::Locked state(mExecState);
+ state->mState = UNINITIALIZED;
+ }
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ queue->clear();
+ }
+ {
+ Mutexed<PendingWork>::Locked pending(mPendingWork);
+ pending->clear();
+ }
+ sp<AMessage> reply;
+ (new AMessage(WorkHandler::kWhatReset, mHandler))->postAndAwaitResponse(&reply);
+ return C2_OK;
+}
+
+c2_status_t SimpleC2Component::release() {
+ ALOGV("release");
+ sp<AMessage> reply;
+ (new AMessage(WorkHandler::kWhatRelease, mHandler))->postAndAwaitResponse(&reply);
+ return C2_OK;
+}
+
+std::shared_ptr<C2ComponentInterface> SimpleC2Component::intf() {
+ return mIntf;
+}
+
+namespace {
+
+std::list<std::unique_ptr<C2Work>> vec(std::unique_ptr<C2Work> &work) {
+ std::list<std::unique_ptr<C2Work>> ret;
+ ret.push_back(std::move(work));
+ return ret;
+}
+
+} // namespace
+
+void SimpleC2Component::finish(
+ uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
+ std::unique_ptr<C2Work> work;
+ {
+ Mutexed<PendingWork>::Locked pending(mPendingWork);
+ if (pending->count(frameIndex) == 0) {
+ ALOGW("unknown frame index: %" PRIu64, frameIndex);
+ return;
+ }
+ work = std::move(pending->at(frameIndex));
+ pending->erase(frameIndex);
+ }
+ if (work) {
+ fillWork(work);
+ std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
+ listener->onWorkDone_nb(shared_from_this(), vec(work));
+ ALOGV("returning pending work");
+ }
+}
+
+void SimpleC2Component::cloneAndSend(
+ uint64_t frameIndex,
+ const std::unique_ptr<C2Work> ¤tWork,
+ std::function<void(const std::unique_ptr<C2Work> &)> fillWork) {
+ std::unique_ptr<C2Work> work(new C2Work);
+ if (currentWork->input.ordinal.frameIndex == frameIndex) {
+ work->input.flags = currentWork->input.flags;
+ work->input.ordinal = currentWork->input.ordinal;
+ } else {
+ Mutexed<PendingWork>::Locked pending(mPendingWork);
+ if (pending->count(frameIndex) == 0) {
+ ALOGW("unknown frame index: %" PRIu64, frameIndex);
+ return;
+ }
+ work->input.flags = pending->at(frameIndex)->input.flags;
+ work->input.ordinal = pending->at(frameIndex)->input.ordinal;
+ }
+ work->worklets.emplace_back(new C2Worklet);
+ if (work) {
+ fillWork(work);
+ std::shared_ptr<C2Component::Listener> listener = mExecState.lock()->mListener;
+ listener->onWorkDone_nb(shared_from_this(), vec(work));
+ ALOGV("cloned and sending work");
+ }
+}
+
+bool SimpleC2Component::processQueue() {
+ std::unique_ptr<C2Work> work;
+ uint64_t generation;
+ int32_t drainMode;
+ bool isFlushPending = false;
+ bool hasQueuedWork = false;
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ if (queue->empty()) {
+ return false;
+ }
+
+ generation = queue->generation();
+ drainMode = queue->drainMode();
+ isFlushPending = queue->popPendingFlush();
+ work = queue->pop_front();
+ hasQueuedWork = !queue->empty();
+ }
+ if (isFlushPending) {
+ ALOGV("processing pending flush");
+ c2_status_t err = onFlush_sm();
+ if (err != C2_OK) {
+ ALOGD("flush err: %d", err);
+ // TODO: error
+ }
+ }
+
+ if (!mOutputBlockPool) {
+ c2_status_t err = [this] {
+ // TODO: don't use query_vb
+ C2StreamFormatConfig::output outputFormat(0u);
+ std::vector<std::unique_ptr<C2Param>> params;
+ c2_status_t err = intf()->query_vb(
+ { &outputFormat },
+ { C2PortBlockPoolsTuning::output::PARAM_TYPE },
+ C2_DONT_BLOCK,
+ ¶ms);
+ if (err != C2_OK && err != C2_BAD_INDEX) {
+ ALOGD("query err = %d", err);
+ return err;
+ }
+ C2BlockPool::local_id_t poolId =
+ outputFormat.value == C2FormatVideo
+ ? C2BlockPool::BASIC_GRAPHIC
+ : C2BlockPool::BASIC_LINEAR;
+ if (params.size()) {
+ C2PortBlockPoolsTuning::output *outputPools =
+ C2PortBlockPoolsTuning::output::From(params[0].get());
+ if (outputPools && outputPools->flexCount() >= 1) {
+ poolId = outputPools->m.values[0];
+ }
+ }
+
+ err = GetCodec2BlockPool(poolId, shared_from_this(), &mOutputBlockPool);
+ ALOGD("Using output block pool with poolID %llu => got %llu - %d",
+ (unsigned long long)poolId,
+ (unsigned long long)(
+ mOutputBlockPool ? mOutputBlockPool->getLocalId() : 111000111),
+ err);
+ return err;
+ }();
+ if (err != C2_OK) {
+ Mutexed<ExecState>::Locked state(mExecState);
+ std::shared_ptr<C2Component::Listener> listener = state->mListener;
+ state.unlock();
+ listener->onError_nb(shared_from_this(), err);
+ return hasQueuedWork;
+ }
+ }
+
+ if (!work) {
+ c2_status_t err = drain(drainMode, mOutputBlockPool);
+ if (err != C2_OK) {
+ Mutexed<ExecState>::Locked state(mExecState);
+ std::shared_ptr<C2Component::Listener> listener = state->mListener;
+ state.unlock();
+ listener->onError_nb(shared_from_this(), err);
+ }
+ return hasQueuedWork;
+ }
+
+ {
+ std::vector<C2Param *> updates;
+ for (const std::unique_ptr<C2Param> ¶m: work->input.configUpdate) {
+ if (param) {
+ updates.emplace_back(param.get());
+ }
+ }
+ if (!updates.empty()) {
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = intf()->config_vb(updates, C2_MAY_BLOCK, &failures);
+ ALOGD("applied %zu configUpdates => %s (%d)", updates.size(), asString(err), err);
+ }
+ }
+
+ ALOGV("start processing frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
+ process(work, mOutputBlockPool);
+ ALOGV("processed frame #%" PRIu64, work->input.ordinal.frameIndex.peeku());
+ {
+ Mutexed<WorkQueue>::Locked queue(mWorkQueue);
+ if (queue->generation() != generation) {
+ ALOGD("work form old generation: was %" PRIu64 " now %" PRIu64,
+ queue->generation(), generation);
+ work->result = C2_NOT_FOUND;
+ queue.unlock();
+ {
+ Mutexed<ExecState>::Locked state(mExecState);
+ std::shared_ptr<C2Component::Listener> listener = state->mListener;
+ state.unlock();
+ listener->onWorkDone_nb(shared_from_this(), vec(work));
+ }
+ queue.lock();
+ return hasQueuedWork;
+ }
+ }
+ if (work->workletsProcessed != 0u) {
+ Mutexed<ExecState>::Locked state(mExecState);
+ ALOGV("returning this work");
+ std::shared_ptr<C2Component::Listener> listener = state->mListener;
+ state.unlock();
+ listener->onWorkDone_nb(shared_from_this(), vec(work));
+ } else {
+ ALOGV("queue pending work");
+ work->input.buffers.clear();
+ std::unique_ptr<C2Work> unexpected;
+ {
+ Mutexed<PendingWork>::Locked pending(mPendingWork);
+ uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
+ if (pending->count(frameIndex) != 0) {
+ unexpected = std::move(pending->at(frameIndex));
+ pending->erase(frameIndex);
+ }
+ (void)pending->insert({ frameIndex, std::move(work) });
+ }
+ if (unexpected) {
+ ALOGD("unexpected pending work");
+ unexpected->result = C2_CORRUPTED;
+ Mutexed<ExecState>::Locked state(mExecState);
+ std::shared_ptr<C2Component::Listener> listener = state->mListener;
+ state.unlock();
+ listener->onWorkDone_nb(shared_from_this(), vec(unexpected));
+ }
+ }
+ return hasQueuedWork;
+}
+
+std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
+ const std::shared_ptr<C2LinearBlock> &block) {
+ return createLinearBuffer(block, block->offset(), block->size());
+}
+
+std::shared_ptr<C2Buffer> SimpleC2Component::createLinearBuffer(
+ const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size) {
+ return C2Buffer::CreateLinearBuffer(block->share(offset, size, ::C2Fence()));
+}
+
+std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
+ const std::shared_ptr<C2GraphicBlock> &block) {
+ return createGraphicBuffer(block, C2Rect(block->width(), block->height()));
+}
+
+std::shared_ptr<C2Buffer> SimpleC2Component::createGraphicBuffer(
+ const std::shared_ptr<C2GraphicBlock> &block, const C2Rect &crop) {
+ return C2Buffer::CreateGraphicBuffer(block->share(crop, ::C2Fence()));
+}
+
+} // namespace android
diff --git a/media/codec2/components/base/SimpleC2Interface.cpp b/media/codec2/components/base/SimpleC2Interface.cpp
new file mode 100644
index 0000000..c849a4e
--- /dev/null
+++ b/media/codec2/components/base/SimpleC2Interface.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2017 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 "SimpleC2Interface"
+#include <utils/Log.h>
+
+// use MediaDefs here vs. MediaCodecConstants as this is not MediaCodec specific/dependent
+#include <media/stagefright/foundation/MediaDefs.h>
+
+#include <SimpleC2Interface.h>
+
+namespace android {
+
+/* SimpleInterface */
+
+SimpleInterface<void>::BaseParams::BaseParams(
+ const std::shared_ptr<C2ReflectorHelper> &reflector,
+ C2String name,
+ C2Component::kind_t kind,
+ C2Component::domain_t domain,
+ C2String mediaType,
+ std::vector<C2String> aliases)
+ : C2InterfaceHelper(reflector) {
+ setDerivedInstance(this);
+
+ addParameter(
+ DefineParam(mName, C2_PARAMKEY_COMPONENT_NAME)
+ .withConstValue(AllocSharedString<C2ComponentNameSetting>(name.c_str()))
+ .build());
+
+ if (aliases.size()) {
+ C2String joined;
+ for (const C2String &alias : aliases) {
+ if (joined.length()) {
+ joined += ",";
+ }
+ joined += alias;
+ }
+ addParameter(
+ DefineParam(mAliases, C2_PARAMKEY_COMPONENT_ALIASES)
+ .withConstValue(AllocSharedString<C2ComponentAliasesSetting>(joined.c_str()))
+ .build());
+ }
+
+ addParameter(
+ DefineParam(mKind, C2_PARAMKEY_COMPONENT_KIND)
+ .withConstValue(new C2ComponentKindSetting(kind))
+ .build());
+
+ addParameter(
+ DefineParam(mDomain, C2_PARAMKEY_COMPONENT_DOMAIN)
+ .withConstValue(new C2ComponentDomainSetting(domain))
+ .build());
+
+ // simple interfaces have single streams
+ addParameter(
+ DefineParam(mInputStreamCount, C2_PARAMKEY_INPUT_STREAM_COUNT)
+ .withConstValue(new C2PortStreamCountTuning::input(1))
+ .build());
+
+ addParameter(
+ DefineParam(mOutputStreamCount, C2_PARAMKEY_OUTPUT_STREAM_COUNT)
+ .withConstValue(new C2PortStreamCountTuning::output(1))
+ .build());
+
+ // set up buffer formats and allocators
+
+ // default to linear buffers and no media type
+ C2BufferData::type_t rawBufferType = C2BufferData::LINEAR;
+ C2String rawMediaType;
+ C2Allocator::id_t rawAllocator = C2AllocatorStore::DEFAULT_LINEAR;
+ C2BlockPool::local_id_t rawPoolId = C2BlockPool::BASIC_LINEAR;
+ C2BufferData::type_t codedBufferType = C2BufferData::LINEAR;
+ C2Allocator::id_t codedAllocator = C2AllocatorStore::DEFAULT_LINEAR;
+ C2BlockPool::local_id_t codedPoolId = C2BlockPool::BASIC_LINEAR;
+
+ switch (domain) {
+ case C2Component::DOMAIN_IMAGE:
+ case C2Component::DOMAIN_VIDEO:
+ // TODO: should we define raw image? The only difference is timestamp handling
+ rawBufferType = C2BufferData::GRAPHIC;
+ rawMediaType = MEDIA_MIMETYPE_VIDEO_RAW;
+ rawAllocator = C2AllocatorStore::DEFAULT_GRAPHIC;
+ rawPoolId = C2BlockPool::BASIC_GRAPHIC;
+ break;
+ case C2Component::DOMAIN_AUDIO:
+ rawBufferType = C2BufferData::LINEAR;
+ rawMediaType = MEDIA_MIMETYPE_AUDIO_RAW;
+ rawAllocator = C2AllocatorStore::DEFAULT_LINEAR;
+ rawPoolId = C2BlockPool::BASIC_LINEAR;
+ break;
+ default:
+ break;
+ }
+ bool isEncoder = kind == C2Component::KIND_ENCODER;
+
+ // handle raw decoders
+ if (mediaType == rawMediaType) {
+ codedBufferType = rawBufferType;
+ codedAllocator = rawAllocator;
+ codedPoolId = rawPoolId;
+ }
+
+ addParameter(
+ DefineParam(mInputFormat, C2_PARAMKEY_INPUT_STREAM_BUFFER_TYPE)
+ .withConstValue(new C2StreamBufferTypeSetting::input(
+ 0u, isEncoder ? rawBufferType : codedBufferType))
+ .build());
+
+ addParameter(
+ DefineParam(mInputMediaType, C2_PARAMKEY_INPUT_MEDIA_TYPE)
+ .withConstValue(AllocSharedString<C2PortMediaTypeSetting::input>(
+ isEncoder ? rawMediaType : mediaType))
+ .build());
+
+ addParameter(
+ DefineParam(mOutputFormat, C2_PARAMKEY_OUTPUT_STREAM_BUFFER_TYPE)
+ .withConstValue(new C2StreamBufferTypeSetting::output(
+ 0u, isEncoder ? codedBufferType : rawBufferType))
+ .build());
+
+ addParameter(
+ DefineParam(mOutputMediaType, C2_PARAMKEY_OUTPUT_MEDIA_TYPE)
+ .withConstValue(AllocSharedString<C2PortMediaTypeSetting::output>(
+ isEncoder ? mediaType : rawMediaType))
+ .build());
+
+ C2Allocator::id_t inputAllocators[1] = { isEncoder ? rawAllocator : codedAllocator };
+ C2Allocator::id_t outputAllocators[1] = { isEncoder ? codedAllocator : rawAllocator };
+ C2BlockPool::local_id_t outputPoolIds[1] = { isEncoder ? codedPoolId : rawPoolId };
+
+ addParameter(
+ DefineParam(mInputAllocators, C2_PARAMKEY_INPUT_ALLOCATORS)
+ .withDefault(C2PortAllocatorsTuning::input::AllocShared(inputAllocators))
+ .withFields({ C2F(mInputAllocators, m.values[0]).any(),
+ C2F(mInputAllocators, m.values).inRange(0, 1) })
+ .withSetter(Setter<C2PortAllocatorsTuning::input>::NonStrictValuesWithNoDeps)
+ .build());
+
+ addParameter(
+ DefineParam(mOutputAllocators, C2_PARAMKEY_OUTPUT_ALLOCATORS)
+ .withDefault(C2PortAllocatorsTuning::output::AllocShared(outputAllocators))
+ .withFields({ C2F(mOutputAllocators, m.values[0]).any(),
+ C2F(mOutputAllocators, m.values).inRange(0, 1) })
+ .withSetter(Setter<C2PortAllocatorsTuning::output>::NonStrictValuesWithNoDeps)
+ .build());
+
+ addParameter(
+ DefineParam(mOutputPoolIds, C2_PARAMKEY_OUTPUT_BLOCK_POOLS)
+ .withDefault(C2PortBlockPoolsTuning::output::AllocShared(outputPoolIds))
+ .withFields({ C2F(mOutputPoolIds, m.values[0]).any(),
+ C2F(mOutputPoolIds, m.values).inRange(0, 1) })
+ .withSetter(Setter<C2PortBlockPoolsTuning::output>::NonStrictValuesWithNoDeps)
+ .build());
+
+ // add stateless params
+ addParameter(
+ DefineParam(mSubscribedParamIndices, C2_PARAMKEY_SUBSCRIBED_PARAM_INDICES)
+ .withDefault(C2SubscribedParamIndicesTuning::AllocShared(0u))
+ .withFields({ C2F(mSubscribedParamIndices, m.values[0]).any(),
+ C2F(mSubscribedParamIndices, m.values).any() })
+ .withSetter(Setter<C2SubscribedParamIndicesTuning>::NonStrictValuesWithNoDeps)
+ .build());
+
+ /* TODO
+
+ addParameter(
+ DefineParam(mCurrentWorkOrdinal, C2_PARAMKEY_CURRENT_WORK)
+ .withDefault(new C2CurrentWorkTuning())
+ .withFields({ C2F(mCurrentWorkOrdinal, m.timeStamp).any(),
+ C2F(mCurrentWorkOrdinal, m.frameIndex).any(),
+ C2F(mCurrentWorkOrdinal, m.customOrdinal).any() })
+ .withSetter(Setter<C2CurrentWorkTuning>::NonStrictValuesWithNoDeps)
+ .build());
+
+ addParameter(
+ DefineParam(mLastInputQueuedWorkOrdinal, C2_PARAMKEY_LAST_INPUT_QUEUED)
+ .withDefault(new C2LastWorkQueuedTuning::input())
+ .withFields({ C2F(mLastInputQueuedWorkOrdinal, m.timeStamp).any(),
+ C2F(mLastInputQueuedWorkOrdinal, m.frameIndex).any(),
+ C2F(mLastInputQueuedWorkOrdinal, m.customOrdinal).any() })
+ .withSetter(Setter<C2LastWorkQueuedTuning::input>::NonStrictValuesWithNoDeps)
+ .build());
+
+ addParameter(
+ DefineParam(mLastOutputQueuedWorkOrdinal, C2_PARAMKEY_LAST_OUTPUT_QUEUED)
+ .withDefault(new C2LastWorkQueuedTuning::output())
+ .withFields({ C2F(mLastOutputQueuedWorkOrdinal, m.timeStamp).any(),
+ C2F(mLastOutputQueuedWorkOrdinal, m.frameIndex).any(),
+ C2F(mLastOutputQueuedWorkOrdinal, m.customOrdinal).any() })
+ .withSetter(Setter<C2LastWorkQueuedTuning::output>::NonStrictValuesWithNoDeps)
+ .build());
+
+ std::shared_ptr<C2OutOfMemoryTuning> mOutOfMemory;
+
+ std::shared_ptr<C2PortConfigCounterTuning::input> mInputConfigCounter;
+ std::shared_ptr<C2PortConfigCounterTuning::output> mOutputConfigCounter;
+ std::shared_ptr<C2ConfigCounterTuning> mDirectConfigCounter;
+
+ */
+}
+
+void SimpleInterface<void>::BaseParams::noInputLatency() {
+ addParameter(
+ DefineParam(mRequestedInputDelay, C2_PARAMKEY_INPUT_DELAY_REQUEST)
+ .withConstValue(new C2PortRequestedDelayTuning::input(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mActualInputDelay, C2_PARAMKEY_INPUT_DELAY)
+ .withConstValue(new C2PortActualDelayTuning::input(0u))
+ .build());
+}
+
+void SimpleInterface<void>::BaseParams::noOutputLatency() {
+ addParameter(
+ DefineParam(mRequestedOutputDelay, C2_PARAMKEY_OUTPUT_DELAY_REQUEST)
+ .withConstValue(new C2PortRequestedDelayTuning::output(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
+ .withConstValue(new C2PortActualDelayTuning::output(0u))
+ .build());
+}
+
+void SimpleInterface<void>::BaseParams::noPipelineLatency() {
+ addParameter(
+ DefineParam(mRequestedPipelineDelay, C2_PARAMKEY_PIPELINE_DELAY_REQUEST)
+ .withConstValue(new C2RequestedPipelineDelayTuning(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mActualPipelineDelay, C2_PARAMKEY_PIPELINE_DELAY)
+ .withConstValue(new C2ActualPipelineDelayTuning(0u))
+ .build());
+}
+
+void SimpleInterface<void>::BaseParams::noPrivateBuffers() {
+ addParameter(
+ DefineParam(mPrivateAllocators, C2_PARAMKEY_PRIVATE_ALLOCATORS)
+ .withConstValue(C2PrivateAllocatorsTuning::AllocShared(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mMaxPrivateBufferCount, C2_PARAMKEY_MAX_PRIVATE_BUFFER_COUNT)
+ .withConstValue(C2MaxPrivateBufferCountTuning::AllocShared(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mPrivatePoolIds, C2_PARAMKEY_PRIVATE_BLOCK_POOLS)
+ .withConstValue(C2PrivateBlockPoolsTuning::AllocShared(0u))
+ .build());
+}
+
+void SimpleInterface<void>::BaseParams::noInputReferences() {
+ addParameter(
+ DefineParam(mMaxInputReferenceAge, C2_PARAMKEY_INPUT_MAX_REFERENCE_AGE)
+ .withConstValue(new C2StreamMaxReferenceAgeTuning::input(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mMaxInputReferenceCount, C2_PARAMKEY_INPUT_MAX_REFERENCE_COUNT)
+ .withConstValue(new C2StreamMaxReferenceCountTuning::input(0u))
+ .build());
+}
+
+void SimpleInterface<void>::BaseParams::noOutputReferences() {
+ addParameter(
+ DefineParam(mMaxOutputReferenceAge, C2_PARAMKEY_OUTPUT_MAX_REFERENCE_AGE)
+ .withConstValue(new C2StreamMaxReferenceAgeTuning::output(0u))
+ .build());
+
+ addParameter(
+ DefineParam(mMaxOutputReferenceCount, C2_PARAMKEY_OUTPUT_MAX_REFERENCE_COUNT)
+ .withConstValue(new C2StreamMaxReferenceCountTuning::output(0u))
+ .build());
+}
+
+void SimpleInterface<void>::BaseParams::noTimeStretch() {
+ addParameter(
+ DefineParam(mTimeStretch, C2_PARAMKEY_TIME_STRETCH)
+ .withConstValue(new C2ComponentTimeStretchTuning(1.f))
+ .build());
+}
+
+/*
+ Clients need to handle the following base params due to custom dependency.
+
+ std::shared_ptr<C2ApiLevelSetting> mApiLevel;
+ std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
+ std::shared_ptr<C2ComponentAttributesSetting> mAttrib;
+
+ std::shared_ptr<C2PortSuggestedBufferCountTuning::input> mSuggestedInputBufferCount;
+ std::shared_ptr<C2PortSuggestedBufferCountTuning::output> mSuggestedOutputBufferCount;
+
+ std::shared_ptr<C2TrippedTuning> mTripped;
+
+*/
+
+} // namespace android
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
new file mode 100644
index 0000000..b3a98f4
--- /dev/null
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2017 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 SIMPLE_C2_COMPONENT_H_
+#define SIMPLE_C2_COMPONENT_H_
+
+#include <list>
+#include <unordered_map>
+
+#include <C2Component.h>
+
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/Mutexed.h>
+
+namespace android {
+
+class SimpleC2Component
+ : public C2Component, public std::enable_shared_from_this<SimpleC2Component> {
+public:
+ explicit SimpleC2Component(
+ const std::shared_ptr<C2ComponentInterface> &intf);
+ virtual ~SimpleC2Component();
+
+ // C2Component
+ // From C2Component
+ virtual c2_status_t setListener_vb(
+ const std::shared_ptr<Listener> &listener, c2_blocking_t mayBlock) override;
+ virtual c2_status_t queue_nb(std::list<std::unique_ptr<C2Work>>* const items) override;
+ virtual c2_status_t announce_nb(const std::vector<C2WorkOutline> &items) override;
+ virtual c2_status_t flush_sm(
+ flush_mode_t mode, std::list<std::unique_ptr<C2Work>>* const flushedWork) override;
+ virtual c2_status_t drain_nb(drain_mode_t mode) override;
+ virtual c2_status_t start() override;
+ virtual c2_status_t stop() override;
+ virtual c2_status_t reset() override;
+ virtual c2_status_t release() override;
+ virtual std::shared_ptr<C2ComponentInterface> intf() override;
+
+ // for handler
+ bool processQueue();
+
+protected:
+ /**
+ * Initialize internal states of the component according to the config set
+ * in the interface.
+ *
+ * This method is called during start(), but only at the first invocation or
+ * after reset().
+ */
+ virtual c2_status_t onInit() = 0;
+
+ /**
+ * Stop the component.
+ */
+ virtual c2_status_t onStop() = 0;
+
+ /**
+ * Reset the component.
+ */
+ virtual void onReset() = 0;
+
+ /**
+ * Release the component.
+ */
+ virtual void onRelease() = 0;
+
+ /**
+ * Flush the component.
+ */
+ virtual c2_status_t onFlush_sm() = 0;
+
+ /**
+ * Process the given work and finish pending work using finish().
+ *
+ * \param[in,out] work the work to process
+ * \param[in] pool the pool to use for allocating output blocks.
+ */
+ virtual void process(
+ const std::unique_ptr<C2Work> &work,
+ const std::shared_ptr<C2BlockPool> &pool) = 0;
+
+ /**
+ * Drain the component and finish pending work using finish().
+ *
+ * \param[in] drainMode mode of drain.
+ * \param[in] pool the pool to use for allocating output blocks.
+ *
+ * \retval C2_OK The component has drained all pending output
+ * work.
+ * \retval C2_OMITTED Unsupported mode (e.g. DRAIN_CHAIN)
+ */
+ virtual c2_status_t drain(
+ uint32_t drainMode,
+ const std::shared_ptr<C2BlockPool> &pool) = 0;
+
+ // for derived classes
+ /**
+ * Finish pending work.
+ *
+ * This method will retrieve the pending work according to |frameIndex| and
+ * feed the work into |fillWork| function. |fillWork| must be
+ * "non-blocking". Once |fillWork| returns the filled work will be returned
+ * to the client.
+ *
+ * \param[in] frameIndex the index of the pending work
+ * \param[in] fillWork the function to fill the retrieved work.
+ */
+ void finish(uint64_t frameIndex, std::function<void(const std::unique_ptr<C2Work> &)> fillWork);
+
+ /**
+ * Clone pending or current work and send the work back to client.
+ *
+ * This method will retrieve and clone the pending or current work according
+ * to |frameIndex| and feed the work into |fillWork| function. |fillWork|
+ * must be "non-blocking". Once |fillWork| returns the filled work will be
+ * returned to the client.
+ *
+ * \param[in] frameIndex the index of the work
+ * \param[in] currentWork the current work under processing
+ * \param[in] fillWork the function to fill the retrieved work.
+ */
+ void cloneAndSend(
+ uint64_t frameIndex,
+ const std::unique_ptr<C2Work> ¤tWork,
+ std::function<void(const std::unique_ptr<C2Work> &)> fillWork);
+
+
+ std::shared_ptr<C2Buffer> createLinearBuffer(
+ const std::shared_ptr<C2LinearBlock> &block);
+
+ std::shared_ptr<C2Buffer> createLinearBuffer(
+ const std::shared_ptr<C2LinearBlock> &block, size_t offset, size_t size);
+
+ std::shared_ptr<C2Buffer> createGraphicBuffer(
+ const std::shared_ptr<C2GraphicBlock> &block);
+
+ std::shared_ptr<C2Buffer> createGraphicBuffer(
+ const std::shared_ptr<C2GraphicBlock> &block,
+ const C2Rect &crop);
+
+ static constexpr uint32_t NO_DRAIN = ~0u;
+
+ C2ReadView mDummyReadView;
+
+private:
+ const std::shared_ptr<C2ComponentInterface> mIntf;
+
+ class WorkHandler : public AHandler {
+ public:
+ enum {
+ kWhatProcess,
+ kWhatInit,
+ kWhatStart,
+ kWhatStop,
+ kWhatReset,
+ kWhatRelease,
+ };
+
+ WorkHandler();
+ ~WorkHandler() override = default;
+
+ void setComponent(const std::shared_ptr<SimpleC2Component> &thiz);
+
+ protected:
+ void onMessageReceived(const sp<AMessage> &msg) override;
+
+ private:
+ std::weak_ptr<SimpleC2Component> mThiz;
+ bool mRunning;
+ };
+
+ enum {
+ UNINITIALIZED,
+ STOPPED,
+ RUNNING,
+ };
+
+ struct ExecState {
+ ExecState() : mState(UNINITIALIZED) {}
+
+ int mState;
+ std::shared_ptr<C2Component::Listener> mListener;
+ };
+ Mutexed<ExecState> mExecState;
+
+ sp<ALooper> mLooper;
+ sp<WorkHandler> mHandler;
+
+ class WorkQueue {
+ public:
+ inline WorkQueue() : mFlush(false), mGeneration(0ul) {}
+
+ inline uint64_t generation() const { return mGeneration; }
+ inline void incGeneration() { ++mGeneration; mFlush = true; }
+
+ std::unique_ptr<C2Work> pop_front();
+ void push_back(std::unique_ptr<C2Work> work);
+ bool empty() const;
+ uint32_t drainMode() const;
+ void markDrain(uint32_t drainMode);
+ inline bool popPendingFlush() {
+ bool flush = mFlush;
+ mFlush = false;
+ return flush;
+ }
+ void clear();
+
+ private:
+ struct Entry {
+ std::unique_ptr<C2Work> work;
+ uint32_t drainMode;
+ };
+
+ bool mFlush;
+ uint64_t mGeneration;
+ std::list<Entry> mQueue;
+ };
+ Mutexed<WorkQueue> mWorkQueue;
+
+ typedef std::unordered_map<uint64_t, std::unique_ptr<C2Work>> PendingWork;
+ Mutexed<PendingWork> mPendingWork;
+
+ std::shared_ptr<C2BlockPool> mOutputBlockPool;
+
+ SimpleC2Component() = delete;
+};
+
+} // namespace android
+
+#endif // SIMPLE_C2_COMPONENT_H_
diff --git a/media/codec2/components/base/include/SimpleC2Interface.h b/media/codec2/components/base/include/SimpleC2Interface.h
new file mode 100644
index 0000000..2051d3d
--- /dev/null
+++ b/media/codec2/components/base/include/SimpleC2Interface.h
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SIMPLE_C2_INTERFACE_H_
+#define ANDROID_SIMPLE_C2_INTERFACE_H_
+
+#include <C2Component.h>
+#include <C2Config.h>
+#include <util/C2InterfaceHelper.h>
+
+namespace android {
+
+/**
+ * Wrap a common interface object (such as Codec2Client::Interface, or C2InterfaceHelper into
+ * a C2ComponentInterface.
+ *
+ * \param T common interface type
+ */
+template <typename T>
+class SimpleC2Interface : public C2ComponentInterface {
+public:
+ SimpleC2Interface(const char *name, c2_node_id_t id, const std::shared_ptr<T> &impl)
+ : mName(name),
+ mId(id),
+ mImpl(impl) {
+ }
+
+ ~SimpleC2Interface() override = default;
+
+ // From C2ComponentInterface
+ C2String getName() const override { return mName; }
+ c2_node_id_t getId() const override { return mId; }
+ c2_status_t query_vb(
+ const std::vector<C2Param*> &stackParams,
+ const std::vector<C2Param::Index> &heapParamIndices,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2Param>>* const heapParams) const override {
+ return mImpl->query(stackParams, heapParamIndices, mayBlock, heapParams);
+ }
+ c2_status_t config_vb(
+ const std::vector<C2Param*> ¶ms,
+ c2_blocking_t mayBlock,
+ std::vector<std::unique_ptr<C2SettingResult>>* const failures) override {
+ return mImpl->config(params, mayBlock, failures);
+ }
+ c2_status_t createTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
+ c2_status_t releaseTunnel_sm(c2_node_id_t) override { return C2_OMITTED; }
+ c2_status_t querySupportedParams_nb(
+ std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const override {
+ return mImpl->querySupportedParams(params);
+ }
+ c2_status_t querySupportedValues_vb(
+ std::vector<C2FieldSupportedValuesQuery> &fields,
+ c2_blocking_t mayBlock) const override {
+ return mImpl->querySupportedValues(fields, mayBlock);
+ }
+
+private:
+ C2String mName;
+ const c2_node_id_t mId;
+ const std::shared_ptr<T> mImpl;
+};
+
+/**
+ * Utility classes for common interfaces.
+ */
+template<>
+class SimpleC2Interface<void> {
+public:
+ /**
+ * Base Codec 2.0 parameters required for all components.
+ */
+ struct BaseParams : C2InterfaceHelper {
+ explicit BaseParams(
+ const std::shared_ptr<C2ReflectorHelper> &helper,
+ C2String name,
+ C2Component::kind_t kind,
+ C2Component::domain_t domain,
+ C2String mediaType,
+ std::vector<C2String> aliases = std::vector<C2String>());
+
+ /// Marks that this component has no input latency. Otherwise, component must
+ /// add support for C2PortRequestedDelayTuning::input and C2PortActualDelayTuning::input.
+ void noInputLatency();
+
+ /// Marks that this component has no output latency. Otherwise, component must
+ /// add support for C2PortRequestedDelayTuning::output and C2PortActualDelayTuning::output.
+ void noOutputLatency();
+
+ /// Marks that this component has no pipeline latency. Otherwise, component must
+ /// add support for C2RequestedPipelineDelayTuning and C2ActualPipelineDelayTuning.
+ void noPipelineLatency();
+
+ /// Marks that this component has no need for private buffers. Otherwise, component must
+ /// add support for C2MaxPrivateBufferCountTuning, C2PrivateAllocatorsTuning and
+ /// C2PrivateBlockPoolsTuning.
+ void noPrivateBuffers();
+
+ /// Marks that this component holds no references to input buffers. Otherwise, component
+ /// must add support for C2StreamMaxReferenceAgeTuning::input and
+ /// C2StreamMaxReferenceCountTuning::input.
+ void noInputReferences();
+
+ /// Marks that this component holds no references to output buffers. Otherwise, component
+ /// must add support for C2StreamMaxReferenceAgeTuning::output and
+ /// C2StreamMaxReferenceCountTuning::output.
+ void noOutputReferences();
+
+ /// Marks that this component does not stretch time. Otherwise, component
+ /// must add support for C2ComponentTimeStretchTuning.
+ void noTimeStretch();
+
+ std::shared_ptr<C2ApiLevelSetting> mApiLevel;
+ std::shared_ptr<C2ApiFeaturesSetting> mApiFeatures;
+
+ std::shared_ptr<C2PlatformLevelSetting> mPlatformLevel;
+ std::shared_ptr<C2PlatformFeaturesSetting> mPlatformFeatures;
+
+ std::shared_ptr<C2ComponentNameSetting> mName;
+ std::shared_ptr<C2ComponentAliasesSetting> mAliases;
+ std::shared_ptr<C2ComponentKindSetting> mKind;
+ std::shared_ptr<C2ComponentDomainSetting> mDomain;
+ std::shared_ptr<C2ComponentAttributesSetting> mAttrib;
+ std::shared_ptr<C2ComponentTimeStretchTuning> mTimeStretch;
+
+ std::shared_ptr<C2PortMediaTypeSetting::input> mInputMediaType;
+ std::shared_ptr<C2PortMediaTypeSetting::output> mOutputMediaType;
+ std::shared_ptr<C2StreamBufferTypeSetting::input> mInputFormat;
+ std::shared_ptr<C2StreamBufferTypeSetting::output> mOutputFormat;
+
+ std::shared_ptr<C2PortRequestedDelayTuning::input> mRequestedInputDelay;
+ std::shared_ptr<C2PortRequestedDelayTuning::output> mRequestedOutputDelay;
+ std::shared_ptr<C2RequestedPipelineDelayTuning> mRequestedPipelineDelay;
+
+ std::shared_ptr<C2PortActualDelayTuning::input> mActualInputDelay;
+ std::shared_ptr<C2PortActualDelayTuning::output> mActualOutputDelay;
+ std::shared_ptr<C2ActualPipelineDelayTuning> mActualPipelineDelay;
+
+ std::shared_ptr<C2StreamMaxReferenceAgeTuning::input> mMaxInputReferenceAge;
+ std::shared_ptr<C2StreamMaxReferenceCountTuning::input> mMaxInputReferenceCount;
+ std::shared_ptr<C2StreamMaxReferenceAgeTuning::output> mMaxOutputReferenceAge;
+ std::shared_ptr<C2StreamMaxReferenceCountTuning::output> mMaxOutputReferenceCount;
+ std::shared_ptr<C2MaxPrivateBufferCountTuning> mMaxPrivateBufferCount;
+
+ std::shared_ptr<C2PortStreamCountTuning::input> mInputStreamCount;
+ std::shared_ptr<C2PortStreamCountTuning::output> mOutputStreamCount;
+
+ std::shared_ptr<C2SubscribedParamIndicesTuning> mSubscribedParamIndices;
+ std::shared_ptr<C2PortSuggestedBufferCountTuning::input> mSuggestedInputBufferCount;
+ std::shared_ptr<C2PortSuggestedBufferCountTuning::output> mSuggestedOutputBufferCount;
+
+ std::shared_ptr<C2CurrentWorkTuning> mCurrentWorkOrdinal;
+ std::shared_ptr<C2LastWorkQueuedTuning::input> mLastInputQueuedWorkOrdinal;
+ std::shared_ptr<C2LastWorkQueuedTuning::output> mLastOutputQueuedWorkOrdinal;
+
+ std::shared_ptr<C2PortAllocatorsTuning::input> mInputAllocators;
+ std::shared_ptr<C2PortAllocatorsTuning::output> mOutputAllocators;
+ std::shared_ptr<C2PrivateAllocatorsTuning> mPrivateAllocators;
+ std::shared_ptr<C2PortBlockPoolsTuning::output> mOutputPoolIds;
+ std::shared_ptr<C2PrivateBlockPoolsTuning> mPrivatePoolIds;
+
+ std::shared_ptr<C2TrippedTuning> mTripped;
+ std::shared_ptr<C2OutOfMemoryTuning> mOutOfMemory;
+
+ std::shared_ptr<C2PortConfigCounterTuning::input> mInputConfigCounter;
+ std::shared_ptr<C2PortConfigCounterTuning::output> mOutputConfigCounter;
+ std::shared_ptr<C2ConfigCounterTuning> mDirectConfigCounter;
+ };
+};
+
+template<typename T>
+using SimpleInterface = SimpleC2Interface<T>;
+
+template<typename T, typename ...Args>
+std::shared_ptr<T> AllocSharedString(const Args(&... args), const char *str) {
+ size_t len = strlen(str) + 1;
+ std::shared_ptr<T> ret = T::AllocShared(len, args...);
+ strcpy(ret->m.value, str);
+ return ret;
+}
+
+template<typename T, typename ...Args>
+std::shared_ptr<T> AllocSharedString(const Args(&... args), const std::string &str) {
+ std::shared_ptr<T> ret = T::AllocShared(str.length() + 1, args...);
+ strcpy(ret->m.value, str.c_str());
+ return ret;
+}
+
+template <typename T>
+struct Setter {
+ typedef typename std::remove_reference<T>::type type;
+
+ static C2R NonStrictValueWithNoDeps(
+ bool mayBlock, C2InterfaceHelper::C2P<type> &me) {
+ (void)mayBlock;
+ return me.F(me.v.value).validatePossible(me.v.value);
+ }
+
+ static C2R NonStrictValuesWithNoDeps(
+ bool mayBlock, C2InterfaceHelper::C2P<type> &me) {
+ (void)mayBlock;
+ C2R res = C2R::Ok();
+ for (size_t ix = 0; ix < me.v.flexCount(); ++ix) {
+ res.plus(me.F(me.v.m.values[ix]).validatePossible(me.v.m.values[ix]));
+ }
+ return res;
+ }
+
+ static C2R StrictValueWithNoDeps(
+ bool mayBlock,
+ const C2InterfaceHelper::C2P<type> &old,
+ C2InterfaceHelper::C2P<type> &me) {
+ (void)mayBlock;
+ if (!me.F(me.v.value).supportsNow(me.v.value)) {
+ me.set().value = old.v.value;
+ }
+ return me.F(me.v.value).validatePossible(me.v.value);
+ }
+};
+
+} // namespace android
+
+#endif // ANDROID_SIMPLE_C2_INTERFACE_H_